我有一个WPF应用程序,它在ViewModel中调用MessageBox.Show()方式(以检查用户是否真的要删除)。这实际上是有效的,但是违背了MVVM,因为ViewModel不应该明确地确定View上发生了什么。
所以现在我在想如何在我的MVVM应用程序中最好地实现MessageBox.Show()功能,选项:
对于曾经使用MessageBox.Show()的几行代码而言,这两种解决方案似乎都过于复杂。
您在哪些方面成功实现了MVVM应用程序中的Dialogue Box?
在你提到的两个中,我更喜欢选项#2。页面上的“删除”按钮只显示“确认删除对话框”。 “确认删除对话框”实际上启动了删除。
你看过Karl Shifflett的WPF Line Of Business Slides and Demos吗?我知道他做的是这样的。我会试着记住哪里。
编辑:查看演示#11“MVVM中的数据验证”(EditContactItemsControlSelectionViewModel.DeleteCommand)。 Karl从ViewModal调用一个弹出窗口(What!?:-)。我其实更喜欢你的想法。似乎更容易进行单元测试。
我会把它从VM中抛出来。我不想使用别人的服务或只是写自己的邮箱。
我最近遇到了这个问题,我不得不用一些完全MVVM投诉消息框机制替换ViewModels中的MessageBox.Show。
为了达到这个目的,我使用了PropertyChanged
和InteractionRequest<Notification>
以及交互触发器,并为消息框编写了我自己的视图。
我实施的是发布InteractionRequest<Confirmation>
关于此主题有很多答案,从创建自定义类到使用第三方库都有所不同。我想说如果你想要一个很好的视觉效果的酷炫弹出窗口,可以使用第三方库。
但是,如果您只是想使用microsoft的常规消息框来获取WPF应用,那么这是一个MVVM /单元测试友好的实现:
最初我以为我会从消息框继承并用接口包装但我不能因为Message框没有公共构造函数,所以这里是“简单”的解决方案:
在visual studio中反编译消息框你可以看到所有的方法重载,我检查了我想要的那些然后创建了一个新类并添加了方法,用接口和ta-da包装它!现在你可以使用ninject来绑定接口和类,注入它并使用Moq来对e.t.c进行单元测试。
创建一个接口(只添加了一些重载,因为我不需要它们):
here
然后我们有继承它的类:
public interface IMessageBox
{
/// <summary>Displays a message box that has a message, title bar caption, and button; and that returns a result.</summary>
MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button);
/// <summary>Displays a message box that has a message, title bar caption, button, and icon; and that returns a result.</summary>
MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon);
/// <summary>Displays a message box that has a message and title bar caption; and that returns a result.</summary>
MessageBoxResult Show(string messageBoxText, string caption);
}
现在只需在注入e.t.c时使用它,并且使用一个脆弱的抽象来完成这个技巧......这很好,取决于你将使用它的位置。我的案例是一个简单的应用程序,只是为了做一些事情,所以没有必要设计一个解决方案。希望这有助于某人。
救援服务。使用Onyx(免责声明,我是作者)这很简单:
public void Foo()
{
IDisplayMessage dm = this.View.GetService<IDisplayMessage>();
dm.Show("Hello, world!");
}
在正在运行的应用程序中,这将间接调用MessageBox.Show(“Hello,world!”)。在测试时,可以模拟IDisplayMessage服务并将其提供给ViewModel,以便在测试期间完成您想要完成的任务。
现在扩展Dean Chalk的答案,他的链接是kaput:
在App.xaml.cs文件中,我们将确认对话框连接到viewmodel。
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var confirm = (Func<string, string, bool>)((msg, capt) => MessageBox.Show(msg, capt, MessageBoxButton.YesNo) == MessageBoxResult.Yes);
var window = new MainWindowView();
var viewModel = new MainWindowViewModel(confirm);
window.DataContext = viewModel;
...
}
在视图(MainWindowView.xaml)中,我们有一个调用ViewModel中的命令的按钮
<Button Command="{Binding Path=DeleteCommand}" />
viewmodel(MainWindowViewModel.cs)使用委托命令来显示“你确定吗?”对话框并执行操作。在这个例子中,它是一个类似于SimpleCommand
的this,但是ICommand的任何实现都应该这样做。
private readonly Func<string, string, bool> _confirm;
//constructor
public MainWindowViewModel(Func<string, string, bool> confirm)
{
_confirm = confirm;
...
}
#region Delete Command
private SimpleCommand _deleteCommand;
public ICommand DeleteCommand
{
get { return _deleteCommand ?? (_deleteCommand = new SimpleCommand(ExecuteDeleteCommand, CanExecuteDeleteCommand)); }
}
public bool CanExecuteDeleteCommand()
{
//put your logic here whether to allow deletes
return true;
}
public void ExecuteDeleteCommand()
{
bool doDelete =_confirm("Are you sure?", "Confirm Delete");
if (doDelete)
{
//delete from database
...
}
}
#endregion
我只是创建一个接口(IMessageDisplay或类似的),它被注入VM,它有像MessageBox(ShowMessage()等)的方法。你可以使用一个标准的消息框来实现它,或者更具体的WPF(我使用this one on CodePlex一些叫做Prajeesh的人)。
这样一切都是分开的和可测试的。
如何在视图后面的代码中处理像qazxsw poi这样的事件(无论如何它只是查看代码,所以我没有看到在代码隐藏上使用此代码有任何问题)。
我已经为我们制作了一个简单的MessageBox包装器控件,可以在纯MVVM解决方案中使用,并且仍然允许单元测试功能。详细信息在我的博客"MessageBoxRequested"
中
杯
我已经实现了一个侦听来自ViewModel的Message的Behavior。它基于Laurent Bugnion解决方案,但由于它不使用代码并且更可重用,我认为它更优雅。
http://geekswithblogs.net/mukapu/archive/2010/03/12/user-prompts-messagebox-with-mvvm.aspx
以防万一其他人仍在阅读和不满意:
我只是想处理'通知'类型的MessageBoxes(即我不关心http://slwpfmessagebox.codeplex.com/),但我遇到的大多数解决方案的问题是它们似乎间接强迫您选择View实现(也就是说,目前我有一个DialogResult
,但如果我后来决定直接在我的视图中调整隐藏面板的可见性,那么它将与传入ViewModel的MessageBox.Show
接口非常吻合。
所以我快速而又肮脏:
ViewModel有一个INotification
属性,更改通知string NotificationMessage
。
View订阅PropertyChanged
,如果它看到PropertyChanged
属性通过,做它想要的任何东西。
好的,这意味着View具有代码隐藏功能,而NotificationMessage
的名称是硬编码的,但无论如何它都会在XAML中进行硬编码。这意味着我避免了所有的东西,比如Visibility的转换器,以及说明通知是否仍然可见的属性。
(不可否认,这只是针对有限的用例(火灾和遗忘),我没有考虑过如何扩展它。)