我有以下视图模型:
public class ViewModel: INotifyPropertyChanged
{
public ObservableCollection<Item> Items { get; set; }
...
}
public class Item: INotifyPropertyChanged
{
public SubItem A { get; set; }
public SubItem B { get; set; }
...
}
public class SubItem: INotifyPropertyChanged
{
public bool Valid { get; set; }
...
}
xaml:
<ListBox ItemsSource="{Binding Items}" ..>
如果我想显示文本"Valid item"
如果A.Valid
和B.Valid
都是true
,则:
我可以通过在视图(项目数据模板(中具有逻辑来做到这一点,例如使用可见性和额外的容器:
<Grid Visibility="{Binding A.Valid}" Converter=...> <TextBlock Text="Valid item" Visibility="{Binding B.Valid}" Converter=... > </Grid>
,或者我可以将新属性添加到项目ViewModel:
public class Item: INotifyPropertyChanged { public bool Valid => A.Valid && B.Valid; // bind to this ... }
问题是,
SubItem
的任何一个通知都不会更新视图。
在(1(的情况下,绑定将同时订阅PropertyChanged
事件:Item
和相应的SubItem
。如果(2(绑定只知道Item.Valid
属性,所以我必须做类似的事情:
public class Item: INotifyPropertyChanged
{
SubItem _a;
public SubItem A
{
get { return _a; }
set
{
_a.PropertyChanged -= bla;
_a = value;
_a.PropertyChanged += bla;
OnPropertyChanged(nameof(A));
OnPropertyChanged(nameof(Valid));
}
}
void bla(object sender, PropertyChangedEventArgs e) =>
OnPropertyChanged(nameof(Valid));
...
}
这很糟糕。因此,我更喜欢(1((有时使用数据触发器,但这是无关紧要的(。
是否还有其他选项可以真正具有ViewModel属性(2(但是没有麻烦?
在这种特殊情况下,数据绑定方法似乎最简单。这样,您依靠WPF的数据绑定机制为您处理事件订阅,而不必通过代码手动进行。
我知道处理此操作的唯一另一种方法是使用某种调解器对象。当更改SubItem
的Valid
属性时,您会发出一条消息,表明发生了这一消息。已订阅此消息的Item
类通过检查当前有效状态A
和B
来处理它,然后相应地设置其自己的Valid
属性。
这种方法并非没有自己的皱纹。一方面,您需要将中介对象注入视图模型对象。此外,您的Item
对象需要在适当的时间(通常是在对象创建和破坏(中订阅并退订相关消息。所有这些管道虽然比直接处理属性更改事件更容易,但比仅使用数据触发并依赖WPF的绑定机制IMO更加困难。