Search code examples
c#.netmvvmmaui

Handling classes inheriting the same base class in a mvvm structure


I have setup an MVVM Structure in a .NET MAUI application.

My models are structured like this:

public partial class Animal
{
    public string Name { get; set; }
}

public class Bird : Animal
    {
        public string Color { get; set; }
    }

public class Fish : Animal
    {
        public int FinCount { get; set; }
    }

Now I have one view that looks at a viewmodel containing a List<Animals> and shows it to the user. Now when the user clicks on a item in the list, the application calls a Command that changes the view to a "DetailView" and passes the clicked element to the detail view.

The detail viewmodel has an [ObservableProperty] Animal detailedAnimal.

Is it possible to distinguish between the Bird and the Fish class in the XAML? Depending on what kind of animal it is, I want the view to show different control elements. This is currently realized by setting an observable property when applying the query attribute from the list view. depending on that, I set different elements visible.

I dont want to check the class and move its specific properties to seperate observable properties to then display in the detail view.

But is there a way in the XAML of the detail view to address the properties of the different kind of objects that can be in this list or is it better to make a seperate view and viewmodel for every class that inherits Animal, and call the correct viewmodel when I click the element in the list?

Thanks!


Solution

  • As Jason suggested, you can use DataTemplateSelector.

    Here's the sample code that you can refer to:

    public abstract class Animal
    {
            public enum Types { Bird, Fish }
            public abstract Types Type { get; }
            public string Name { get; set; }
    }
    
    public class Bird : Animal
    {
            public override Types Type => Types.Bird;
            public string Color { get; set; }
    }
    
    public class Fish : Animal
    {
            public override Types Type => Types.Fish;
            public int FinCount { get; set; }
    }
    
    public class AnimalDataTemplateSelector : DataTemplateSelector
    {
            public DataTemplate Bird { get; set; }
    
            public DataTemplate Fish { get; set; }
    
            protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
            {
                var obj = (Animal)item;
    
                if (obj.Type == Animal.Types.Bird)
                {
                    return Bird;
                }
                else
                {
                    return Fish;
                }
            }
    }