Aggregate detail values in Master-Detail view

回眸只為那壹抹淺笑 提交于 2019-12-11 01:38:33

问题


I have a master-detail relationship in some custom entities. Say I have the following structure:

class Master : INotifyPropertyChanged
{
    public int Id { get; set; } // + property changed implementation 
    public string Name { get; set; } // + property changed implementation

    public ObservableCollection<Detail> Details { get; }
}

class Detail : INotifyPropertyChanged
{
     public int Id { get; private set; }
     public string Description { get; set; }
     public double Value { get; set; } // + property changed implementation
}

My goal is to have a ListView, using a GridView, showing a list of Master objects. When I select a specific Master, I'll have a separate ListView for the details, allowing editing. Basically, a fairly standard Master-Detail view.

However, I also want the GridView for the Master to show the Sum of all of that master's Detail elements, ie: Details.Select(d => d.Value).Sum();

This is fairly easy to display using a custom IValueConverter. I can convert from the details collection directly to a double displaying sum, and bind a TextBlock's Text to the Details OneWay, via the IValueConverter. This will work, and show the correct values when I open the window.

However, if I change one of the detail members, this will not update (even though detail implements INotifyPropertyChanged), since the collection itself is still the same (the ObservableCollection reference hasn't changed).

I want to have an aggregated value in a master list, showing the sum (or average/count/etc) within the detail list, and have this stay up to date when the user changes properties in details. How can I go about implementing this?


Edit:

Ideally, I would prefer if there is a means of accomplishing this that doesn't involve changing the Master class directly. The application in question is using the MVVM pattern, and I'd really prefer to not change my Model classes in order to implement a specific View. Is there a way to do this without introducing custom logic into the model?


回答1:


I was considering possibilities with the UI where you'd make the binding explicit and perform binding/updates from a command... but it seems that the easiest way to do it would be to extend the ObservableCollection to add/remove listeners to each Detail instance as its added/removed, then just fire CollectionChanged when any of them change. Call it DeeplyObservableCollection<T>.

class Master : INotifyPropertyChanged
{
    public int Id { get; set; } // + property changed implementation 
    public string Name { get; set; } // + property changed implementation
    public double Sum {get {return Details.Sum(x=>x.Value);}}

    public DeeplyObservableCollection<Detail> Details { get; }

    // hooked up in the constructor
    void OnDOCChanged(object sender, CollectionChangedEventArgs e) 
    { OnPropertyChanged("Sum"); }
}

Worst case you'd have to wrap an ObservableCollection in another type if you can't properly override all the methods you need...



来源:https://stackoverflow.com/questions/1568387/aggregate-detail-values-in-master-detail-view

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!