C# 使用MVVM在WPF中创建新窗口的最佳方法
在邻居的帖子中: 我已经发布了如何使用MVVM关闭windows的设想。现在我有一个问题:如何打开它们 我有一个主窗口(主视图)。如果用户单击“显示”按钮,则应显示“演示”窗口(模式对话框)。使用MVVM模式创建和打开窗口的首选方法是什么?我认为有两种一般做法: 第一个(可能是最简单的)。事件处理程序“ShowButton\u Click”应以如下方式在主窗口的代码隐藏中实现:C# 使用MVVM在WPF中创建新窗口的最佳方法,c#,.net,wpf,mvvm,C#,.net,Wpf,Mvvm,在邻居的帖子中: 我已经发布了如何使用MVVM关闭windows的设想。现在我有一个问题:如何打开它们 我有一个主窗口(主视图)。如果用户单击“显示”按钮,则应显示“演示”窗口(模式对话框)。使用MVVM模式创建和打开窗口的首选方法是什么?我认为有两种一般做法: 第一个(可能是最简单的)。事件处理程序“ShowButton\u Click”应以如下方式在主窗口的代码隐藏中实现: private void ModifyButton_Click(object sender, Rout
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
}
}
- 将引发“ShowDialogEvent”李>
- 将管理按钮状态
((MainWindowViewModel)DataContext).ShowDialogEvent += ShowDialog;
class MainViewModel {
public MainViewModel(IView view, IModel model, IController controller) {
mModel = model;
mController = controller;
mView = view;
view.DataContext = this;
}
public ICommand ShowCommand = new DelegateCommand(o=> {
mResult = controller.GetSomeData(mSomeData);
});
}
class Controller : IController {
public void OpenMainView() {
IView view = new MainView();
new MainViewModel(view, somemodel, this);
}
public int GetSomeData(object anyKindOfData) {
ShowWindow wnd = new ShowWindow(anyKindOfData);
bool? res = wnd.ShowDialog();
...
}
}
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
}
(ShowDialog-类似于“ModifyButton_Click”方法。)
因此,我的问题是:
1.你看到其他的方法了吗?
2.你认为其中一个是好的还是坏的?(为什么?)
欢迎有其他想法
谢谢。我使用一个控制器来处理视图之间传递的所有信息。所有视图模型都使用控制器中的方法来请求更多信息,这些信息可以实现为对话框、其他视图等 它看起来像这样:
((MainWindowViewModel)DataContext).ShowDialogEvent += ShowDialog;
class MainViewModel {
public MainViewModel(IView view, IModel model, IController controller) {
mModel = model;
mController = controller;
mView = view;
view.DataContext = this;
}
public ICommand ShowCommand = new DelegateCommand(o=> {
mResult = controller.GetSomeData(mSomeData);
});
}
class Controller : IController {
public void OpenMainView() {
IView view = new MainView();
new MainViewModel(view, somemodel, this);
}
public int GetSomeData(object anyKindOfData) {
ShowWindow wnd = new ShowWindow(anyKindOfData);
bool? res = wnd.ShowDialog();
...
}
}
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
}
看看我目前的MVVM解决方案,它在Silverlight中显示模式对话框。 它解决了您提到的大多数问题,但它完全从特定于平台的事物中抽象出来,并且可以重用。此外,我没有使用任何代码隐藏,只与实现ICommand的DelegateCommand绑定。对话框基本上是一个视图-一个单独的控件,它有自己的ViewModel,从主屏幕的ViewModel显示,但通过DelagateCommand绑定从UI触发
请参见此处的完整Silverlight 4解决方案我的方法与adrianm类似。但是,在我的例子中,控制器从不使用具体的视图类型。控制器与视图完全解耦,方式与ViewModel相同 其工作原理可以在的ViewModel示例中看到 致以最良好的祝愿
jbe我最近也在考虑这个问题。如果您在项目中使用“容器”或任何依赖项注入,我有一个想法。我想通常你会覆盖App.OnStartup(),在那里创建模型、视图模型和视图,并为每个模型提供适当的引用。使用Unity,可以为容器提供对模型的引用,然后使用容器“解析”视图。Unity容器注入您的视图模型,因此您永远不会直接实例化它。解决视图后,可以对其调用
Show()
在我观看的一个示例视频中,Unity容器是在OnStartup
中作为局部变量创建的。如果在应用程序类中将其创建为公共静态只读属性,该怎么办?然后,您可以在主视图模型中使用它来创建新窗口,自动注入新视图所需的任何资源。类似于App.Container.Resolve().ShowDialog()的东西代码>
我想您可以在测试中模拟调用Unity容器的结果。或者,您可以在App类中编写类似于ShowMyChildView()
的方法,这基本上就是我上面描述的。模拟调用App.ShowMyChildView()
可能很容易,因为它只会返回一个bool?
,是吗
嗯,这可能并不比仅仅使用newmychildview()
好多少,但这是我的一个小主意。我想我会分享的 一些MVVM框架(例如)使用。
因此,要打开一个新窗口(或创建任何视图),一些视图特定的代码将订阅来自中介的消息,ViewModel将发送这些消息
像这样:
归属
Messenger.Default.Register<DialogMessage>(this, ProcessDialogMessage);
...
private void ProcessDialogMessage(DialogMessage message)
{
// Instantiate new view depending on the message details
}
我更喜欢在singleton类中进行订阅,它与应用程序的UI部分一样“存在”。
总而言之:ViewModel传递诸如“我需要创建视图”之类的消息,UI侦听这些消息并对其进行操作
当然,没有“理想”的方法。我有点晚了,但我发现现有的答案不够充分。我会解释原因。一般而言:
- 可以从视图访问ViewModels
- 从ViewModels访问视图是错误的,因为它引入了循环依赖关系,并且使得ViewModels难以测试
Benny Jobigan的回答:
现在,ViewModel没有与视图紧密耦合。然而,我发现为每个视图创建接口是不切实际的
阿科纳特的anwer:
这样更好。看起来Messenger或EventAggregator或其他发布/订阅模式是MVVM中所有内容的通用解决方案:)缺点是调试或导航到DialogMessageHandler
比较困难。这太间接了。例如,如何读取对话框中的输出?通过修改对话框消息
我的解决方案:
您可以按如下方式从MainWindowViewModel打开窗口:
((MainWindowViewModel)DataContext).ShowDialogEvent += ShowDialog;
class MainViewModel {
public MainViewModel(IView view, IModel model, IController controller) {
mModel = model;
mController = controller;
mView = view;
view.DataContext = this;
}
public ICommand ShowCommand = new DelegateCommand(o=> {
mResult = controller.GetSomeData(mSomeData);
});
}
class Controller : IController {
public void OpenMainView() {
IView view = new MainView();
new MainViewModel(view, somemodel, this);
}
public int GetSomeData(object anyKindOfData) {
ShowWindow wnd = new ShowWindow(anyKindOfData);
bool? res = wnd.ShowDialog();
...
}
}
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
}
DialogService只接受dialog的ViewModel,因此您的ViewModel完全独立于视图。在运行时,DialogService可以找到适当的视图(例如使用命名约定)并显示它,或者可以在单元测试中轻松模拟它
在我的情况下,我使用以下接口: