You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Xamarin.Forms的CollectionView中使用外部DataTemplate?复用失败求助

解决Xamarin.Forms中CollectionView复用DataTemplate无效的问题

看起来你遇到的问题核心是自定义控件的根元素选择错误,以及CollectionView.ItemTemplate的使用方式不对。让我一步步帮你修复:

问题根源

你把ArticoloSpesaControl.xaml的根元素设为DataTemplate,但带有x:Class的XAML文件需要继承自VisualElement(比如ContentView、StackLayout等),而DataTemplate并不是可视化元素,它只是用于生成UI的模板。另外,CollectionView.ItemTemplate要求的是DataTemplate类型,直接放自定义控件是不符合要求的。

下面提供两种可行的解决方案:


方案1:将模板作为可复用的DataTemplate放在资源字典中

这种方式适合单纯复用模板的场景,不需要额外的控件逻辑:

  1. 创建独立的资源字典文件(比如ArticoloSpesaTemplate.xaml):
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                    xmlns:plugin="clr-namespace:Plugin.Badge.Abstractions;assembly=Plugin.Badge.Abstractions"
                    xmlns:ffimageloading="clr-namespace:FFImageLoading.Forms;assembly=FFImageLoading.Forms">

    <DataTemplate x:Key="ArticoloSpesaTemplate">
        <StackLayout Orientation="Horizontal" Padding="10,0,10,0">
            <StackLayout Orientation="Horizontal" HorizontalOptions="Start" Spacing="0">
                <plugin:Badge BadgeText="{Binding Articolo.quantita}" 
                              Style="{StaticResource Badge}" 
                              BackgroundColor="{StaticResource BadgeColor}" 
                              WidthRequest="35" 
                              Margin="0,9,2,0" />
                <ffimageloading:CachedImage Source="loading.gif" 
                                            WidthRequest="40" 
                                            HorizontalOptions="Start" 
                                            VerticalOptions="Center" 
                                            IsVisible="{Binding RequestPending}" />
                <Label Text="{Binding DescrizioneArticolo}" 
                       Style="{StaticResource LabelProduct}" 
                       WidthRequest="200" 
                       HeightRequest="40" 
                       HorizontalOptions="FillAndExpand" />
                <Label Text="{Binding Articolo.prezzoNetto, StringFormat='{0:F}€'}" 
                       WidthRequest="90" 
                       TextColor="Red" 
                       HeightRequest="50" 
                       VerticalTextAlignment="Center" 
                       HorizontalOptions="End" 
                       HorizontalTextAlignment="End" 
                       VerticalOptions="Center" 
                       Style="{StaticResource LabelMedium}" />
            </StackLayout>
        </StackLayout>
    </DataTemplate>
</ResourceDictionary>
  1. 在页面中合并资源字典(比如在MainPage.xaml的Resources节点里):
<ContentPage.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <!-- 替换成你的资源字典命名空间 -->
            <local:ArticoloSpesaTemplate />
        </ResourceDictionary.MergedDictionaries>
        <!-- 其他本地资源 -->
    </ResourceDictionary>
</ContentPage.Resources>
  1. 在CollectionView中引用模板:
<CollectionView ItemsSource="{Binding Spesa.Articoli}" >
    <CollectionView.ItemTemplate>
        <StaticResource ResourceKey="ArticoloSpesaTemplate" />
    </CollectionView.ItemTemplate>
</CollectionView>

方案2:封装成ContentView自定义控件

如果你的模板需要附带逻辑(比如事件处理、绑定属性),这种方式更合适:

  1. 修改ArticoloSpesaControl.xaml的根元素为ContentView:
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Prestospesa.View.Control.ArticoloSpesaControl"
             xmlns:plugin="clr-namespace:Plugin.Badge.Abstractions;assembly=Plugin.Badge.Abstractions"
             xmlns:ffimageloading="clr-namespace:FFImageLoading.Forms;assembly=FFImageLoading.Forms">

    <StackLayout Orientation="Horizontal" Padding="10,0,10,0">
        <StackLayout Orientation="Horizontal" HorizontalOptions="Start" Spacing="0">
            <plugin:Badge BadgeText="{Binding Articolo.quantita}" 
                          Style="{StaticResource Badge}" 
                          BackgroundColor="{StaticResource BadgeColor}" 
                          WidthRequest="35" 
                          Margin="0,9,2,0" />
            <ffimageloading:CachedImage Source="loading.gif" 
                                        WidthRequest="40" 
                                        HorizontalOptions="Start" 
                                        VerticalOptions="Center" 
                                        IsVisible="{Binding RequestPending}" />
            <Label Text="{Binding DescrizioneArticolo}" 
                   Style="{StaticResource LabelProduct}" 
                   WidthRequest="200" 
                   HeightRequest="40" 
                   HorizontalOptions="FillAndExpand" />
            <Label Text="{Binding Articolo.prezzoNetto, StringFormat='{0:F}€'}" 
                   WidthRequest="90" 
                   TextColor="Red" 
                   HeightRequest="50" 
                   VerticalTextAlignment="Center" 
                   HorizontalOptions="End" 
                   HorizontalTextAlignment="End" 
                   VerticalOptions="Center" 
                   Style="{StaticResource LabelMedium}" />
        </StackLayout>
    </StackLayout>
</ContentView>
  1. 确保后台代码继承ContentView(ArticoloSpesaControl.xaml.cs):
using Xamarin.Forms;

namespace Prestospesa.View.Control
{
    public partial class ArticoloSpesaControl : ContentView
    {
        public ArticoloSpesaControl()
        {
            InitializeComponent();
        }
    }
}
  1. 在CollectionView的DataTemplate中引用控件:
<CollectionView ItemsSource="{Binding Spesa.Articoli}" >
    <CollectionView.ItemTemplate>
        <DataTemplate>
            <control:ArticoloSpesaControl />
        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

这两种方案都能解决你的复用问题,根据是否需要控件逻辑来选择即可。

内容的提问来源于stack exchange,提问作者Gianluca Musa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:12:05