46

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

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

  1. 我可以收到一条带有文本“你确定...?”的消息。连同两个按钮 Yes 和 No all 在我的 XAML 中的 Border 中,并在模板上创建一个触发器,以便它基于名为AreYourSureDialogueBoxIsVisible的 ViewModelProperty 折叠/可见,然后当我需要此对话框时,将 AreYourSureDialogueBoxIsVisible 分配给“true ",并且还通过我的 ViewModel 中的 DelegateCommand 处理这两个按钮。

  2. 我还可以尝试使用 XAML 中的触发器来处理此问题,以便删除按钮实际上只是使某些 Border 元素出现,其中包含消息和按钮,而 Yes 按钮执行实际删除操作。

对于过去使用 MessageBox.Show() 的几行代码来说,这两种解决方案似乎都太复杂了。

您通过哪些方式在 MVVM 应用程序中成功实现了对话框?

4

13 回答 13

14

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

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

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

于 2009-07-09T14:49:09.163 回答
5

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

您是否查看过 Karl Shifflett 的WPF 业务线幻灯片和演示?我知道他会做这样的事情。我会试着记住在哪里。

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

于 2009-07-08T13:27:57.973 回答
5

既然他的链接是 kaput,就扩展 Dean Chalk 的答案:

在 App.xaml.cs 文件中,我们将确认对话框连接到视图模型。

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}" />

视图模型 (MainWindowViewModel.cs) 使用委托命令来显示“您确定吗?” 对话框并执行操作。在此示例中,它与thisSimpleCommand类似,但 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
于 2015-07-17T08:12:19.860 回答
4

我只是创建了一个接口(IMessageDisplay 或类似的),它被注入到 VM 中,它具有像 MessageBox(ShowMessage() 等)这样的方法。您可以使用标准消息框或更具体的 WPF 来实现它(我在Prajeesh的 CodePlex 上使用了这个)。

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

于 2010-07-16T08:38:43.460 回答
3

"MessageBoxRequested"在 View 的代码隐藏中引发类似处理的事件怎么样?

于 2012-09-26T18:36:01.187 回答
3

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

我只是想处理“通知”类型的 MessageBoxes(即我不关心DialogResult),但我读过的大多数解决方案的问题是它们似乎间接地迫使你选择你的 View 实现(即是,目前我MessageBox.ShowINotification,但如果我后来决定直接在我的视图中摆弄隐藏面板的可见性,那将不会与传入 ViewModel

所以我又快又脏:

ViewModel 有一个string NotificationMessage属性,更改通知到PropertyChanged.

View 订阅PropertyChanged,如果它看到NotificationMessage属性通过,就做它想做的任何事情。

好的,这意味着视图有代码隐藏,并且名称PropertyChanged是硬编码的,但无论如何它都会在 XAML 中硬编码。这意味着我避免了所有的东西,比如可见性转换器,以及说明通知是否仍然可见的属性。

(诚​​然,这仅适用于有限的用例(即发即弃),我没有考虑过如何扩展它。)

于 2013-04-30T09:39:45.390 回答
2

关于这个主题有很多答案,从创建自定义类到使用第三方库。如果您想要具有漂亮视觉效果的酷炫弹出窗口,我会说使用第三方库。

但是,如果您只想为您的 WPF 应用程序使用微软的常规消息框,这里是一个 MVVM/单元测试友好的实现:

最初我以为我会从消息框继承并用接口包装它,但由于消息框没有公共构造函数,我不能,所以这里是“简单”的解决方案:

在visual studio中反编译消息框,你可以看到所有的方法重载,我检查了我想要的,然后创建了一个新类并添加了方法,用接口和ta-da包装了它!现在您可以使用ninject绑定接口和类,注入它并使用Moq进行单元测试等

创建一个接口(只添加了一些重载,因为我不需要全部):

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);
        }
    }

现在只需在注入等时使用它,然后繁荣你有一个脆弱的抽象可以解决问题......这很好,取决于你将在哪里使用它。我的案例是一个简单的应用程序,只打算做一些事情,所以没有必要设计一个解决方案。希望这可以帮助某人。

于 2018-09-17T15:18:33.180 回答
1

WPF 和 Silverlight 消息框

支持 MVVM

http://slwpfmessagebox.codeplex.com/

于 2011-07-16T18:48:47.223 回答
1

我制作了一个简单的 MessageBox 包装器控件,供我们在纯 MVVM 解决方案中使用,并且仍然允许单元测试功能。详情在我的博客http://geekswithblogs.net/mukapu/archive/2010/03/12/user-prompts-messagebox-with-mvvm.aspx

穆卡普

于 2010-03-11T21:24:41.050 回答
0

我只是将它从虚拟机中扔掉。我不想不得不使用别人的服务或编写自己的服务只是为了抛出一个消息框。

于 2009-07-16T16:09:16.007 回答
0

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

在这里查看

断开链接的缓存

于 2011-02-06T17:49:29.433 回答
0

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

为了实现这一点,我使用了交互触发器,并为消息框编写了我自己的视图InteractionRequest<Notification>InteractionRequest<Confirmation>

我实施的内容在这里发布

于 2014-09-09T10:56:11.693 回答
0

工作正常 [MVVM]

if (System.Windows.MessageBox.Show("Are you need to delete?", "", 
   System.Windows.MessageBoxButton.YesNo) == System.Windows.MessageBoxResult.Yes)
{
    // Do your action
}
于 2021-12-12T21:19:26.087 回答