如何在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放在资源字典中
这种方式适合单纯复用模板的场景,不需要额外的控件逻辑:
- 创建独立的资源字典文件(比如
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>
- 在页面中合并资源字典(比如在
MainPage.xaml的Resources节点里):
<ContentPage.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <!-- 替换成你的资源字典命名空间 --> <local:ArticoloSpesaTemplate /> </ResourceDictionary.MergedDictionaries> <!-- 其他本地资源 --> </ResourceDictionary> </ContentPage.Resources>
- 在CollectionView中引用模板:
<CollectionView ItemsSource="{Binding Spesa.Articoli}" > <CollectionView.ItemTemplate> <StaticResource ResourceKey="ArticoloSpesaTemplate" /> </CollectionView.ItemTemplate> </CollectionView>
方案2:封装成ContentView自定义控件
如果你的模板需要附带逻辑(比如事件处理、绑定属性),这种方式更合适:
- 修改
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>
- 确保后台代码继承
ContentView(ArticoloSpesaControl.xaml.cs):
using Xamarin.Forms; namespace Prestospesa.View.Control { public partial class ArticoloSpesaControl : ContentView { public ArticoloSpesaControl() { InitializeComponent(); } } }
- 在CollectionView的
DataTemplate中引用控件:
<CollectionView ItemsSource="{Binding Spesa.Articoli}" > <CollectionView.ItemTemplate> <DataTemplate> <control:ArticoloSpesaControl /> </DataTemplate> </CollectionView.ItemTemplate> </CollectionView>
这两种方案都能解决你的复用问题,根据是否需要控件逻辑来选择即可。
内容的提问来源于stack exchange,提问作者Gianluca Musa
相关产品推荐
相关产品推荐

