MVVM下如何同屏实现CRUD Master Details
我有一个 MVVM(Prism)应用程序,我需要实现一个主详细信息屏幕,其中主是一个列表视图,详细信息显示在它旁边。只读似乎很容易(尚未完成,但我已经了解了 WPF 绑定),但编辑/添加让我感到困惑。
如何使主数据在保存详细信息之前不会更新? 如何才能使您在编辑/添加模式下无法更改主控的当前选择?
我已经在谷歌上搜索了很多,但没有找到任何实质性的例子。
谢谢。
PS:此视图是大屏幕上的子视图。这就是为什么我希望将主图和细节放在一起。
I have a MVVM (Prism) application that I need to implement a master details screen wheer the master is a listview and the details is displayed next to it. Read-only seems easy enough (haven't done it yet but I've got my head around WPF binding) but edit/add confuses me.
How to I make it so the master is not updated until the details is saved?
How do I make it so you can't change the master's current selection while in edit/add mode?
I've been googling a plenty but have not found any meaty examples of this.
Thanks.
PS: This view is a child view on a larger screen. This is why I want both master and detail together.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您当然可以做到这一点,尽管在我看来,这样的 UI 设计无法充分利用 WPF 的全部功能。旧的 WinForms UI 通常不会更新大部分应用程序,直到数据保存到 SQL Server(或其他地方),因为它们没有真正的业务对象和像 WPF 这样强大的绑定系统。尝试在 WPF 中复制 WinForms 的限制对我来说似乎是一种倒退。为什么不在 UI 中可见的所有位置(包括主视图)显示最新数据?另外,为什么不允许用户在保存之前编辑多个项目,例如在主视图中使用动画标记标记任何已编辑但未保存的项目?将这些与通用撤消结合起来,您将获得更好的设计并且对用户来说更直观。
但是,如果您的业务要求绝对有必要,则执行以下操作:
防止对数据的更改在保存之前在详细信息之外可见
进入“编辑/添加模式”时,使数据对象的副本,并将详细信息视图的 DataContext 设置为副本而不是实时对象。 “保存”数据后,将数据从卷影副本复制回活动对象,并将详细视图的 DataContext 设置回其应有的位置。
防止在编辑/添加模式下更改母版的当前选择
两种可能性:
在编辑/添加模式下,更改母版视图以禁止鼠标点击测试或键盘焦点
当编辑/添加模式开始时,捕获“当前选择”,然后添加一个事件处理程序来监视“当前选择”更改并立即更改选择回到原来的样子。当编辑/添加模式结束时,删除处理程序。该处理程序可以使用 lambda 表达式方便地进行编码,并使用局部变量上的闭包来存储当前选择。
You certainly can do this, though in my opinion such a UI design fails to harness the full power of WPF. Old WinForms UIs usually didn't update most of the application until data was saved to SQL Server (or wherever) because they didn't have real business objects and a powerful binding system like WPF. Trying to copy WinForms limitations within WPF seems like a step backward to me. Why not show the latest data everywhere it is visible in the UI, including in the master view? Also, why not allow the user to edit multiple items before saving, for example marking any edited but unsaved item with an animated marker in the master view? Combine these with a generalized undo and you have a better design and more intuitive for the user.
However if your business requirements make it absolutely necessary, here is how to do it:
Preventing changes to data from being visible outside the detail until it is saved
Upon entry into your "edit/add mode", make a copy of the data objects and set your detail view's DataContext to the copy instead of the live object. When the data is "saved", copy the data from the shadow copy back into the live object and set your detail view's DataContext back where it should be.
Preventing the master's current selection from changing while in edit/add mode
Two possibilities:
During edit/add mode, change the master view to disallow mouse hit testing or keyboard focus
When edit/add mode begins, capture the "current selection" then add an event handler that watches for "current selection" changes and immediately changes the selection back to what it was. When edit/add mode ends, remove the handler. This handler can be conveniently coded using a lambda expression and using a closure on a local variable to store the current selection.
感谢您的回答。现在我重新阅读了我的消息,我发现它相当模糊。我有一个编辑对象的屏幕,其中包含其他子对象的多个列表。我已将它们实现为选项卡控件中的不同选项卡。其中一个选项卡可以编辑评论,因此我想显示评论列表,并在列表旁边显示当前选择的编辑面板。然后,用户可以使用添加、编辑或删除按钮来更新列表。我想以纯粹的 MVVM 方式做到这一点。
我想出了以下设计,它似乎可以用最少的技巧来工作。
View 包含一个子对象列表,就像绑定到 ViewModel 中可观察集合的 ListView 一样。我包含了一个子对象缓冲区——它用于缓冲更改,直到它们准备好保存回列表(或丢弃)。
View 还包括一个绑定到 ViewModel 中的缓冲区对象的编辑面板。每当列表视图的当前选择使用深层复制更改时,缓冲区就会更新。我尝试在 Selecteditem 属性上使用数据绑定,但从未调用该集,因此添加了一个小的代码隐藏方法,以在选择更改时强制更新该属性。
列表视图和编辑视图是互斥的。理论上,您可以隐藏禁用的屏幕,也许可以使用翻转屏幕。作为一般模式,我的应用程序最好同时显示两者,因为编辑面板可能会显示列表视图中未显示的额外信息。通过将 IsEnabled 绑定到 ViewModel 属性(如 IsEditCommentMode)来控制启用哪个面板的选择。
必须添加管理列表的命令,这些命令是新建、编辑和删除。请注意,“添加”和“编辑”将设置缓冲区,然后将 IsEditCommentMode 设置为 true。这些列表管理命令仅在 IsEditCommentMode 为 false 时可用。
编辑面板实现了保存和取消命令,它们仅在 IsEditCommentMode 为 true 时启用。当执行 Save 时,它应该从缓冲区复制到列表(添加或更新)并触发更改通知。最后,应该将 IsEditCommentMode 设置为 false。
这一切都运行良好,并且似乎没有违反任何 MVVM 原则(以我谦虚但经常有缺陷的观点)。
Thanks for the answer. Now I've re-read my message, I see it is rather vague. I have a screen that edits an object which contains multiple lists of other child objects. I've implemented these as different tabs in a tab control. One of these tabs edits the comments, so I wanted to display a list of comments with an edit panel for the current selection next to the list. The user could then use add, edit or delete buttons to update the list. I wanted to do this in a pure(ish) MVVM way.
I came up with the following design which seems to work with minimal hacks.
The View includes a list of the child objects simply as a ListView bound to an observable collection within the ViewModel. I included a child object buffer – this is used to buffer changes until they are ready to be saved back to the list (or thrown away).
The View also includes an edit panel bound to the buffer object in the ViewModel. The buffer is updated whenever the list view’s current selection changes using a deep copy. I tried using data binding on the Selecteditem property but the set was never called, so a small code-behind method was added to force the property to be updated when the selection was changed.
The list view and edit view are mutually exclusive. In theory you could hide the disabled one, perhaps using a flip screen. As a general pattern, it is better for my app to have both visible at the same time as the edit panel may show extra information not shown in the list view. The choice as to which panel is enabled is controlled by binding IsEnabled to a ViewModel property like IsEditCommentMode.
Commands to manage the list have to be added, these are New, Editand Delete. Note that Add and Edit will set set up the buffer then set IsEditCommentMode to true. These list management commands are only available when IsEditCommentMode is false.
The edit panel implements Save and Cancel commands, they are only be enabled when IsEditCommentMode is true. When Save is executed, it should copy from the buffer to the list (either add or update) and fire the change notification. Finally, it should set IsEditCommentMode to false.
This all works well and does not seem to violate any MVVM tenents (in my humble but often flawed opinion).