MVVM - 多态集合

4

我想在一个ListBox中展示两个派生类型:OutFlight和InFlight,它们都是由抽象类型Flight派生而来的。

MVVM模式要求我为ListBox的绑定模型设置一个ViewModel。对于暴露一个类型来说这不是什么大问题,但我的ListBox包含了两个派生类型,我正在寻找最佳的MVVM方法。这是否意味着我必须为每个派生类型设置继承的ViewModel?我曾经在某处读到过不推荐使用ViewModel继承... 我相信这是一个非常普遍的情况


如果你的ViewModel包含这个作为ListBox源的List<Flight> ListBoxSource,有什么问题吗? - Davut Gürbüz
你想为列表框中的项目创建一个ViewModel,对吗? - Andre
一小段示例代码会很有帮助。 - Adolfo Perez
2个回答

6
有几种方法。一种方法是为您的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; }
}

另一种方法是使用一些基本的ViewModel类型集合作为ListBox的ItemsSource。该集合包含类型为“InFlightViewModel”和“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>

1
您可以创建一个通用的视图模型FlightViewModel,封装OutFlight和InFlight实体。因此,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
}

这只是一个例子,你可以理解一下。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接