所以我有一个对象的MVVM绑定设置。该对象属于如下类:
public class SomeClass
{
public int Field1 {get; set:}
public List<MyClass> CollectionOfObjects {get; set;}
public string Description {get; set;}
}
我的MVVM类实现了INotifyPropertyChanged ...
private SomeClass _viewableObject;
public SomeClass ViewableObject
{
get
{
return _viewableObject;
}
set
{
_viewableObject = value;
OnPropertyChanged("ViewableObject");
}
}
这在我定义新对象的情况下非常有用。例如:
ViewableObject = new SomeClass();
但是我将UI组件绑定到SomeClass
的字段。 Field1
和Description
被推送到文本框,并说CollectionOfObjects
被推送到DataGrid
。
<Datagrid .... ItemsSource = "{Binding ViewableObject.CollectionOfObjects}" ></DataGrid>
因此,如果我仅更新ViewableObject.CollectionOfObjects
而不是整个ViewableObject
,我如何才能更新UI以反映修改?有没有更简洁的方法来做到这一点,而不是拆分MVVM中SomeClass
的每个字段?
答案 0 :(得分:2)
您可以创建自己的实现INotifyCollectionChanged的集合,但是您会发现使用ObservableCollection更容易实现这一点。
答案 1 :(得分:1)
你有几个选择。最简单的方法是将CollectionOfObjects
从List<MyClass>
转换为ObservableCollection<MyClass>
- 正如已经提到的那样。
但请注意,这只会在新项目添加到ObservableCollection
时提供UI通知,或者删除现有项目。
如果您更改CollectionOfObjects
指向的整个引用,则使用ObservableCollection
是没有用的。相反,您需要在INotifyPropertyChanged
上实施SomeClass
并在设置每个属性值时引发PropertyChanged
个事件。
生成的SomeClass
将如下所示:
public class SomeClass : INotifyPropertyChanged
{
public SomeClass()
{
CollectionOfObjects = new ObservableCollection<MyClass>();
}
public int Field1
{
get
{
return _field1;
}
set
{
if(_field1 != value)
{
_field1 = value;
PropertyChanged(new PropertyChangedEventArgs("Field1"));
}
}
}
public ObservableCollection<MyClass> CollectionOfObjects
{
get
{
return _collectionOfObjects;
}
set
{
if(_collectionOfObjects != value)
{
_collectionOfObjects = value;
PropertyChanged(new PropertyChangedEventArgs("CollectionOfObjects"));
}
}
}
public string Description
{
get
{
return _description;
}
set
{
if(_description != value)
{
_description = value;
PropertyChanged(new PropertyChangedEventArgs("Description"));
}
}
}
public event PropertyChangedEventHandler PropertyChanged = delegate {}
private int _field1;
private ObservableCollection<MyClass> _collectionOfObjects;
private string _description;
}
请注意,严格来说,这不再是Model对象。它对INotifyPropertyChanged
和ObservableCollection
的依赖使其成为ViewModel。但是,你已经拥有其中一个......
选择是否能够容忍污染&#39;你的模型类,它成为一个ViewModel。对于某些情况,这绝对没问题。在其他情况下,优先严格区分Model和ViewModel的关注点。此时,您需要引入一个能够从Model转换为ViewModel的映射器 - 反之亦然。也许模型是数据库记录,或完全不同的东西。它可能需要依赖于其他库,从某些特定于层的基类继承,或者包含许多域逻辑。
严格分离Model和ViewModel的另一个好处是两者可以独立变化。模型可能包含UI(因此ViewModel)不需要包含的一些属性。或者,ViewModel可能会将某些属性聚合为平均值或总数等.ViewModel通常应具有映射到用户界面的属性,而Models可能不会。
最后一点说明。通过引入映射器并正确分离Model和ViewModel,您可以将现有的ViewModel类称为什么?我倾向于将其称为控制器。然后,该模式变为M-V-C-VM:Model-View-Controller-ViewModel。 Controller仍然是UI元素的DataContext
,但是公开了ViewModel
属性。 Controller应首先加载Model数据(可能通过存储库接口),然后让mapper将Model转换为MVVM特定的ViewModel。
如果您正在使用依赖注入,那么控制器会接受服务接口作为构造函数参数,但ViewModel不会将服务作为构造函数参数:它们将是相当愚蠢的数据包。
我重申这可能是矫枉过正,但它有时也是最好的选择。
答案 2 :(得分:0)
谢谢大家的建议。我使用的解决方案如下:
public class SomeClass : ObservableCollection<Elements>
{
private int _field1;
public int Field1
{
get
{
return _field1;
}
set
{
_field1 = value;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
private string _description;
public string Description
{
get
{
return _description;
}
set
{
_description= value;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
// remove this since the class is now the collection.
// public List<MyClass> CollectionOfObjects {get; set;}
}
现在SomeClass
扩展ObservableCollection
因此有一个CollectionChangedEvent
所以在我的MVVM课程中,我添加了以下内容:
处理程序
private void CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
this.OnPropertyChanged("ViewableObject");
}
将处理程序分配给事件
private SomeClass _viewableObject;
public SomeClass ViewableObject
{
get
{
return _viewableObject;
}
set
{
_viewableObject = value;
if(value != null)
_viewableObject.CollectionChanged += new NotifyCollectionChangedEventHandler(CollectionChanged)
OnPropertyChanged("ViewableObject");
}
}
考虑到开始时的整个问题是,MVVM中的代码发出的唯一时间是新的赋值发生时,事件处理程序仅在需要时被调用。我认为这是一种接近它的简单方法。