用于ListView中多种项目类型的UWP DataTemplates [英] UWP DataTemplates for multiple item types in ListView

查看:114
本文介绍了用于ListView中多种项目类型的UWP DataTemplates的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我将如何实施呢?

让我们说这是我的模特:

Let's say this is my model:

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.

For the sake of the amount of code in this question please assume that INotifyPropertyChanged is implemented where necessary, and that the ViewModel is correctly initialized in the page.

如何使用我自己的对应DataTemplates?在WPF中,我只需要定义多个没有x:Key但具有定义的DataType的DataTemplates,然后让ListView根据项的类型选择要使用的模板. UWP不喜欢这样.编译器只是声明Dictionary Item "DataTemplate" must have a Key attribute.那我该如何实现我的目标呢?

How can I use my own corresponding DataTemplates? In WPF I would just define multiple DataTemplates without an x:Key but with a defined DataType and let the ListView chose which to use based on the type of the item. UWP doesn't like that; the compiler simply states Dictionary Item "DataTemplate" must have a Key attribute. So how do I accomplish my goal?

我当前的尝试是创建自定义DataTemplateSelector,这似乎很简单.

My current attempt is to make a custom DataTemplateSelector, which seems rather straight forward.

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中定义它:

Define it in XAML like this:

<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属性似乎并不那么容易.

Unfortunately when I run this, an Exception occurs during runtime, stating Failed to create a 'Ui.Components.TemplateMatch' from the text 'model:Dog'. So it seems binding to a Type property is not that easy.

感谢您的帮助!

请注意,我想使用类型Type的属性,而不是string,在该属性中我将传递CLR类型名称并使用反射来调用该类型,主要是因为我不想混合使用CLR和XML名称空间出现在XAML中.如果您找到使用XML名称空间调用该类型的方法,我将很乐意将其作为答案.

Please note that I'd like to use a property of type Type, as opposed to string where I would pass the CLR type name and using reflection to invoke the type, mostly because I don't want mixed CLR and XML namespaces appear in XAML. If you can find a way to invoke the type using the XML namespace, I'll gladly take that as an answer.

推荐答案

我找到了解决方法.如果您可以创建这些类型的实例-可以将其用于检测类型:

I found workaround. If you able to create instances of these types - you can use it for detecting types:

[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>

这篇关于用于ListView中多种项目类型的UWP DataTemplates的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆