Сводные значения подробностей в представлении Master-Detail

В некоторых настраиваемых объектах у меня есть отношения "главный-деталь". Скажем, у меня есть следующая структура:

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
}

Моя цель - иметь ListView, используя GridView, отображающий список основных объектов. Когда я выбираю конкретный мастер, у меня будет отдельный ListView для деталей, позволяющий редактировать. По сути, довольно стандартный вид Master-Detail.

Однако я также хочу, чтобы GridView для мастера отображал сумму всех элементов сведений этого мастера, то есть: Details.Select(d => d.Value).Sum();

Это довольно легко отобразить с помощью настраиваемого IValueConverter. Я могу преобразовать из коллекции деталей непосредственно в двойную отображаемую сумму и привязать текст TextBlock к объекту Details OneWay через IValueConverter. Это сработает и покажет правильные значения, когда я открою окно.

Однако, если я изменю один из элементов детали, это не будет обновляться (даже если деталь реализует INotifyPropertyChanged), поскольку сама коллекция остается прежней (ссылка ObservableCollection не изменилась).

Я хочу иметь агрегированное значение в главном списке, показывающее сумму (или среднее / количество / и т. Д.) В подробном списке, и чтобы это оставалось актуальным, когда пользователь изменяет свойства в деталях. Как я могу это реализовать?


Редактировать:

В идеале я бы предпочел, чтобы для этого существовали средства, не связанные с непосредственным изменением Мастер-класса. Рассматриваемое приложение использует шаблон MVVM, и я бы действительно предпочел не изменять свои классы модели, чтобы реализовать конкретное представление. Есть ли способ сделать это, не вводя в модель пользовательскую логику?


person Reed Copsey    schedule 14.10.2009    source источник


Ответы (1)


Я рассматривал возможности с пользовательским интерфейсом, где вы бы сделали привязку явной и выполняли привязку / обновления из команды ... но кажется, что самый простой способ сделать это - расширить ObservableCollection для добавления / удаления слушателей для каждой детали instance в качестве добавленного / удаленного, тогда просто активируйте CollectionChanged, когда любой из них изменится. Назовите его 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"); }
}

В худшем случае вам придется обернуть ObservableCollection в другой тип, если вы не можете должным образом переопределить все необходимые вам методы ...

person Community    schedule 14.10.2009
comment
+1, так как это действительно работает. Я думал об этом, но мне очень хотелось бы сделать это, не меняя Мастер-класс, в идеальном мире. Реализация этого означает изменение модели, чтобы позволить работать View, что мне просто не нравится ... - person Reed Copsey; 14.10.2009
comment
Ну, не совсем ... Это не сильно отличается от написания ObservableCollection в первую очередь. - person ; 15.10.2009
comment
За исключением того, что теперь у моей сущности есть свойство Sum, это чисто проблема просмотра и не связана с сущностью ... - person Reed Copsey; 15.10.2009
comment
Я не разделяю этого мнения. Цель ViewModel - готовить данные и выполнять вычисления для View. Представление должно выяснять, как отображать данные, а не выяснять, как генерировать данные для отображения. - person ; 15.10.2009
comment
Уилл: Это должна выяснить ViewModel, а не Модель. Я сформулировал это плохо - моя проблема заключалась в том, что это влияет на элементы моей модели, а не в моей модели представления. - person Reed Copsey; 16.10.2009
comment
Хех, я предположил, что Мастер был вашей моделью просмотра. Если вы хотите быть жесткими, вы можете подписаться на событие в своей ViewModel. Я немного более гибок в этом вопросе. - person ; 16.10.2009