2013-04-10 61 views
4

我想在一個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

回答

1

您可以創建封裝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 
} 

這僅僅是一個例子,但你明白了。

5

有幾種方法。一種方法是爲您的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>