UWP DataTemplates für mehrere Artikeltypen in ListView

Wie würde ich das implementieren?

Sagen wir, das ist mein Modell:

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

Um der Menge an Code in dieser Frage willen nehmen Sie bitte an, dassINotifyPropertyChanged wird bei Bedarf implementiert und das ViewModel wird auf der Seite korrekt initialisiert.

Wie kann ich meine eigenen entsprechenden DataTemplates verwenden? In WPF würde ich nur mehrere DataTemplates ohne ein @ definierx:Key, aber mit einem definierten Datentyp, und lassen Sie die ListView anhand des Artikeltyps auswählen, welcher verwendet werden soll. UWP mag das nicht; der Compiler sagt einfachDictionary Item "DataTemplate" must have a Key attribute. Wie erreiche ich mein Ziel?

Aktueller Versuch

Mein aktueller Versuch ist es, ein benutzerdefiniertes @ zu erstelleDataTemplateSelector, was ziemlich einfach zu sein scheint.

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

Definieren Sie es in XAML wie folgt:

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

Leider tritt während der Laufzeit eine Ausnahme auf, die angibt, dassFailed to create a 'Ui.Components.TemplateMatch' from the text 'model:Dog'. Also scheint es bindend zu einemType Eigenschaft ist nicht so einfach.

Jede Hilfe wird gebeten!

Bitte beachten Sie, dass ich eine Eigenschaft vom Typ @ verwenden möchType, im Gegensatz zustring wobei ich den CLR-Typnamen übergeben und Reflection zum Aufrufen des Typs verwenden würde, hauptsächlich, weil in XAML keine gemischten CLR- und XML-Namespaces angezeigt werden sollen. Wenn Sie einen Weg finden, den Typ über den XML-Namespace aufzurufen, nehme ich das gerne als Antwort.

Antworten auf die Frage(4)

Ihre Antwort auf die Frage