MVVM - 具有多态性的集合

问题描述:

我想在一个ListBox中公开两个派生类型:OutFlight和InFlight都从Flight是一个抽象类型派生。MVVM - 具有多态性的集合

MVVM说我必须为ListBox的绑定模型设置一个ViewModel。这对于一种类型的揭示并不重要,但我的列表框包含两种派生类型,而且我正在寻找最佳的MVVM方法。这是否意味着我必须为每个派生类型设置继承的ViewModels?我读过某处ViewModel继承是不推荐的......我确定这是一个很常见的情况

+0

你想要一个ViewModel列表框的项目正确吗? – Andre 2013-04-10 10:34:41

+0

一些示例代码会有所帮助。 – 2013-04-10 10:37:51

+0

如果您的ViewModel包含此列表框源列表 ListBoxSource;它有什么问题? – 2013-04-10 10:32:52

您可以创建封装OutFlight和InFlight实体的通用视图模型FlightViewModel。因此,FlightViewModel具有所有公共属性,并且基于OutFlight和InFlight实体构造(例如通过在构造函数中传递它们)。它可以有一个额外的属性,表明它是出局还是机上(作为枚举或某物)。

这样做使得FlightViewModel基本上是您的具体类型OutFlight和InFlight的抽象。 FlightViewModel也将只包含您在视图中实际需要的属性以及正确的格式,以便视图可以轻松使用它。

然后,视图的视图模型将具有FlightViewModel对象的集合。

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 
} 

这仅仅是一个例子,但你明白了。

有几种方法。一种方法是为您的Flight类编写一个ViewModel,并用这些“FlightViewModel”对象填充一个集合。该ViewModel可以包含从“Flight”继承的所有对象。如果你的“InFlight”和“OutFlight”类不那么复杂,我会把它们包装在一个ViewModel中(这里是“FlightViewModel”)。

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

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

用其它方法是使用一些基本的视图模型类型列表框的ItemsSource的集合。该集合包含一些类型为“InFlightViewModel”的ViewModel和一些其他类型为“OutFlightViewModel”的ViewModel。对于您的ListBox项目,您可以编写一个ItemTemplateSelector,为项目的类型选择正确的ItemTemplate。

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>