我们如何在 MVVM 模式中实现 WPF 和 SL 的更改通知传播?

发布于 2024-10-10 06:29:39 字数 1756 浏览 1 评论 0原文

以下是针对 MVVM WPF/SL 开发的示例场景:

  • 视图数据绑定到视图模型属性 “Target”
  • “Target”暴露了本地应用程序模型中存在的一个名为“data”的对象的字段,称为“Original”
  • 当“Original”发生变化时,它应该向视图模型发出通知,然后将该更改通知传播到视图。

以下是我提出的解决方案,但我不太喜欢其中任何一个。我正在寻找其他想法,当我们想出一些可靠的东西时,我确信 Microsoft 将发布带有 WPF/SL 扩展的 .NET 5,以获得更好的 MVVM 开发工具。

现在的问题是,“您采取了哪些措施来解决这个问题,效果如何?”

选项 1。

建议:

将处理程序附加到data 的PropertyChanged 事件,该事件监视它所关心的可能已更改的属性的字符串值,并引发相应的通知。

为什么我不喜欢它:

更改不会自然地冒泡,必须显式监视对象,如果数据更改为新源,则必须取消注册/注册事件。

为什么我有点喜欢它:

我可以明确控制更改的传播,并且不必使用属于应用程序更高级别的任何类型,例如依赖属性。

选项 2.

建议:

将处理程序附加到 data 的 PropertyChanged 事件,该事件使用名称属性名称在所有属性中重新引发该事件。

为什么我不喜欢它:

这本质上与选项 1 相同,但不太智能,并且迫使我永远不要更改我的属性名称,因为它们必须与选项 1 上的属性名称相同数据

为什么我有点喜欢它:

它很容易设置,我不需要考虑它...然后,如果我尝试思考,并且把名字改成有意义的东西,我搬起石头砸自己的脚,然后我必须考虑一下!

选项3.

建议:

从依赖对象继承我的视图模型,并直接通知绑定源更改。

为什么我不喜欢它:

我什至不能百分百确定依赖属性/对象可以做到这一点,这只是一个需要研究的想法。另外,我个人并不认为像 Dep Obj 这样的 WPF/SL 类型属于视图模型级别。

为什么我有点喜欢它:

如果它具有我正在寻求的功能,那么它就是一个很好的答案!减去那个讨厌的分层问题。

选项 4.

建议

使用基于 Task Parallels DataFlow Library 的一致代理消息传递系统通过链接管道传播所有内容。

为什么我不喜欢它:

我从来没有尝试过这个,而且我认为它会有所欠缺,而且它要求我从头到尾以完全不同的方式思考我的代码。

为什么我有点喜欢它:

它有可能允许我使用基于推送的数据模型进行一些非常有趣的操作,并使用 ActionBlocks 作为验证和设置器,然后私下更改视图模型属性并显式控制属性更改通知。

Here's an example scenario targetting MVVM WPF/SL development:

  • View data binds to view model Property
    "Target"
  • "Target" exposes a field of an object called "data" that exists in the local application model, called "Original"
  • when "Original" changes, it should raise notification to the view model and then propogate that change notification to the View.

Here are the solutions I've come up with, but I don't like any of them all that much. I'm looking for other ideas, by the time we come up with something rock solid I'm certain Microsoft will have released .NET 5 with WPF/SL extensions for better tools for MVVM development.

For now the question is, "What have you done to solve this problem and how has it worked out for you?"

Option 1.

Proposal:

Attach a handler to data's PropertyChanged event that watches for string values of properties it cares about that might have changed, and raises the appropriate notification.

Why I don't like it:

Changes don't bubble naturally, objects must be explicitly watched, if data changes to a new source, events must be un-registered/registered.

Why I kind of like it:

I get explicit control over propogation of changes, and I don't have to use any types that belong at a higher level of the application such as dependancy properties.

Option 2.

Proposal:

Attach a handler to data's PropertyChanged event that re-raises the event across all properties using the name property name.

Why I don't like it:

This is essentially the same as option 1, but less intelligent, and forces me to never change my property names, as they have to be the same as the property names on data

Why I kind of like it:

It's very easy to set up and I don't have to think about it... Then again if I try to think, and change names to things that make sense, I shoot myself in the foot, and then I have to think about it!

Option 3.

Proposal:

Inherit my view model from dependancy object, and notify binding sources of changes directly.

Why I don't like it:

I'm not even 100% sure dependancy properties/objects can DO this, it was just a thought to look into. Also I don't personally feel that WPF/SL types like Dep Obj belong at the view model level.

Why I kind of like it:

IF it has the capability that I'm seeking then it's a good answer! minus that pesky layering issue.

Option 4.

Proposal:

Use a consistant agent messaging system based off of Task Parallels DataFlow Library to propogate everything through linked pipelining.

Why I don't like it:

I've never tried this, and somehow I think it will be lacking, plus it requires me to think about my code completely differently all the way around.

Why I kind of like it:

It has the possiblity of allowing me to do some VERY fun manipulations with a push based data model and using ActionBlocks as validation AND setters to then privately change view model properties and explicitly control PropertyChanged notifications.

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

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

发布评论

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

评论(1

一梦等七年七年为一梦 2024-10-17 06:29:39

我基本上一直在使用选项 4。当应用程序的状态发生变化(因此模型中的数据发生变化)时,我使用 MVVM 基金会 Messenger。然后,需要此数据进行数据绑定的 ViewModel 可以订阅此消息,相应地更新本地属性,并调用 RaisePropertyChanged()* 来通知绑定系统已发生更改。

是的,这是一种不同的思考方式,但我认为这是值得的。它使您的 ViewModel 保持非常松散的耦合——它们不依赖于您的应用程序的模型,也不依赖于它们支持的视图。

我注意到的最大缺点是调试大量使用 Messenger 的代码更加困难。基本上,当抛出异常时,您将被带到 Messenger 类中的方法而不是实际的有问题的代码。我认为这是因为 Messenger 使用了弱引用。您学会了解决这个问题,但这绝对不理想。

在我最近开发的一个应用程序中,我决定将对应用程序数据的所有更改集中在一个名为 AppDataManager 的大型但简单的类中。此类包含需要跟踪更改的所有数据的字段。在启动时进行一些初始化之后,数据更改总是或几乎总是由用户发起。由于双向数据绑定,用户操作会导致 ViewModel 中的属性发生更改。然后,此更改会使用消息转发到 AppDataManager。然后,AppDataManager 更改它自己对此数据的引用,并发送一条消息来通知任何感兴趣的 ViewModel 该数据已更改。我通常将更改的数据包含在消息中(因此接收者不必知道在哪里可以找到数据)。我不确定这是最好的架构,也不知道它如何扩展到大型应用程序,但到目前为止它似乎对我来说效果很好。

显然,集中化的另一种方法是网络方法,其中 ViewModel 直接订阅彼此的消息。这很可能有效,但我还没有尝试过。我发现,如果对数据的所有更改都通过一个类进行路由,那么我可以更轻松地实现撤消系统。我的数据也是分层排列的,因此层次结构顶部的更改需要向下级联到“叶子”(例如,如果更改地图,则必须更改道路,如果更改道路,则必须更改道路)更改构成道路的航路点)。我发现集中管理这种级联比选择任意 ViewModel 来管理要容易得多。

*RaisePropertyChangedObservableObject 的成员,它也是 MVVM 基金会的一部分。我的项目中的所有 ViewModel 都继承自 ObservableObject。

注意:我正在考虑从 MVVM Foundation 切换到 MVVM Light Toolkit< /a>,这似乎是 MVVM 基金会的进一步发展。

I've basically been using Option 4. When the state of the application changes (and therefore, data in the model changes), I send out a notification using the MVVM Foundation Messenger. ViewModels that need this data for databinding can then subscribe to this message, update local properties accordingly, and call RaisePropertyChanged()* to notify the binding system that a change has occurred.

Yes, this is a different way of thinking about things, but I think it's worth it. It keeps your ViewModels very loosely coupled--they don't depend on your application's model nor the Views they support.

The biggest downside I've noticed is that debugging code that makes heavy use of the Messenger is more difficult. Basically, when an exception gets thrown, you get taken to a method in the Messenger class instead of the actual offending code. I think this is because because Messenger makes use of weak references. You learn to work around this problem, but it's definitely not ideal.

In a recent app I was working on, I decided to centralize all changes to application data in one large but simple class called AppDataManager. This class has fields for all the data that needs to be change tracked. After some initialization at startup, data changes are always or almost always initiated by the user. Thanks to two-way data binding, a user actions results in change to a property in a ViewModel. This change is then forwarded to the AppDataManager using a message. The AppDataManager then changes it's own reference to this data and sends out a message to notify any interested ViewModels that this data has changed. I usually include the changed data in the message (so the receiver doesn't have to know where to find the data). I'm not sure this is the best architecture, and I don't know how it would scale for large apps, but it seems to have worked well for me so far.

Obviously, an alternative approach to centralization would be a network approach where ViewModels subscribe directly to each other's messages. This very well might work, but I haven't tried it. I found that I could implement an undo system a lot more easily if all changes to the data were routed through one class. My data was also hierarchically arranged, so changes at the top of the hierarchy would need to cascade down to the "leaves" (e.g., if you change the map, you have to change the roads, and if you change the roads, you have to change the waypoints making up the roads). I found it much easier to manage this cascading centrally than choose an arbitrary ViewModel to do it.

*RaisePropertyChanged is a member of ObservableObject, which is also part of the MVVM Foundation. All ViewModels in my project inherit from ObservableObject.

Note: I'm thinking of switching from MVVM Foundation to the MVVM Light Toolkit, which seems to be a further development of the MVVM Foundation.

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