How would I go about implementing this?
Let\'s say this is my model:
public interface IAnimal
{
string Name { get; }
}
public class Fish : IAnimal
{
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).
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>