2013-04-10 5 views
4

Je suis en train d'exposer deux types dérivés dans une zone de liste: OutFlight et InFlight à la fois dériver de vol qui est un type abstrait.MVVM - Collection avec polymorphisme

MVVM dit que je dois mettre un ViewModel pour la zone de liste » Modèle lié. Ce n'est pas un gros problème pour exposer un type, mais ma liste contient deux types dérivés, et je suis à la recherche de la meilleure approche MVVM. Cela signifie-t-il que je dois définir des ViewModels hérités pour chacun des types dérivés? Je l'ai lu quelque part l'héritage ViewModel n'est pas recommandé à tous ... Je suis sûr que c'est un cas très fréquent

+0

Vous voulez un ViewModel pour les éléments de la zone de liste correcte? – Andre

+0

Un petit exemple de code aiderait. –

+0

Si votre ViewModel contient ceci comme une liste de sources ListBox ListBoxSource; Qu'est-ce qui va pas avec ça? –

Répondre

1

Vous pouvez créer un modèle de vue générique FlightViewModel qui encapsule les entités OutFlight et InFlight. Donc, un FlightViewModel a toutes les propriétés communes, et est construit sur la base des entités OutFlight et InFlight (par exemple en les passant dans le constructeur). Il pourrait avoir une propriété supplémentaire indiquant s'il s'agit d'un vol ou d'un vol (enum ou quelque chose).

Faire cela fait FlightViewModel essentiellement une abstraction de vos types de béton et OutFlight Inflight. FlightViewModel ne contiendrait également que les propriétés dont vous avez réellement besoin dans votre vue et dans le format correct, de sorte qu'il puisse être facilement utilisé par la vue.

Ensuite, le modèle de vue de votre point de vue aurait une collection d'objets FlightViewModel. C'est juste un exemple bien sûr, mais vous avez l'idée.

5

Il existe plusieurs façons. Une façon est d'écrire un ViewModel pour votre classe Flight et de remplir une collection avec ces objets "FlightViewModel". Ce ViewModel peut contenir tous les objets hérités de "Flight". Si vos classes "InFlight" et "OutFlight" ne sont pas si complexes, je les placerais dans un ViewModel (ici le "FlightViewModel").

public class FlightViewModel : INotifyPropertyChanged 
{ 
    public Flight Flight { get; set; } 

    public int PropertyYouNeedForInFlight { get; set; } 
    public string PropertyYouNeedForOutFlight { get; set; } 
} 

Une autre façon est d'utiliser une collection d'un certain type de ViewModel de base comme la zone de liste ItemsSource. Cette collection contient des ViewModels de type "InFlightViewModel" et d'autres de type "OutFlightViewModel". Pour vos éléments ListBox, vous pouvez écrire un ItemTemplateSelector qui choisit le ItemTemplate correct pour le type de l'élément.

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>