你是如何在MVVM中成功实现MessageBox.Show()功能的?

时间:2009-07-08 13:19:12

标签: wpf mvvm triggers messagebox

我有一个WPF应用程序,它在ViewModel中调用MessageBox.Show()方式(检查用户是否真的要删除)。 这实际上有效,但是违背了MVVM ,因为ViewModel不应该明确地确定View上会发生什么。

所以现在我想如何在我的MVVM应用程序中最好地实现MessageBox.Show()功能,选项:

  1. 我可以收到一条短信,上面写着“你确定......?”以及我的XAML中的边框中的两个按钮是和否全部,并在模板上创建一个触发器,使其基于名为 AreYourSureDialogueBoxIsVisible 的ViewModelProperty折叠/可见,然后当我需要此对话框时框,将AreYourSureDialogueBoxIsVisible指定为“true”,并在ViewModel中通过DelegateCommand处理这两个按钮。

  2. 我也可以尝试用XAML中的触发器来处理这个问题,这样“删除”按钮实际上只会使一些Border元素出现,其中包含消息和按钮,而Yes按钮实际上是删除了。

  3. 对于曾经使用MessageBox.Show()的几行代码,两种解决方案似乎都过于复杂

    您在哪些方面成功实施了MVVM应用程序中的对话框?

12 个答案:

答案 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;对话框并执行操作。在此示例中,SimpleCommandthis类似,但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解决方案,但由于它不使用代码并且更可重用,我认为它更优雅。

Check it out here

答案 7 :(得分:1)

WPF&amp; Silverlight MessageBoxes

MVVM支持

http://slwpfmessagebox.codeplex.com/

答案 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时使用它即可实现脆弱的抽象...这很好,具体取决于您将在哪里使用它。我的情况是一个简单的应用程序,仅意味着要做一些事情,因此设计解决方案毫无意义。希望这对某人有帮助。