我将如何实施此目标?
让我们说这是我的模特:
public interface IAnimal
{
string Name { get; }
}
public class Fish : IAnimal
{
public string Name { get; set; }
public int ScalesCount { get; set; }
}
public class Dog : IAnimal
{
public string Name { get; set; }
public string CollarManufacturerName { get; set; }
}
public class ViewModel
{
public ObservableCollection<IAnimal> Animals { get; set; }
public ViewModel()
{
this.Animals = new ObservableCollection<IAnimal>();
this.Animals.Add(new Fish { Name = "Carl", ScalesCount = 9000 });
this.Animals.Add(new Dog { Name = "Fifi", CollarManufacturerName = "Macrosoft" });
}
}
为了解决此问题中的代码量,请假设在必要时实施了INotifyPropertyChanged
,并且在页面中正确初始化了ViewModel。
如何使用我自己的相应DataTemplates?在WPF中,我只定义多个DataTemplates而不使用x:Key
但是使用已定义的DataType,并让ListView根据项目的类型选择使用哪个。 UWP不喜欢这样;编译器只是简单地说明Dictionary Item "DataTemplate" must have a Key attribute
。那么我该如何实现目标呢?
我目前的尝试是制作一个自定义DataTemplateSelector
,这似乎很简单。
public class MyDataTemplateSelector: Windows.UI.Xaml.Controls.DataTemplateSelector
{
public ObservableCollection<TemplateMatch> Matches { get; set; }
public DataTemplateSelector()
{
this.Matches = new ObservableCollection<TemplateMatch>();
}
protected override DataTemplate SelectTemplateCore(object item)
{
return this.Matches.FirstOrDefault(m => m.TargetType.Equals(item))?.Template;
}
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
return this.Matches.FirstOrDefault(m => m.TargetType.Equals(item))?.Template;
}
}
public class TemplateMatch
{
public Type TargetType { get; set; }
public DataTemplate Template { get; set; }
}
在XAML中定义它,如下所示:
<ListView ItemsSource="{x:Bind ViewModel.Animals}">
<ListView.ItemTemplateSelector>
<cmp:MyDataTemplateSelector>
<cmp:MyDataTemplateSelector.Matches>
<cmp:TemplateMatch TargetType="model:Dog" Template="{StaticResource DogTemplate}"/>
<cmp:TemplateMatch TargetType="model:Fish" Template="{StaticResource FishTemplate}"/>
</cmp:MyDataTemplateSelector.Matches>
</cmp:MyDataTemplateSelector>
</ListView.ItemTemplateSelector>
</ListView>
不幸的是,当我运行它时,在运行时期间发生异常,声明Failed to create a 'Ui.Components.TemplateMatch' from the text 'model:Dog'.
所以看起来绑定到Type
属性并不那么容易。
感谢任何帮助!
请注意,我希望使用Type
类型的属性,而不是string
,我将传递CLR类型名称并使用反射来调用该类型,主要是因为我不想在XAML中出现混合CLR和XML命名空间。如果您可以找到使用XML命名空间调用类型的方法,我很乐意将其作为答案。
答案 0 :(得分:2)
我找到了解决方法。如果您能够创建这些类型的实例 - 您可以使用它来检测类型:
[ContentProperty(Name = nameof(Matches))]
public class TypeTemplateSelector : DataTemplateSelector
{
public ObservableCollection<TemplateMatch> Matches { get; set; }
public TypeTemplateSelector()
{
this.Matches = new ObservableCollection<TemplateMatch>();
}
protected override DataTemplate SelectTemplateCore(object item)
{
return this.Matches.FirstOrDefault(m => m.ItemOfType.GetType().Equals(item.GetType()))?.TemplateContent;
}
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
return this.Matches.FirstOrDefault(m => m.ItemOfType.GetType().Equals(item.GetType()))?.TemplateContent;
}
}
[ContentProperty(Name = nameof(ItemOfType))]
public class TemplateMatch
{
public object ItemOfType { get; set; }
public DataTemplate TemplateContent { get; set; }
}
XAML:
<controls:TypeTemplateSelector>
<controls:TemplateMatch TemplateContent="{StaticResource FishTemplate}">
<models:Fish/>
</controls:TemplateMatch>
<controls:TemplateMatch TemplateContent="{StaticResource DogTemplate}">
<models:Dog/>
</controls:TemplateMatch>
</controls:TypeTemplateSelector>
答案 1 :(得分:0)
线索在错误信息中。
无法创建&#39; Ui.Components.TemplateMatch&#39;从文本 &#39;模型:狗&#39;
注意&#39;模型:Dog&#39;作为文本而不是类型来到你的选择器。
将TemplateMatch类的TargetType属性更改为字符串,而不是像这样的类型: -
public class TemplateMatch
{
public string TargetType { get; set; }
public DataTemplate Template { get; set; }
}
然后将模板选择器类更改为
public class MyDataTemplateSelector : DataTemplateSelector
{
public ObservableCollection<TemplateMatch> Matches { get; set; }
public MyDataTemplateSelector()
{
Matches = new ObservableCollection<TemplateMatch>();
}
protected override DataTemplate SelectTemplateCore(object item)
{
return Matches.FirstOrDefault(m => m.TargetType.Equals(item.GetType().ToString()))?.Template;
}
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
return Matches.FirstOrDefault(m => m.TargetType.Equals(item.GetType().ToString()))?.Template;
}
}
最后将你的xaml改为阅读
<ListView ItemsSource="{x:Bind ViewModel.Animals}">
<ListView.ItemTemplateSelector>
<cmp:MyDataTemplateSelector>
<cmp:MyDataTemplateSelector.Matches>
<cmp:TemplateMatch TargetType="YourFullNamespaceNotXamlNamespace.Dog" Template="{StaticResource DogTemplate}"/>
<cmp:TemplateMatch TargetType="YourFullNamespaceNotXamlNamespace.Fish" Template="{StaticResource FishTemplate}"/>
</cmp:MyDataTemplateSelector.Matches>
</cmp:MyDataTemplateSelector>
</ListView.ItemTemplateSelector>
</ListView>
重点是忘记尝试将其作为类型传递给选择器,并将typename作为字符串传递(完整命名空间而不是Xaml命名空间)。