我有一个WPF应用程序,它在ViewModel中调用MessageBox.Show()方式(检查用户是否真的要删除)。 这实际上有效,但是违背了MVVM ,因为ViewModel不应该明确地确定View上会发生什么。
所以现在我想如何在我的MVVM应用程序中最好地实现MessageBox.Show()功能,选项:
我可以收到一条短信,上面写着“你确定......?”以及我的XAML中的边框中的两个按钮是和否全部,并在模板上创建一个触发器,使其基于名为 AreYourSureDialogueBoxIsVisible 的ViewModelProperty折叠/可见,然后当我需要此对话框时框,将AreYourSureDialogueBoxIsVisible指定为“true”,并在ViewModel中通过DelegateCommand处理这两个按钮。
我也可以尝试用XAML中的触发器来处理这个问题,这样“删除”按钮实际上只会使一些Border元素出现,其中包含消息和按钮,而Yes按钮实际上是删除了。
对于曾经使用MessageBox.Show()的几行代码,两种解决方案似乎都过于复杂。
您在哪些方面成功实施了MVVM应用程序中的对话框?
答案 0 :(得分:12)
救援服务。使用Onyx(免责声明,我是作者),这很简单:
public void Foo()
{
IDisplayMessage dm = this.View.GetService<IDisplayMessage>();
dm.Show("Hello, world!");
}
在正在运行的应用程序中,这将间接调用MessageBox.Show(“Hello,world!”)。在测试时,可以模拟IDisplayMessage服务并将其提供给ViewModel,以便在测试期间完成您想要完成的任务。
答案 1 :(得分:5)
在你提到的两个中,我更喜欢选项#2。页面上的“删除”按钮只显示“确认删除对话框”。 “确认删除对话框”实际上启动了删除。
你看过Karl Shifflett的WPF Line Of Business Slides and Demos吗?我知道他做的是这样的。我会试着记住哪里。
编辑:查看演示#11“MVVM中的数据验证”(EditContactItemsControlSelectionViewModel.DeleteCommand)。 Karl从ViewModal调用一个弹出窗口(What!?:-)。我其实更喜欢你的想法。似乎更容易进行单元测试。
答案 2 :(得分:4)
要扩展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)使用委托命令来显示&#34;你确定吗?&#34;对话框并执行操作。在此示例中,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
答案 3 :(得分:3)
我只是创建了一个接口(IMessageDisplay或类似的),它被注入VM,它有像MessageBox(ShowMessage()等)的方法。您可以使用标准消息框或更具特定于WPF的内容来实现(我使用this one on CodePlex一些名为Prajeesh的人。)
这样一切都是分开的和可测试的。
答案 4 :(得分:3)
如何在视图的代码隐藏中处理像"MessageBoxRequested"
这样的事件(无论如何它只是查看代码,所以我没有看到在代码隐藏时使用此代码有任何问题。)
答案 5 :(得分:1)
我已经制作了一个简单的MessageBox包装器控件,供我们在纯MVVM解决方案中使用,并且仍然允许单元测试功能。详细信息在我的博客http://geekswithblogs.net/mukapu/archive/2010/03/12/user-prompts-messagebox-with-mvvm.aspx
中mukapu
答案 6 :(得分:1)
我实现了一个侦听来自ViewModel的Message的Behavior。它基于Laurent Bugnion解决方案,但由于它不使用代码并且更可重用,我认为它更优雅。
答案 7 :(得分:1)
答案 8 :(得分:1)
以防万一其他人仍在阅读并且不满意:
我只是想处理'通知'类型的MessageBoxes(即我不关心DialogResult
),但是我对大多数解决方案的解决方案是,他们似乎间接地强迫你可以选择你的View实现(也就是说,目前我有一个MessageBox.Show
,但如果我后来决定直接在我的视图中调整隐藏面板的可见性,那么它将不会很好地与{传递给ViewModel的接口{1}}。
所以我快速而又肮脏:
ViewModel具有INotification
属性,更改通知string NotificationMessage
。
视图订阅PropertyChanged
,如果它看到PropertyChanged
属性通过,则执行任何操作。
好的,这意味着View有代码隐藏,NotificationMessage
的名称是硬编码的,但无论如何它都会在XAML中进行硬编码。这意味着我避免使用像Visibility转换器这样的东西,以及说明通知是否仍然可见的属性。
(不可否认,这只适用于有限的用例(火灾和遗忘),我没有考虑过如何扩展它。)
答案 9 :(得分:0)
我只是从VM中抛出它。我不想使用其他人的服务或只是自己写一个消息框。
答案 10 :(得分:0)
我最近遇到过这个问题,我必须使用一些完全MVVM投诉消息框机制替换ViewModels中的MessageBox.Show。
为实现这一目标,我使用了InteractionRequest<Notification>
和InteractionRequest<Confirmation>
以及交互触发器,并为消息框编写了自己的视图。
我已实施的内容已发布here
答案 11 :(得分:0)
关于此主题的答案很多,从创建自定义类到使用第三方库不等。我想说的是,如果您想要带有漂亮视觉效果的炫酷弹出窗口,请使用第三方库。
但是,如果您只想将Microsoft的常规消息框用于WPF应用程序,则这里是MVVM /单元测试友好的实现:
最初,我以为我只是从消息框继承并用接口包装它,但由于消息框没有公共构造函数而无法这样做,所以这是“简单”的解决方案:
在Visual Studio中的反编译消息框中,您可以看到所有方法重载,我检查了我想要的重载,然后创建了一个新类并添加了方法,并用接口和ta-da对其进行了包装!现在,您可以使用ninject绑定接口和类,注入它,然后使用Moq对e.t.c进行单元测试。
创建一个接口(仅添加了一些重载,因为我不需要全部重载):
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);
}
然后,我们有了将从其继承的类:
public class MessageBoxHelper : IMessageBox
{
/// <summary>Displays a message box that has a message, title bar caption, button, and icon; and that returns a result.</summary>
public MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button,
MessageBoxImage icon)
{
return MessageBox.Show(messageBoxText, caption, button, icon, MessageBoxResult.None,
MessageBoxOptions.None);
}
/// <summary>Displays a message box that has a message, title bar caption, and button; and that returns a result.</summary>
public MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button)
{
return MessageBox.Show(messageBoxText, caption, button, MessageBoxImage.None, MessageBoxResult.None,
MessageBoxOptions.None);
}
/// <summary>Displays a message box that has a message and title bar caption; and that returns a result.</summary>
public MessageBoxResult Show(string messageBoxText, string caption)
{
return MessageBox.Show(messageBoxText, caption, MessageBoxButton.OK, MessageBoxImage.None,
MessageBoxResult.None, MessageBoxOptions.None);
}
/// <summary>Displays a message box that has a message and that returns a result.</summary>
public MessageBoxResult Show(string messageBoxText)
{
return MessageBox.Show(messageBoxText, string.Empty, MessageBoxButton.OK, MessageBoxImage.None,
MessageBoxResult.None, MessageBoxOptions.None);
}
}
现在只需在注入e.t.c和臂杆u时使用它即可实现脆弱的抽象...这很好,具体取决于您将在哪里使用它。我的情况是一个简单的应用程序,仅意味着要做一些事情,因此设计解决方案毫无意义。希望这对某人有帮助。