如何使用 WPF MVVM 回滚组合框的选定 SelectedValue
我有类似的东西会弹出给用户以获取更改确认。如果他单击“否”,我会将视图模型中的 selectedValue 设置为之前的选择。但它没有在视图中正确显示。请帮忙。
I have something like it will pop to the user for getting confirmation of changes. If he clicks no I am setting the selectedValue in view model to the previous selection. But its not getting displayed correctly in view. Please help.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
.NET 4.5.1+ 的非常简单的解决方案:
它在所有情况下都适合我。
只需触发 NotifyPropertyChanged,无需赋值即可回滚。
Very simple solution for .NET 4.5.1+:
It's works for me in all cases.
Just fire NotifyPropertyChanged without value assignment to rollback.
如果用户单击“否”并且您尝试恢复该值,然后调用 OnPropertyChanged,WPF 将吞咽该事件,因为它已经响应该事件。解决此问题的一种方法是使用调度程序并在当前事件上下文之外调用事件。
If the user clicks no and you try to revert the value and then call OnPropertyChanged, WPF will swallow the event since it is already responding to that event. One way to get around this is to use the dispatcher and call the event outside of the current event context.
WPF 似乎会在更新 UI 之前验证绑定属性是否已更改。因此,简单地调用 NotifyPropertyChanged()/OnPropertyChanged() 并不能解决问题。
问题是,由于属性没有更改,WPF 认为不需要刷新组合框。
这是我在 ViewModel 中处理它的令人难以置信的黑客方式;
不漂亮,但工作可靠。
WPF seems to validate that the bound property has changed before updating the UI. So simply invoking an NotifyPropertyChanged()/OnPropertyChanged() doesn't do the trick.
The problem is that since the property hasn't changed, WPF doesn't think it needs to refresh the combo box.
here is the incredibly hackish way I handle it in my ViewModels;
Not pretty but it works reliably.
假设:
- 当用户从 ComboBox 中选择某个值时,显示一个对话框(带有消息和 OKCancel 按钮)。
- 如果用户按“确定”,则一切正常。 :)
- 如果用户按“取消”,则表示 vmPropSelectedValue=previousValue。
这行不通。为什么?
没有确切的答案,但我相信当您显示对话框时,系统刚刚更改了所选值,并且刚刚通知源(通过绑定基础设施)改变了值。如果此时(当源具有控制权时)您现在从 VM 代码更改 ViewModel 属性的值,您预计这将触发 INotifyPropertyChanged 的 OnPropertyChanged,您预计这将要求 WPF 使用您请求的值更新目标。但是,WPF 尚未完成循环 - 它仍在等待 Source 将控制权返回给它。所以它只是拒绝你的请求(否则它会进入无限循环)。
如果这令人困惑,请尝试以下操作:
循环开始:
1. 用户更改 UI 上的值。 WPF 更改目标。
2. 绑定基础设施请求源进行自我更新。
3. 源自行更新(VM 属性)。
4. 源将控制权返回给绑定基础设施。
循环结束。
专家:找不到这方面的文档。以上是我对事情如何运作的信念。如有错误,请指正。
简短回答:
AFAIK,这不能仅通过纯 VM 代码来完成。您必须在代码后面放置一些代码。
这是一种方法: http://www.amazedsaint.com /2008/06/wpf-combo-box-cancelling-selection.html
Assumptions:
- You show a dialog box (with a message and OKCancel buttons) when a user selects some value from ComboBox.
- If user presses OK, everything is OK. :)
- If user presses Cancel, you say vmPropSelectedValue=previousValue.
This won't work. Why?
Don't have exact answer, but I believe when you show the dialog the system has just changed the selected value and has just notified the Source (via binding infrastructure) about the changed value . If at this moment (when source has control) you now change the value of ViewModel property from your VM code, which you expect would trigger OnPropertyChanged of INotifyPropertyChanged, which you expect would ask the WPF to update the target with your requested value. However, the WPF has not yet completed the cycle - its still waiting for the Source to return the control back to it. So it simply rejects your request (otherwise it would go in infinite loop).
If this was confusing, try this:
Cycle starts:
1. User changes value on UI. WPF changes target.
2. binding infrastructure requests Source to update itself.
3. Source updates itself (VM property).
4. Source returns control back to binding infra.
Cycle End.
Experts: Can't find some documentation in this regard. Above is my belief how things work. Please rectify if incorrect.
Short Answer:
AFAIK, this can't be done via pure VM code alone. You will have to put some code-behind code.
Here's one way: http://www.amazedsaint.com/2008/06/wpf-combo-box-cancelling-selection.html
在大多数 WPF 应用程序中,您可以使用 TwoWay 模式将视图模型绑定到用户界面,然后就可以开始了。
然而,这违背了典型的用户体验,当您编辑某些内容但不保存时,您不会看到该编辑反映在整个应用程序中,即使您没有将更改保存到数据库也是如此。
WPF 中可用的机制是 Binding 的 UpdateSourceTrigger 属性。使用此属性,您可以控制用户界面何时更新其绑定到的 ViewModel。这允许您仅在用户保存他正在编辑的内容或类似内容时进行更新。
UpdateSourceTrigger 设置为 Explicit 的 XAML 绑定示例:
当您想要真正保存到 ViewModel 时,您可以调用:
In most WPF applications you bind a view model to the user interface with a TwoWay mode and then you're set to go.
However this goes against the typical user experience, where when you edit something and you don't save, you don't see that editing reflected throughout your entire application, even if you don't save your changes to the Database.
The mechanism available in WPF is the UpdateSourceTrigger property of the Binding. With this property you can control when the User Interface updates the ViewModel that it is bound to. This allows you to update only when the user saves what he's editing or something similar.
An example of a XAML Binding with the UpdateSourceTrigger set to Explicit:
And when you want to really save to the ViewModel you call:
如果您尝试异步引发属性更改事件怎么办?这与 shaun 和 NebulaSleuth 的例子类似。
What if you tried to raise the property changed event asynchronously? This is similar the examples from shaun and NebulaSleuth.
以下是我使用的一般流程:
(如果您的业务逻辑要求所选项目不处于无效状态,我建议将其移至模型端)。此方法对于使用单选按钮呈现的列表框也很友好,因为使 SelectedItem setter 尽快退出不会阻止单选按钮在弹出消息框时突出显示。
我将所有撤消逻辑放入处理程序中,并使用 SynchronizationContext.Post() 调用该事件
(顺便说一句:SynchronizationContext.Post 也适用于 Windows 应用商店应用程序。因此,如果您共享 ViewModel 代码,此方法仍然有效)。
Here is the general flow that I use:
(If your business logic requires the selected item to not be in an invalid state, I suggest moving that to the Model side). This approach is also friendly to ListBoxes that are rendered using Radio Buttons as making the SelectedItem setter exit as soon as possible will not prevent radio buttons from being highlighted when a message box pops out.
I put any undo logic in a handler and call that using SynchronizationContext.Post()
(BTW: SynchronizationContext.Post also works for Windows Store Apps. So if you have shared ViewModel code, this approach would still work).
我意识到这是一篇旧帖子,但似乎没有人以正确的方式做到这一点。我使用 System.Interactivity.Triggers 和 Prism 来处理 SelectionChanged 事件并手动触发 SelectedItem。这将防止 UI 和视图模型中发生不需要的选定项更改。
我的看法:
我的视图模型(来自 Prism 5 的 BindeableBase 和 DelegateCommand):
I realize this is an old post but it seems no one has done this the right way. I used System.Interactivity.Triggers and Prism to process the SelectionChanged event and manually trigger the SelectedItem. This will prevent undesired Selected Item Changes in both the UI and the View-Model.
My view:
My View-Model (BindeableBase and DelegateCommand from Prism 5):