How can i implement this?
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" }); } }
Due to the amount of code in this question, suppose that INotifyPropertyChanged is executed where necessary, and that the ViewModel is correctly initialized on the page.
How can I use my own DataTemplates? In WPF, I would simply define a few DataTemplates without x:Key , but with a specific DataType type, and let the ListView choose what to use depending on the type of element. UWP doesn't like this; the compiler simply indicates the Dictionary Item "DataTemplate" must have a Key attribute . So how can I achieve my goal?
Current attempt
My current attempt is to create a custom DataTemplateSelector , which seems pretty straightforward.
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; } }
Define it in XAML as follows:
<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>
Unfortunately, when I run this, an exception occurs at runtime, indicating Failed to create a 'Ui.Components.TemplateMatch' from the text 'model:Dog'. So it seems that binding to the Type property is not so simple.
Any help is appreciated!
Note that I would like to use a property of type Type , as opposed to string , where I would pass in the name of the CLR type and use reflection to call the type, mainly because I do not want mixed CLR and XML namespaces to be displayed in XAML . If you can find a way to invoke a type using the XML namespace, I will gladly take this as an answer.
listview xaml win-universal-app datatemplate
Daniel Schmid
source share