MVVM - Collection with polymorphism

I am trying to identify two derived types in a ListBox: OutFlight and InFlight are obtained from Flight, which is an abstract type.

MVVM says that I need to set the ViewModel for the associated ListBox model. This is not very important for exposig of the same type, but my list contains two derived types, and I'm looking for a better MVVM approach. Does this mean that I need to set inherited ViewModels for each of the derived types? I read that ViewModel inheritance is not recommended at all ... I'm sure this is a very common case

+4
source share
2 answers

You can create a general FlightViewModel that encapsulates OutFlight and InFlight objects. Thus, FlightViewModel has all the common properties and is built on the basis of OutFlight and InFlight objects (for example, passing them in the constructor). It may have an additional property indicating whether it is a deflection or a stream (as an enumeration or something else).

This makes FlightViewModel basically an abstraction of your specific OutFlight and InFlight types. FlightViewModel will also contain only those properties that you really need in your view and in the correct format so that it can be easily used in the view.

Then the view model of your view will have a set of FlightViewModel objects.

public class FlightViewModel { private Flight _flight; public FlightViewModel(OutFlight outFlight) { FlightNumber = outFlight.FlightNumber; FlightType = FlightType.OutFlight; _flight = outFlight; } public FlightViewModel(InFlight inFlight) { FlightNumber = inFlight.FlightNumber; FlightType = FlightType.InFlight; _flight = inFlight; } public int FlightNumber { get { return _flight.FlightNumber; } set { _flight.FlightNumber = value; } } public FlightType FlightType { get; set; } ... other properties } 

This is just an example, of course, but you get the point.

+1
source

There are several ways. One way is to write a ViewModel for your Flight class and populate the collection with those FlightViewModel objects. This ViewModel can contain all objects that inherit from Flight. If your InFlight and OutFlight classes are not so complex, I would wrap them in a single ViewModel (here is the FlightViewModel).

 public class FlightViewModel : INotifyPropertyChanged { public Flight Flight { get; set; } public int PropertyYouNeedForInFlight { get; set; } public string PropertyYouNeedForOutFlight { get; set; } } 

Another way is to use a collection of some basic ViewModel type as a ListBox ItemsSource element. This collection contains some ViewModels of type "InFlightViewModel" and some others of type "OutFlightViewModel". For ListBox items, you can write an ItemTemplateSelector that selects the correct ItemTemplate for the item type.

 public class MainWindowViewModel { public ObservableCollection<ViewModelBase> Flights { get; set; } public MainWindowViewModel() { Flights = new ObservableCollection<ViewModelBase>(); Flights.Add(new InFlightViewModel()); Flights.Add(new OutFlightViewModel()); } } public class FlightTemplateSelector : DataTemplateSelector { public DataTemplate InFlightTemplate { get; set; } public DataTemplate OutFlightTemplate { get; set; } public override DataTemplate SelectTemplate(object item, DependencyObject container) { if(item.GetType() == typeof(InFlight)) return InFlightTemplate; if(item.GetType() == typeof(OutFlight)) return OutFlightTemplate //Throw exception or choose some random layout throw new Exception(); } } <local:FlightTemplateSelector x:Key="FlightTemplateSelector"> <local:FlightTemplateSelector.InFlightTemplate> <!-- Define your layout here --> </local:FlightTemplateSelector.InFlightTemplate> <!-- Define your layout here --> <local:FlightTemplateSelector.OutFlightTemplate> </local:FlightTemplateSelector.OutFlightTemplate> </local:FlightTemplateSelector> 
+5
source

All Articles