在WPF的MVVM模式中,处理对话框是比较复杂的操作之一。由于视图模型不知道视图的任何信息,因此对话框通信可能会很有趣。我可以公开一个ICommand,当视图调用它时,就会出现一个对话框。
有人知道处理对话框结果的好方法吗?我说的是windows对话框,比如MessageBox。
其中一种方法是在视图模型上设置一个事件,当需要对话框时,视图会订阅该事件。
public event EventHandler<MyDeleteArgs> RequiresDeleteDialog;
这是可以的,但这意味着视图需要代码,这是我想要避免的。
一个好的MVVM对话框应该:
仅用XAML声明。
从数据绑定中获取它的所有行为。
不幸的是,WPF不提供这些特性。显示对话框需要对ShowDialog()进行代码隐藏调用。支持对话框的Window类不能在XAML中声明,因此它不能轻易地绑定到DataContext。
为了解决这个问题,我写了一个XAML存根控件,它位于逻辑树中,将数据绑定传递给一个Window,并处理显示和隐藏对话框的问题。你可以在这里找到它:http://www.codeproject.com/KB/WPF/XAMLDialog.aspx
它使用起来非常简单,不需要对ViewModel进行任何奇怪的更改,也不需要事件或消息。基本调用如下所示:
<dialog:Dialog Content="{Binding Path=DialogViewModel}" Showing="True" />
您可能希望添加一个设置显示的样式。我在我的文章中解释过。我希望这对你有所帮助。
编辑: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
使用可冻结命令
<Grid>
<Grid.DataContext>
<WpfApplication1:ViewModel />
</Grid.DataContext>
<Button Content="Text">
<Button.Command>
<WpfApplication1:MessageBoxCommand YesCommand="{Binding MyViewModelCommand}" />
</Button.Command>
</Button>
</Grid>
public class MessageBoxCommand : Freezable, ICommand
{
public static readonly DependencyProperty YesCommandProperty = DependencyProperty.Register(
"YesCommand",
typeof (ICommand),
typeof (MessageBoxCommand),
new FrameworkPropertyMetadata(null)
);
public static readonly DependencyProperty OKCommandProperty = DependencyProperty.Register(
"OKCommand",
typeof (ICommand),
typeof (MessageBoxCommand),
new FrameworkPropertyMetadata(null)
);
public static readonly DependencyProperty CancelCommandProperty = DependencyProperty.Register(
"CancelCommand",
typeof (ICommand),
typeof (MessageBoxCommand),
new FrameworkPropertyMetadata(null)
);
public static readonly DependencyProperty NoCommandProperty = DependencyProperty.Register(
"NoCommand",
typeof (ICommand),
typeof (MessageBoxCommand),
new FrameworkPropertyMetadata(null)
);
public static readonly DependencyProperty MessageProperty = DependencyProperty.Register(
"Message",
typeof (string),
typeof (MessageBoxCommand),
new FrameworkPropertyMetadata("")
);
public static readonly DependencyProperty MessageBoxButtonsProperty = DependencyProperty.Register(
"MessageBoxButtons",
typeof(MessageBoxButton),
typeof(MessageBoxCommand),
new FrameworkPropertyMetadata(MessageBoxButton.OKCancel)
);
public ICommand YesCommand
{
get { return (ICommand) GetValue(YesCommandProperty); }
set { SetValue(YesCommandProperty, value); }
}
public ICommand OKCommand
{
get { return (ICommand) GetValue(OKCommandProperty); }
set { SetValue(OKCommandProperty, value); }
}
public ICommand CancelCommand
{
get { return (ICommand) GetValue(CancelCommandProperty); }
set { SetValue(CancelCommandProperty, value); }
}
public ICommand NoCommand
{
get { return (ICommand) GetValue(NoCommandProperty); }
set { SetValue(NoCommandProperty, value); }
}
public MessageBoxButton MessageBoxButtons
{
get { return (MessageBoxButton)GetValue(MessageBoxButtonsProperty); }
set { SetValue(MessageBoxButtonsProperty, value); }
}
public string Message
{
get { return (string) GetValue(MessageProperty); }
set { SetValue(MessageProperty, value); }
}
public void Execute(object parameter)
{
var messageBoxResult = MessageBox.Show(Message);
switch (messageBoxResult)
{
case MessageBoxResult.OK:
OKCommand.Execute(null);
break;
case MessageBoxResult.Yes:
YesCommand.Execute(null);
break;
case MessageBoxResult.No:
NoCommand.Execute(null);
break;
case MessageBoxResult.Cancel:
if (CancelCommand != null) CancelCommand.Execute(null); //Cancel usually means do nothing ,so can be null
break;
}
}
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
protected override Freezable CreateInstanceCore()
{
throw new NotImplementedException();
}
}