简体   繁体   中英

MVVM - binding to aggregated property

I have following viewmodels:

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}" ..>

If I want to display text "Valid item" if both A.Valid and B.Valid are true , then:

  1. I can do this by having logic in the view (item data template), eg using visibility and extra container:

     <Grid Visibility="{Binding A.Valid}" Converter=...> <TextBlock Text="Valid item" Visibility="{Binding B.Valid}" Converter=... \\> </Grid> 
  2. Or I can add a new property to item viewmodel:

     public class Item: INotifyPropertyChanged { public bool Valid => A.Valid && B.Valid; // bind to this ... } 

    The problem is that notifications of either of SubItem will not update the view.

In case of (1) the binding will subscribe to both PropertyChanged events: Item and corresponding SubItem . In case of (2) the binding only knows about Item.Valid property, so I have to do something like:

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));
    ...
}

Which is awful. So I prefer (1) (using data triggers sometimes, but it's irrelevant).

Are there other options to actually have viewmodel property (2) but without the hassle?

The data binding approach seems easiest in this particular case. That way you rely upon WPF's data binding mechanism handling the event subscriptions for you, rather than having to do it manually via code.

The only other way I know of handling this is to use some kind of mediator object. When the Valid property of SubItem is changed you send out a message that this has happened. Your Item class, which has subscribed to this message, handles it by checking the current valid state of A and B , then sets its own Valid property accordingly.

This approach is not without its own wrinkles however. For one thing, you need to inject the mediator object into your ViewModel objects. Also your Item objects need to subscribe to and unsubscribe from the relevant message at the appropriate times (usually on object creation and destruction). All of this plumbing, while still easier than handling property changed events directly, is more difficult than just using a data trigger and relying on WPF's binding mechanism IMO.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM