【问题标题】:MVVM - Collection with polymorphismMVVM - 具有多态性的集合
【发布时间】:2013-04-02 03:21:21
【问题描述】:

我试图在 ListBox 中公开两个派生类型:OutFlight 和 InFlight 都派生自作为抽象类型的 Flight。

MVVM 说我必须为 ListBox 的绑定模型设置一个 ViewModel。公开一种类型并不是什么大问题,但我的列表框包含两种派生类型,我正在寻找最好的 MVVM 方法。这是否意味着我必须为每个派生类型设置继承的 ViewModel?我在某处读过 ViewModel 继承根本不推荐......我确信这是一个非常常见的情况

【问题讨论】:

  • 如果你的 ViewModel 包含这个作为 ListBox Source List ListBoxSource;它有什么问题?
  • 您想要一个正确的列表框项目的 ViewModel 吗?
  • 一些示例代码会有所帮助。

标签: c# wpf mvvm .net-4.0


【解决方案1】:

有几种方法。一种方法是为您的 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”类型的 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>

【讨论】:

    【解决方案2】:

    您可以创建一个通用视图模型 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
    }
    

    这当然只是一个例子,但你明白了。

    【讨论】:

      猜你喜欢
      • 2011-11-16
      • 2021-08-08
      • 2023-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多