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

问题描述 投票:41回答:12

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

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

  1. 我可以收到一条短信,上面写着“你确定......?”以及我的XAML中的边框中的两个按钮是和否全部,并在模板上创建一个触发器,使其基于名为AreYourSureDialogueBoxIsVisible的ViewModelProperty折叠/可见,然后当我需要此对话框时,将AreYourSureDialogueBoxIsVisible指定为“true” “还可以通过我的ViewModel中的DelegateCommand处理这两个按钮。
  2. 我也可以尝试用XAML中的触发器来处理这个问题,这样删除按钮实际上只会使一些Border元素出现,其中包含消息和按钮,而Yes按钮实际上是删除了。

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

您在哪些方面成功实现了MVVM应用程序中的Dialogue Box?

wpf mvvm triggers messagebox
12个回答
5
投票

在你提到的两个中,我更喜欢选项#2。页面上的“删除”按钮只显示“确认删除对话框”。 “确认删除对话框”实际上启动了删除。

你看过Karl Shifflett的WPF Line Of Business Slides and Demos吗?我知道他做的是这样的。我会试着记住哪里。

编辑:查看演示#11“MVVM中的数据验证”(EditContactItemsControlSelectionViewModel.DeleteCommand)。 Karl从ViewModal调用一个弹出窗口(What!?:-)。我其实更喜欢你的想法。似乎更容易进行单元测试。


0
投票

我会把它从VM中抛出来。我不想使用别人的服务或只是写自己的邮箱。


0
投票

我最近遇到了这个问题,我不得不用一些完全MVVM投诉消息框机制替换ViewModels中的MessageBox.Show。

为了达到这个目的,我使用了PropertyChangedInteractionRequest<Notification>以及交互触发器,并为消息框编写了我自己的视图。

我实施的是发布InteractionRequest<Confirmation>


0
投票

关于此主题有很多答案,从创建自定义类到使用第三方库都有所不同。我想说如果你想要一个很好的视觉效果的酷炫弹出窗口,可以使用第三方库。

但是,如果您只是想使用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时使用它,并且使用一个脆弱的抽象来完成这个技巧......这很好,取决于你将使用它的位置。我的案例是一个简单的应用程序,只是为了做一些事情,所以没有必要设计一个解决方案。希望这有助于某人。


12
投票

救援服务。使用Onyx(免责声明,我是作者)这很简单:

public void Foo()
{
    IDisplayMessage dm = this.View.GetService<IDisplayMessage>();
    dm.Show("Hello, world!");
}

在正在运行的应用程序中,这将间接调用MessageBox.Show(“Hello,world!”)。在测试时,可以模拟IDisplayMessage服务并将其提供给ViewModel,以便在测试期间完成您想要完成的任务。


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)使用委托命令来显示“你确定吗?”对话框并执行操作。在这个例子中,它是一个类似于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
投票

我只是创建一个接口(IMessageDisplay或类似的),它被注入VM,它有像MessageBox(ShowMessage()等)的方法。你可以使用一个标准的消息框来实现它,或者更具体的WPF(我使用this one on CodePlex一些叫做Prajeesh的人)。

这样一切都是分开的和可测试的。


3
投票

如何在视图后面的代码中处理像qazxsw poi这样的事件(无论如何它只是查看代码,所以我没有看到在代码隐藏上使用此代码有任何问题)。


1
投票

我已经为我们制作了一个简单的MessageBox包装器控件,可以在纯MVVM解决方案中使用,并且仍然允许单元测试功能。详细信息在我的博客"MessageBoxRequested"


1
投票

我已经实现了一个侦听来自ViewModel的Message的Behavior。它基于Laurent Bugnion解决方案,但由于它不使用代码并且更可重用,我认为它更优雅。

http://geekswithblogs.net/mukapu/archive/2010/03/12/user-prompts-messagebox-with-mvvm.aspx


1
投票

WPF和Silverlight消息框

MVVM支持

Check it out here


1
投票

以防万一其他人仍在阅读和不满意:

我只是想处理'通知'类型的MessageBoxes(即我不关心http://slwpfmessagebox.codeplex.com/),但我遇到的大多数解决方案的问题是它们似乎间接强迫您选择View实现(也就是说,目前我有一个DialogResult,但如果我后来决定直接在我的视图中调整隐藏面板的可见性,那么它将与传入ViewModel的MessageBox.Show接口非常吻合。

所以我快速而又肮脏:

ViewModel有一个INotification属性,更改通知string NotificationMessage

View订阅PropertyChanged,如果它看到PropertyChanged属性通过,做它想要的任何东西。

好的,这意味着View具有代码隐藏功能,而NotificationMessage的名称是硬编码的,但无论如何它都会在XAML中进行硬编码。这意味着我避免了所有的东西,比如Visibility的转换器,以及说明通知是否仍然可见的属性。

(不可否认,这只是针对有限的用例(火灾和遗忘),我没有考虑过如何扩展它。)

© www.soinside.com 2019 - 2024. All rights reserved.