MVVM-与汇总属性结合



我有以下视图模型:

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.ValidB.Valid都是true,则:

  1. 我可以通过在视图(项目数据模板(中具有逻辑来做到这一点,例如使用可见性和额外的容器:

    <Grid Visibility="{Binding A.Valid}" Converter=...>
        <TextBlock Text="Valid item" Visibility="{Binding B.Valid}" Converter=... >
    </Grid>
    
  2. ,或者我可以将新属性添加到项目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的数据绑定机制为您处理事件订阅,而不必通过代码手动进行。

我知道处理此操作的唯一另一种方法是使用某种调解器对象。当更改SubItemValid属性时,您会发出一条消息,表明发生了这一消息。已订阅此消息的Item类通过检查当前有效状态AB来处理它,然后相应地设置其自己的Valid属性。

这种方法并非没有自己的皱纹。一方面,您需要将中介对象注入视图模型对象。此外,您的Item对象需要在适当的时间(通常是在对象创建和破坏(中订阅并退订相关消息。所有这些管道虽然比直接处理属性更改事件更容易,但比仅使用数据触发并依赖WPF的绑定机制IMO更加困难。

最新更新