UWP DataTemplates for multiple item types in ListView

后端 未结 2 1793
梦如初夏
梦如初夏 2021-02-15 16:04

How would I go about implementing this?

Let\'s say this is my model:

public interface IAnimal
{
     string Name { get; }
}
public class Fish : IAnimal
{         


        
相关标签:
2条回答
  • 2021-02-15 16:31

    The clue is in the error message.

    Failed to create a 'Ui.Components.TemplateMatch' from the text 'model:Dog'

    Note the 'model:Dog' is coming to your selector as text not a type.

    Change your TemplateMatch class TargetType property to string instead of type like this:-

    public class TemplateMatch
    {
        public string TargetType { get; set; }
        public DataTemplate Template { get; set; }
    }
    

    Then change your template selector class to read

    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;
        }
    }
    

    Finally change your xaml to read

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

    The point is to forget trying to pass it to your selector as a type, and pass the typename as a string instead (Full namespace not Xaml namespace).

    0 讨论(0)
  • 2021-02-15 16:42

    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>
    
    0 讨论(0)
提交回复
热议问题