将两个集合绑定到 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
很有用。如果 A
和 B
共享一些 属性,那么你可以这样做:
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。
我有一个 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
很有用。如果 A
和 B
共享一些 属性,那么你可以这样做:
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。