主从视图中聚合详细信息值

发布于 2024-08-07 14:15:22 字数 1206 浏览 4 评论 0原文

我在一些自定义实体中有主从关系。假设我有以下结构:

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,显示 Master 对象的列表。当我选择特定的 Master 时,我将有一个单独的 ListView 来显示详细信息,以便进行编辑。基本上,这是一个相当标准的主从视图。

但是,我还希望 Master 的 GridView 显示该 master 的所有 Detail 元素的总和,即: Details.Select(d => d.Value).Sum();

这是使用自定义 IValueConverter 相当容易显示。我可以将详细信息集合直接转换为双显示总和,并通过 IValueConverter 将 TextBlock 的文本绑定到详细信息 OneWay。这将起作用,并在我打开窗口时显示正确的值。

但是,如果我更改详细信息成员之一,这将不会更新(即使详细信息实现了 INotifyPropertyChanged),因为集合本身仍然相同(ObservableCollection 引用没有更改)。

我希望在主列表中有一个聚合值,显示详细列表中的总和(或平均值/计数/等),并在用户更改详细信息属性时保持最新状态。我该如何实施呢?


编辑:

理想情况下,我更希望有一种方法可以完成此任务,而不涉及直接更改 Master 类。有问题的应用程序正在使用 MVVM 模式,我真的不想为了实现特定的视图而更改我的模型类。有没有办法在不将自定义逻辑引入模型的情况下做到这一点?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

路还长,别太狂 2024-08-14 14:15:22

我正在考虑 UI 的可能性,您可以在其中显式绑定并通过命令执行绑定/更新...但似乎最简单的方法是扩展 ObservableCollection 以添加/删除每个详细信息的侦听器实例作为其添加/删除,然后在其中任何一个发生更改时触发 CollectionChanged 。称之为 DeeplyObservableCollection

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 包装为另一种类型...

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文