在WPF的MVVM模式中,处理对话框是比较复杂的操作之一。由于视图模型不知道视图的任何信息,因此对话框通信可能会很有趣。我可以公开一个ICommand,当视图调用它时,就会出现一个对话框。
有人知道处理对话框结果的好方法吗?我说的是windows对话框,比如MessageBox。
其中一种方法是在视图模型上设置一个事件,当需要对话框时,视图会订阅该事件。
public event EventHandler<MyDeleteArgs> RequiresDeleteDialog;
这是可以的,但这意味着视图需要代码,这是我想要避免的。
编辑:10多年后,我可以看出使用Mediator或任何其他消息传递模式在很多层面上都是一个非常糟糕的主意。不要这样做,只需实现Jeffrey的答案或在视图模型中注入一个IDialogService即可。
你应该找个中间人。
Mediator是一种常见的设计模式,在某些实现中也称为Messenger。
它是一种Register/Notify类型的范例,允许ViewModel和Views通过低耦合消息传递机制进行通信。
你应该看看谷歌WPF门徒组,然后搜索调解员。
你会很高兴得到答案的……
但是你可以这样开始:
http://joshsmithonwpf.wordpress.com/2009/04/06/a-mediator-prototype-for-wpf-apps/
享受吧!
编辑:你可以看到这个问题的答案与MVVM轻工具包在这里:
http://mvvmlight.codeplex.com/Thread/View.aspx?ThreadId=209338
我建议放弃20世纪90年代的模态对话框,而是实现一个覆盖控件(画布+绝对定位),可见性绑定到虚拟机中的布尔值。更接近ajax类型控件。
这非常有用:
<BooleanToVisibilityConverter x:Key="booltoVis" />
如:
<my:ErrorControl Visibility="{Binding Path=ThereWasAnError, Mode=TwoWay, Converter={StaticResource booltoVis}, UpdateSourceTrigger=PropertyChanged}"/>
下面是我如何实现一个用户控件。单击“x”关闭后面用户控件代码中的一行代码中的控件。(因为我有我的视图在一个。exe和ViewModels在一个dll,我不觉得代码操纵UI。)
有两种好方法可以做到这一点,1)对话框服务(简单,干净),2)视图辅助。视图辅助提供了一些简洁的特性,但通常不值得这样做。
对话框的服务
A)一个对话服务接口,比如via构造函数或一些依赖容器:
接口IDialogService
{
任务ShowDialogAsync(DialogViewModel dlgVm);
}
b) Your implementation of IDialogService should open a window (or inject some control into the active window), create a view corresponding to the name of the given dlgVm type (use container registration or convention or a ContentPresenter with type associated DataTemplates). ShowDialogAsync should create a TaskCompletionSource and return its .Task proptery. The DialogViewModel class itself needs an event you can invoke in the derived class when you want to close, and watch in the dialog view to actually close/hide the dialog and complete the TaskCompletionSource.
b)要使用,只需在某个dialogviewmodel派生类的实例上调用await this.DialogService.ShowDialog(myDlgVm)。等待返回后,查看你在对话框VM中添加的属性,以确定发生了什么;你甚至不需要回调。
查看帮助
这让你的视图监听视图模型上的事件。如果您愿意的话,可以将这些都打包到一个Blend Behavior中,以避免背后的代码和资源使用(FMI,子类化“Behavior”类,以查看类固醇上的一种可混合的附加属性)。现在,我们将手动在每个视图上执行此操作:
a)创建一个带有自定义有效负载(DialogViewModel派生类)的OpenXXXXXDialogEvent。
b)让视图在OnDataContextChanged事件中订阅该事件。如果旧值!= null并且在窗口的Unloaded事件中,请务必隐藏并取消订阅。
c)当事件触发时,让视图打开你的视图,它可能在你页面的资源中,或者你可以通过约定在其他地方定位它(比如在对话框服务方法中)。
这种方法更灵活,但需要做更多的工作才能使用。我不怎么用它。例如,一个很好的优点是能够将视图物理地放置在一个选项卡中。我已经使用一种算法将其放置在当前用户控件的边界中,或者如果不够大,则遍历可视树,直到找到足够大的容器。
这允许对话框靠近它们实际使用的地方,只使应用程序中与当前活动相关的部分变暗,并让用户在应用程序中移动而不必手动将对话框推开,甚至在不同的选项卡或子视图上打开多个准模态对话框。