2009-11-26 80 views
9

我有一个应用程序需要从用户输入某些信息的按钮打开一个对话框。WPF MVVM中的打开对话框

在我不喜欢这样的时刻(工作正常)

  • 点击该按钮生成视图模型的命令。
  • ViewModel引发Controller侦听的事件。
  • 该控制器采用了新窗口的细节(即查看,视图模型&模型)并打开它(的ShowDialog)
  • 当窗口关闭时,控制器将结果以EventArgs的并返回到视图模型
  • ViewModel将信息传递给模型。

有很多步骤,但他们都有道理,没有太多的打字。

的代码看起来是这样的(窗口询问用户名)

视图模型:

AskUserNameCommand = DelegateCommand(AskUserNameExecute); 
... 

public event EventHandler<AskUserEventArgs> AskUserName; 

void AskUserNameExecute(object arg) { 
    var e = new AskUserNameEventArgs(); 
    AskUserName(this, e); 
    mModel.SetUserName(e.UserName); 
} 

控制器:

mViewModel.AskUserName += (sender,e) => { 
    var view = container.Resolve<IAskUserNameView>(); 
    var model = container.Resolve<IAskUserNameModel>(); 
    var viewmodel = container.Resolve<IAskUserNameViewModel>(view, model); 
    if (dlg.ShowDialog() ?? false) 
     e.UserName = model.UserName; 
} 

我的问题是横向沟通中是如何工作的MVVM模式。 不知怎的,让控制器参与模型之间的数据传输似乎是错误的。

我已经看过介体模式让模型直接进行通信。不喜欢这个想法,因为它使得模型取决于GUI的实现细节。 (即如果对话框被替换为文本框,则该模型需要改变)

+1

难道你看看下面的问题HTTP://stackoverflow.com/questions/454868/handling-dialogs-in-wpf-with-mvvm http://stackoverflow.com/questions/ 1667888/wpf-mvvm-dialog-example http:// stackoverflow。com/questions/1792814/using-mvvm-foundation-messenger-to-show-dialog – Guge 2009-11-26 23:01:15

+0

是的,我看着他们,但他们都推荐一个广播模式来解决实例的实例。 – adrianm 2009-11-27 09:33:00

+0

'点击按钮在ViewModel中生成一个命令',这是什么意思? 'ViewModel引发了一个Controller监听的事件',什么控制器?! – 2016-12-29 09:42:59

回答

0

我遇到过类似的问题。以下是我如何解决这些问题,以及为什么我已经完成了我所做的工作。

我的解决办法:

我MainWindowViewModel有型ModalViewModelBase称为模态的属性。 如果我的代码需要某个视图为模态,它将在此属性中引用它。 MainWindowView通过INotifyPropertyChanged机制监视这个属性。如果将Modal设置为某个虚拟机,则MainWindowView类将把该虚拟机放入一个ModalView窗口,在该窗口中将通过DataTemplates的魔术显示相应的UserControl,该窗口将使用ShowDialog显示。 ModalViewModelBase有一个DialogResult属性和一个名为IsFinished的属性。当模态虚拟机将IsFinished设置为true时,视图关闭。

我也有一些特殊的技巧来从背景工作者线程中做这样的交互式的事情,想要问用户输入。

我的理由:

的模态意见的原则是,其他的意见被禁用,同时显示的模式。这是View基本上看起来不可思议的逻辑的一部分。这就是为什么我在MainWindowViewModel中有一个属性。我要进一步考虑,我应该让所有其他虚拟机在主虚拟机上的其他属性或命令抛出异常,而在模式模式下,但我觉得这太过分了。

实际上拒绝用户执行任何其他操作的视图机制不必使用弹出窗口和sho​​wdialog来执行,它可能是您将模式视图置于现有窗口中,但会禁用所有其他操作,或者禁用所有其他操作其他的东西。这个视图相关的逻辑属于视图本身。 (一个典型的设计师不能编码这个逻辑,似乎是一个次要的问题,我们都需要一些帮助。)

所以我就是这么做的。我只是提出这个建议,可能还有其他的想法,我希望你也能得到更多的答复。

+0

这是一个有趣的方式,但我没有说数据传输是如何工作的。对话框关闭时用户输入如何从对话框(视图)模型获取到主要(视图)模型? – adrianm 2009-11-27 09:39:54

+0

关闭对话框视图后,MainViewModel仍然具有对DialogViewModel的引用。 – Guge 2009-11-27 15:11:35

+0

好的,这跟我一样或多或少是一样的,但是你在视图模型中这样做。 – adrianm 2009-11-27 16:26:42

0

我在Prism v2中使用EventAggregator类似的情况。关于prim函数的好处是,您不必在MVVM应用程序中使用整个框架。您可以提取EventAggregator功能,并将其与当前设置一起使用。

+0

EventAggregator不错,但它是一个广播服务。我找不到一个简单的方法来配置它来调用监听器的特定实例。假设用户打开对话框,将其关闭并再次打开。我现在有两个view/viewmodel/model实例,它们监听事件,直到GC开始清理。 如果侦听器取消订阅事件,但是会导致ViewModel/Model中出现某种IDisposable模式,则可以解决此问题。 – adrianm 2009-11-27 09:24:30

+0

@adrianm你是对的。如果您希望将消息传递到特定实例,则Event Aggregator不适用。 – 2009-12-09 15:39:22

12

我最不喜欢的一个原因或其他当前的建议,所以我想我会链接到一个几乎相同的问题的答案我,如:

Open File Dialog MVVM

具体卡梅伦麦克法兰答案就是我做的。通过接口提供的服务提供IO和/或用户交互是要走的路在这里,有以下原因

  • 它是可测试
  • 它抽象了实施的任何对话,以便您可以更改处理这些类型的东西的策略,而不会影响组成代码
  • 不依赖任何通信模式。你看到的很多建议都依赖于中介,如事件聚合器。这些解决方案依赖于与调解员另一方的合作伙伴进行双向沟通,这种方式既难以实施,又非常松散。
  • ViewModels保持自治。我和你一样,感觉控制器和ViewModel之间的沟通不太合适。如果没有其他原因使ViewModel变得易于测试,ViewModel应该保持自治。

希望这会有所帮助。

+0

谢谢,这让我想到了。我不想将ioc-container注入到viewmodel中,所以我可能会创建一些视图模型可以调用的IControllerService。将比我现在得到的基于事件的沟通更清洁。 – adrianm 2009-11-30 07:08:39

+0

如果您使用的是IoC,我只会声明像您的IDialogService这样的依赖项。我通常认为IoC是所有组成对象可用的服务目录。 – 2009-12-01 15:15:19

2

我使用this方法与mvvm进行对话。

所有我现在要做的就是从我的viewmodel中调用以下内容来处理对话框。

var result = this.uiDialogService.ShowDialog("Dialogwindow title goes here", dialogwindowVM);