将两个集合绑定到 WPF MVVM 中的控件的正确方法

Proper way to bind two collections to the control in WPF MVVM

我有一个 class,它有两个不同类型的项目集合。我想将 class 集合绑定到 TreeView。组织 ViewModel 的正确方法是什么?

以下是我的猜测。

型号:

public CClassModel
{
    List<A> m_itemsA;
    List<B> m_ItemsB;
}

视图模型:

public CClassViewModel
{
    CClassModel = m_model;
    ObservableCollection<object> m_items;
    public CClassViewModel
    {
        m_model = new CClassModel();
        m_items = Merge(m_model.m_itemsA, m_model.m_itemsB);
    }
}

绑定:

<TreeListControl ItemsSource="{Binding ViewModel.m_items}">

要绑定你需要 public 属性,目前你有私有文件。

使用

public ObservableCollection<object> Items { get; set; }

而不是

ObservableCollection<object> m_items;

作为建议,在这种情况下使用 Interface 很有用。如果 AB 共享一些 属性,那么你可以这样做:

public interface IAB
{
    string Name { get; set; }
}

public class A:IAB
{
    public string Name { get;  set; }
}
public class B:IAB
{
    public string Name { get;  set; }
}

使用此设计,您的 CClassModel class 将如下所示:

public clas CClassModel
{
  public List<IAB> Items{ get;  set; }

  //...
}

现在,我建议您创建一个 ViewModelBase 摘要 class:

public abstract class ViewModelBase : INotifyPropertyChanged
{
    #region Property Changed Event Handler
    protected void SetPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
    public event PropertyChangedEventHandler PropertyChanged;
    #endregion Property Changed Event Handler
}

这个摘要class将帮助您在需要时定义一个新的ViewModel,例如:

public class MainViewModel:ViewModelBase
{
    private ObservableCollection<IAB> _collection;
    public ObservableCollection<IAB> Collection
    {
        get { return _collection; }
        set
        {
            if (value != this._collection)
                _collection = value;
            SetPropertyChanged("Collection");
        }
    }

    public MainViewModel()
    {
        var m_model = new CClassModel();
        Collection=new ObservableCollection<IAB>(m_model.Items);
    }
}

正如@Rafal 所说,要绑定您需要在 ViewModel 中创建 public 属性,这样您将公开要绑定的信息。

使用 MVVM 模式可以实现的一件事是相对于视图的零代码隐藏。如您所见,ViewModel 的实例化在同一个视图中,特别是在 Resources 中。要使用该实例,您需要设置根控件的 DataContext 属性(例如在本例中是一个网格)。现在您可以使用您在 ViewModel 中定义的属性,如下所示:

<Window x:Class="WpfApplication2.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:wpfApplication2="clr-namespace:WpfApplication2"
    Title="MainWindow" Height="350" Width="525">
<Window.Resources>
    <wpfApplication2:MainViewModel x:Key="MainViewModel"/>
</Window.Resources>
<Grid DataContext="{StaticResource MainViewModel}">
    <TreeView x:Name="ABTreeView" ItemsSource="{Binding Collection}" DisplayMemberPath="Name"> </TreeView>
</Grid>

大概是这样的:

public class A
{ 
  // add something usefull
}

public class B
{
  // add something usefull
}

public class CClassModel
{
  public List<A> m_ItemsA;
  public List<B> m_ItemsB;
}

public class APlaceHolder
{
  public string NodeName { get; set; }
  public List<A> Items { get; set; }
}

public class BPlaceHolder
{
  public string NodeName { get; set; }
  public List<B> Items { get; set; }
}

public class CClassViewModel
{
    CClassModel m_model;
    public ObservableCollection<object> Items { get; set; }

    public CClassViewModel()
    {
        m_model = new CClassModel();
        Items = new ObservableCollection<object>;

        APlaceHolder aph = new APlaceHolder();
        aph.NodeName = "A Items";
        aph.Items = m_model.m_ItemsA;
        Items.Add(aph);

        BPlaceHolder bph = new BPlaceHolder();
        bph.NodeName = "B Items";
        bph.Items = m_model.m_ItemsB;
        Items.Add(bph);
    }
}

您需要为 APlaceHolder 和 BPlaceHolder 添加 HierarchicalDataTemplates,为 A 和 B 添加 DataTemplates。