在 WPF 应用程序中保存和取消更改时出现问题
我有一个要求,我必须实现一个三步保存功能
我有一个 MainView,它分为两部分:
- 左侧部分有一个
UserControl
,里面有一个TreeView
它。 - 右侧部分有一个
ContentControl
,它托管UserControl
,具体取决于TreeViewUserControl
中选择的项目。
为了解释这个情况,我给你举一个例子。
如果我单击叶节点,则将填充数据用户控件,并为模型 -> ViewModel -> 填充相应选定的 TreeView 项的数据。查看(用户控件)。如果用户更改数据然后保存,则必须临时保存数据,如果用户取消,则必须放弃所有更改。向 TreeView 添加新节点时应演示相同的行为。
只有当用户单击“文件”菜单中的“保存”时,数据才会被序列化并保存到磁盘。
此外,如果用户尝试离开,我希望阻止他们这样做,直到他们保存或取消更改。
我在这种情况下保存这些数据对象的临时状态时遇到问题。我尝试使用浅拷贝,但这不起作用,因为它只提供主实体的引用(在读取文件时初始化)。
还有其他方法吗?
I have a requirement for which i have to implement a 3 Step save functionality
I have a MainView which is divided into two parts:
- Left Part has a
UserControl
which has aTreeView
inside it. - Right Part has a
ContentControl
which hostsUserControl
depending upon the Item selected in theTreeViewUserControl
.
To Explain the senario i give you an example.
If i click a leaf Node the Data UserControl Will be populated and the Data of the respective selected TreeView Item is populated for the Model ->ViewModel-> View(UserControl). If the user changes the Data and then saves it it must be saved temporarily and if the user cancels all changes must be discarded. The same behavior should be demonstrated when adding new nodes to the TreeView.
Only when the user clicks Save in the File menu should the data be serialized and saved to disk.
In addition, if the user tries to navigate away, I wish to prevent them from doing so until they either save or cancel their changes.
I am facing problem in saving the temporary state of these Data objects in such senario. I tried using shallow copies but this is not working as its giving only the references of the main Entity (initialized when the file is read).
Is there any other approach?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
你的问题确实与WPF或MVVM没有太大关系。您需要跟踪模型状态的更改,并能够从 ViewModel 查询所有模型的状态,以确定是否应该允许用户离开。
不幸的是,该框架本身并不支持这种模式。你必须自己写。
我将如何(大致)完成此任务:
每个模型都会实现一个接口,比如说
IDirty
。该接口具有以下属性/方法:创建后,模型不是脏的 (
IsDirty == false
)。当它的属性改变时,它就会变得肮脏。所有属性的原始状态也会被记住。如果用户取消,则调用CancelEdit()
并恢复原始状态。如果调用AcceptEdit(),则原始状态将被当前状态覆盖。我还将创建自定义 ObservableCollection 实现,它允许我查询其中包含的所有模型的状态,以确定是否有任何模型是脏的。我的 ViewModel 也是如此,因此 View 可以绑定到 ViewModel 的 IsDirty 属性,该属性查询 ViewModel 中的所有模型集合。同样,对
CancelEdit
和AcceptEdit
的调用也被链接起来,因此您可以(例如)在 ViewModel 和所有模型上调用AcceptEdit()
其中将调用AcceptEdit
。这对于编码来说可能会变得非常乏味。我确信有一些框架旨在提供此类功能。我只是不知道有什么临时的。
Your question really doesn't have much to do with WPF or MVVM. You need to keep track of changes to your Model's states, and be able to query the states of all Models from your ViewModels to determine if you should allow users to leave.
Unfortunately, the framework doesn't natively support this pattern. You must write it yourself.
How I would (roughly) accomplish this:
Each Model would implement an interface, lets say
IDirty
. This interface has the following properties/methods:Upon creation, the Model is not dirty (
IsDirty == false
). As its properties are changed, it becomes Dirty. The original state of all properties is also remembered. If the user cancels, thenCancelEdit()
is called and the original state is restored. IfAcceptEdit()
is called, then the original state is overwritten with the current state.I would also create custom
ObservableCollection
implementations that would allow me to query the state of all Models contained within to determine if any is dirty. Same for my ViewModels, so the View can bind to the ViewModel'sIsDirty
property, which queries all collections of Models within the ViewModel. Likewise, calls toCancelEdit
andAcceptEdit
are chained as well, so you can (for example) callAcceptEdit()
on the ViewModel and all Models within will haveAcceptEdit
called on them.This can become very tedious to code. I'm sure there are some frameworks out there that are designed to provide this type of functionality. I just don't know of any offhand.
如果您使用标准的 WPF 绑定方法,那么很难实现健壮的表单处理。
这是因为 IsDirty 有 2 种类型:ViewModel.IsDirty(您的责任)和 Binding.IsDirty(WPF 责任)。
当 TextBox 文本值已更改但未发送到绑定源时,会发生 Binding.IsDirty。
ViewModel.IsDirty 可能为 false,而 Binding.IsDirty 为 true。
发生这种情况是因为 TextBox 默认 UpdateSourceTrigger 是 LostFocus,而不是 PropertyChanged。
必须采用这种方式,否则编辑 DateTime (等)将会与用户冲突(部分编辑期间验证将失败,并且用户输入将不断重新格式化)
不幸的是,WPF Binding 类没有实现 IsDirty 功能,即使它是它处于完美的位置,可以访问源 (ViewModel) 和目标 (TextBox),并收到所有相关事件的通知。
此外,Binding 类的设计不适合使用此功能进行扩展。在我看来,它是一个“黑匣子”,也是如何不设计软件的一个很好的例子。
我的解决方案是创建我自己的 Binding 类,然后我就可以再次提高工作效率。
If you use the standard WPF Binding approach then it is very hard to achieve robust form handling.
This is because there are 2 types of IsDirty, ViewModel.IsDirty (your responsibility) and Binding.IsDirty (WPF responsibility).
Binding.IsDirty occurs when a TextBox Text value has changed, but not been sent to the Binding Source.
It is possible for ViewModel.IsDirty to be false, while Binding.IsDirty to be true.
This happens because TextBox default UpdateSourceTrigger is LostFocus, not PropertyChanged.
It has to be this way otherwise editing a DateTime (etc.) will fight the user (validation will fail during partial edits and there will be constant reformatting of the user input)
Unfortunately WPF Binding class does not implement IsDirty functionality, even thought it is in a perfect position to do so, it has access to both the Source (ViewModel) and the Target (TextBox) and is notified of all relevant events.
Furthermore the design of the Binding class does not lend itself to being extended with this functionality. IMO It is a "Black Box" and a great example of how not to design software.
My solution is to create my own Binding class and then I can be productive again.