你如何成功实现MVVM中的MessageBox.Show()function?
我有一个WPF应用程序调用MessageBox.Show()方式返回ViewModel (检查用户是否真的要删除)。 这实际上是有效的 ,但是与MVVM背道而驰,因为ViewModel不应该明确地确定View上会发生什么。
所以现在我想我怎么才能最好地实现我的MVVM应用程序,选项中的MessageBox.Show()function :
-
我可以有一个消息与文字“你确定…?” 在我的XAML中有两个buttonYes和No all,并在模板上创build一个触发器,使其基于名为AreYourSureDialogueBoxIsVisible的ViewModelProperty进行折叠/可见,然后在需要此对话框时,将AreYourSureDialogueBoxIsVisible分配为“true “,并通过DelegateCommand在ViewModel中处理两个button。
-
我也可以尝试在XAML中使用触发器来处理这个事情,这样Deletebutton实际上只是让一些Border元素出现在消息和button中,而Yesbutton却是实际删除的。
这两种解决scheme似乎都过于复杂,因为它们与MessageBox.Show()是一对代码。
您在MVVM应用程序中如何成功实施对话框?
你提到的两个,我更喜欢选项#2。 页面上的删除button只会使“确认删除对话框”出现。 “确认删除对话框”实际上启动了删除。
你有没有看过Karl Shifflett的WPF业务线和演示 ? 我知道他做了这样的事情。 我会尽力记住在哪里。
编辑:检查演示#11“MVVM中的数据validation”(EditContactItemsControlSelectionViewModel.DeleteCommand)。 Karl从ViewModal(What !? :-)调用一个popup窗口。 我其实更喜欢你的想法 似乎更容易unit testing。
救援服务。 使用Onyx (免责声明,我是作者)这是一样简单的:
public void Foo() { IDisplayMessage dm = this.View.GetService<IDisplayMessage>(); dm.Show("Hello, world!"); }
在运行的应用程序中,这将间接调用MessageBox.Show(“Hello,world!”)。 testing时,可以模拟IDisplayMessage服务并将其提供给ViewModel,以便在testing过程中完成您想要完成的任务。
现在扩展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)中,我们有一个button,在ViewModel中调用一个命令
<Button Command="{Binding Path=DeleteCommand}" />
视图模型(MainWindowViewModel.cs)使用委托命令来显示“你确定吗? 对话框并执行操作。 在这个例子中,它是一个类似于此的SimpleCommand
,但是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
那么在View的代码隐藏中处理像"MessageBoxRequested"
这样的事件(无论如何,它只是查看代码,所以我没有看到代码隐藏的代码有任何问题)。
我已经做了一个简单的MessageBox包装控件,使我们可以在纯MVVM解决scheme中使用,并仍然允许unit testingfunction。 细节在我的博客http://geekswithblogs.net/mukapu/archive/2010/03/12/user-prompts-messagebox-with-mvvm.aspx
mukapu
我只是创build一个接口(IMessageDisplay或类似),它被注入虚拟机,它有像MessageBox(ShowMessage()等)的方法。 你可以使用标准的消息框或者更多的WPF来实现它(我在CodePlex上使用了一个叫做Prajeesh的人)。
这样一切都是分离的和可testing的。
我已经实现了一个从ViewModel监听消息的行为。 它基于Laurent Bugnion解决scheme,但是由于它不使用代码并且更加可重用,我认为它更加优雅。
看看这里
以防其他人仍然阅读和不满意:
我只是想处理“通知”types的MessageBoxes(即我不关心DialogResult
),但我已经阅读了大多数解决scheme的问题是,他们似乎间接强迫你select你的视图实现(也就是说,目前我有一个MessageBox.Show
,但是如果我以后决定只是直接在我的视图中隐藏隐藏面板的可见性,那么不会很好地与传递给ViewModel的INotification
接口进行网格化)。
所以我去了快速和肮脏:
ViewModel具有string NotificationMessage
属性,通知PropertyChanged
更改。
视图订阅了PropertyChanged
,如果它看到NotificationMessage
属性通过,做任何想要的。
好的,所以这意味着View有代码隐藏, PropertyChanged
的名字是硬编码的,但是它在XAML中将被硬编码。 这意味着我避免了像可视化转换器这样的所有东西,还有属性来说明通知是否仍然可见。
(无可否认,这仅仅是一个有限的用例(火和遗忘),我没有多less想到如何扩展它。)
我只是把它从虚拟机。 我不想使用别人的服务或写我自己的只是扔一个消息框。
我最近遇到这个问题,我不得不用一些完全的MVVM投诉消息框机制来replaceViewModels中的MessageBox.Show。
为了实现这一点,我使用了InteractionRequest<Notification>
和InteractionRequest<Confirmation>
以及交互触发器,并为消息框写了自己的Views。
我已经实现了这里发布