在邻居帖子中:ViewModel应如何关闭表单? 我发布了如何使用MVVM关闭Windows的愿景.现在我有一个问题:如何打开它们.
我有一个主窗口(主视图).如果用户单击"显示"按钮,则应显示"演示"窗口(模态对话框).使用MVVM模式创建和打开窗口的首选方法是什么?我看到两种一般方法:
第一个(可能是最简单的).事件处理程序"ShowButton_Click"应该在主窗口的代码中实现,方式如下:
private void ModifyButton_Click(object sender, RoutedEventArgs e)
{
ShowWindow wnd = new ShowWindow(anyKindOfData);
bool? res = wnd.ShowDialog();
if (res != null && res.Value)
{
// ... store changes if neecssary
}
}
Run Code Online (Sandbox Code Playgroud)
另一种方法:
在MainWindowViewModel中,我们将实现"ShowCommand"属性,该属性将返回命令的ICommand接口.Comman反过来:
这种方法将更适合MVVM,但需要额外的编码:ViewModel类不能"显示对话框",因此MainWindowViewModel只会引发"ShowDialogEvent",MainWindowView我们需要在其MainWindow_Loaded方法中添加事件处理程序,这样的事情:
((MainWindowViewModel)DataContext).ShowDialogEvent += ShowDialog;
Run Code Online (Sandbox Code Playgroud)
(ShowDialog - 类似于'ModifyButton_Click'方法.)
所以我的问题是:1.你看到其他任何方法吗?你认为其中一个是好还是坏?(为什么?)
欢迎任何其他想法.
谢谢.
arc*_*aut 17
一些MVVM框架(例如MVVM Light)使用Mediator模式.因此,要打开一个新窗口(或创建任何View),一些特定于View的代码将订阅来自中介的消息,ViewModel将发送这些消息.
像这样:
Subsription
Messenger.Default.Register<DialogMessage>(this, ProcessDialogMessage);
...
private void ProcessDialogMessage(DialogMessage message)
{
// Instantiate new view depending on the message details
}
Run Code Online (Sandbox Code Playgroud)
在ViewModel中
Messenger.Default.Send(new DialogMessage(...));
Run Code Online (Sandbox Code Playgroud)
我更喜欢在单例类中进行订阅,只要应用程序的UI部分可以"生存".总结一下:ViewModel传递"我需要创建视图"之类的消息,UI会监听这些消息并对其进行操作.
当然,没有"理想"的方法.
Ben*_*gan 16
我最近也在考虑这个问题.如果你在你的项目中使用Unity作为"容器"或依赖注入的任何东西,我有一个想法.我想通常你会覆盖App.OnStartup()
并创建你的模型,视图模型,并在那里查看,并给每个人提供适当的参考.使用Unity,您可以为容器提供对模型的引用,然后使用容器"解析"视图.Unity容器会注入您的视图模型,因此您永远不会直接实例化它.一旦您的视图得到解决,您Show()
就可以调用它.
在我观看的一个示例视频中,Unity容器被创建为一个局部变量OnStartup
.如果您在App类中将其创建为公共静态只读属性,该怎么办?然后,您可以在主视图模型中使用它来创建新窗口,自动注入新视图所需的任何资源.有点像App.Container.Resolve<MyChildView>().ShowDialog();
.
我想你可以在测试中以某种方式模拟调用Unity容器的结果.或者,也许您可以编写ShowMyChildView()
App类中的方法,这基本上就像我上面描述的那样.可能很容易模拟一个调用,App.ShowMyChildView()
因为它只会返回一个bool?
,是吗?
嗯,这可能不仅仅比使用更好new MyChildView()
,但这是我的一个小想法.我以为我会分享它.=)
我来晚了,但是我发现现有答案还不够。我将解释原因。一般来说:
App.Container.Resolve<MyChildView>().ShowDialog();
Run Code Online (Sandbox Code Playgroud)
这实际上并不能解决任何问题。您正在以一种淡淡的耦合方式从ViewModel访问View。唯一的区别new MyChildView().ShowDialog()
是您经过了间接层。与直接调用MyChildView ctor相比,我没有任何优势。
如果为视图使用界面,它将更加干净:
App.Container.Resolve<IMyChildView>().ShowDialog();`
Run Code Online (Sandbox Code Playgroud)
现在,ViewModel不再与视图淡化耦合。但是,我发现为每个视图创建界面都是不切实际的。
Messenger.Default.Send(new DialogMessage(...));
Run Code Online (Sandbox Code Playgroud)
更好 Messenger或EventAggregator或其他发布/订阅模式似乎是MVVM中所有内容的通用解决方案:)缺点是调试或导航到它比较困难DialogMessageHandler
。这太间接了,恕我直言。例如,您将如何读取对话框的输出?通过修改DialogMessage?
您可以从MainWindowViewModel打开窗口,如下所示:
var childWindowViewModel = new MyChildWindowViewModel(); //you can set parameters here if necessary
var dialogResult = DialogService.ShowModal(childWindowViewModel);
if (dialogResult == true) {
//you can read user input from childWindowViewModel
}
Run Code Online (Sandbox Code Playgroud)
DialogService只接受对话框的ViewModel,因此您的ViewModel完全独立于View。在运行时,DialogService可以找到适当的视图(例如,使用命名约定)并显示它,或者可以在单元测试中轻松地对其进行模拟。
就我而言,我使用以下接口:
interface IDialogService
{
void Show(IDialogViewModel dialog);
void Close(IDialogViewModel dialog);
bool? ShowModal(IDialogViewModel dialog);
MessageBoxResult ShowMessageBox(string message, string caption = null, MessageBoxImage icon = MessageBoxImage.No...);
}
interface IDialogViewModel
{
string Caption {get;}
IEnumerable<DialogButton> Buttons {get;}
}
Run Code Online (Sandbox Code Playgroud)
其中DialogButton指定DialogResult或ICommand或两者。
归档时间: |
|
查看次数: |
50594 次 |
最近记录: |