【发布时间】:2016-01-30 12:36:38
【问题描述】:
假设我的模型有一个原始数组的属性:
class Model
{
public static int MaxValue { get { return 10; } }
private int[] _array = {1,2,3,4};
public int[] MyArray
{
get
{
return _array;
}
set
{
for (int i = 0; i < Math.Min(value.Length, _array.Length); i++)
_array[i] = Math.Min(MaxValue, value[i]);
}
}
ViewModel 然后包装这个属性 this 供 View 使用:
class ViewModel
{
Model _model = new Model();
public int[] MyArray
{
get { return _model.MyArray; }
set { _model.MyArray = value; }
}
}
最后,我展示了一个 ItemsControl,以便用户可以使用 Slider 设置每个值:
<ItemsControl ItemsSource="{Binding MyArray}" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<Slider Value="{Binding Path=., Mode=TwoWay}" Minimum="0" Maximum="{Binding Source={x:Static Model.MaxValue}, Mode=OneWay}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
在这个简单的示例中,TwoWay 绑定不起作用 - 滑块不会更新属性。这可以通过将每个数组元素包装在一个对象中来解决,例如:
class Wrap
{
public int Value{ get; set; }
}
然后 MyArray 属性变成 Wrap[],我们绑定到 Path=Value。虽然以这种方式在模型中包装数组确实感觉有点“混乱”(注意:其他 WinForms 应用程序也使用该模型),但它确实解决了问题,并且滑块现在可以更新数组。
接下来,让我们添加一个按钮来重置数组值。点击时:
for( int i = 0; i < MyArray.Length; i++ )
MyArray[i].Value = i;
出现了另一个问题:单击按钮后,滑块不反映新值。这可以通过将数组更改为 ObservableCollection 并使用对象替换更新值来解决:
//MyArray is now ObservableCollection<Wrap>
for( int i = 0; i < MyArray.Count; i++ )
MyArray[i] = new Wrap() { Value = i };
第一个问题:我的理解是,在 MVVM 中,Model 类不应该与通知有任何关系——这应该完全由 VM 处理。通常这样的讨论围绕 INotifyPropertyChanged,但在我看来,将数组更改为 ObservableCollection 似乎真的开始弄乱模型,以便......好吧......通知。这不会被认为是不好的做法吗?所有其他使用该模型的(WinForms)应用程序现在都必须更新以理解这个古怪的对象包装基元集合,只是为了使其与数据绑定一起工作。是否有其他方法可以解决这个问题?
第二个问题:我真正的问题来自另一个要求。在 ViewModel 中,数组值(和其他属性)实际上是用来生成图像的——每次更新属性时,都需要刷新图像。对于我的其他(非数组)属性,我这样做:
class ViewModel
{
public int SomeProperty
{
get { return _model.SomeProperty; }
set { _model.SomeProperty = value; RefreshImage(); }
}
}
但我不知道在更改 MyArray 值的情况下如何更新图像。我尝试订阅 ObservableCollection 的 CollectionChanged 事件,但它仅由按钮单击(对象替换)触发,而不是由滑块触发(因为它们更新集合中对象内的值)。我可以制作 Wrap 对象 INotifyPropertyChanged 并订阅 ObservableCollection.PropertyChanged ......但是我会从模型中发送通知,这(根据我读过的所有内容)你不应该在 MVVM 中做。因此,当用户操作滑块时,我要么无法刷新图像,要么不得不基本上破坏 MVVM——在我的模型中使用 INotifyPropertyChanged、ObservableCollections 和包装器。当然必须有一种更清洁的方法来解决这个问题......?
【问题讨论】:
标签: wpf mvvm data-binding observablecollection