在应用程序中管理多个WPF视图

4
我发现WPF中有一个导航服务可用于维护应用程序的流程。我不需要回退和前进功能,只是想要在按下特定视图上的按钮时切换视图的好方法。我正在使用MVVM,所以不确定是否可以让App.xaml.cs可能包含每个视图或ViewModel的副本,并让ViewModel命令调用App.xaml.cs进行切换。也许我应该只处理按钮的Click事件并执行某种形式的this.Close(); NewWindow.Show();。像WPF中的许多其他东西一样,这对我来说并不直观,尽管可能有几个简单的解决方案。
谢谢!

你是否使用了像Prism这样的应用程序框架?你是否使用了IoC或类似的东西?这将有助于决定一个方法。 - Anderson Imes
我正在尝试坚持MVVM模式,但这是一个独立的应用程序,有四个不同的窗口可以相互切换。 - Bob
2个回答

2
解决这个问题的一种方法是引入“控制器”(Controllers),它们负责应用程序的工作流程。它们在应用程序中创建、显示和关闭多个视图。
如何实现可以在WPF应用程序框架(WAF)项目的示例应用程序中看到。

由于其他原因,我不得不放弃窗口加载器,并实际上编写了一个静态控制器类,任何我的视图模型都可以订阅它,如果他们想在用户控件导航更改时执行某些操作。我的主窗口通过将各个用户控件的可见性绑定到DataTrigger中的CurrentNavigation属性来执行实际切换。 - Bob

2
我创建了一个"窗口加载器"类,当应用程序启动时,应用程序类实例化它。窗口加载器具有一个字典,维护视图模型类型和视图类型的关联。它还有一个方法,接受视图模型实例,根据视图模型的类型解析视图,实例化视图,设置视图的数据上下文为视图模型,然后显示它。窗口加载器还向视图模型注册一个事件,在窗口要关闭时引发该事件。
窗口加载器实现了IWindowLoader接口,每个视图模型都保留了对它的引用(当窗口加载器实例化视图模型时,它会将自己分配给视图模型中的公共IWindowLoader属性)。 因此,任何视图模型都可以使任何其他视图模型显示,而无需知道视图,也无需进行显示。同时,窗口加载器很容易被模拟测试。
当我经历与你类似的过程时,我找到了许多相同基本模式的示例。最终我自己实现了这个模式。

听起来很合理。我得到了窗口关闭的事件。你是如何连接调用以打开一个已注册类型的新窗口的?还有窗口加载器上的事件吗?你将要打开的类型作为字符串传递并让窗口加载器将其解析为类型吗? - Bob
打开新窗口:每个视图模型都有一个IWindowLoader属性。即使是主窗口的每个视图模型也是在应用程序类中由窗口加载器实例化的。因此,当窗口加载器创建视图模型时,它只需执行viewModel.WindowLoader = this。然后,viewModel1可以执行: ViewModel2 viewModel = new ViewModel2(); this.WindowLoader.Show(viewModel);然后,窗口加载器Show方法在字典中查找typeof(viewModel),并使用Activator实例化视图,将两者配对,注册关闭事件并执行window.Show()。 - Mark Bostleman
小修正:窗口加载器查找的是viewModel.GetType(),而不是typeof(viewModel)。此外,与我的原始答案相反,我的窗口加载器Show方法不是使用要显示的视图模型类型,而是使用其实例。这样做的原因是我喜欢让我的“父”视图模型实例化自己的子视图模型,以便它们可以设置属性并进行任何其他必要的准备工作,然后再传递给窗口加载器。 - Mark Bostleman
其实我差不多懂了。WindowLoader中的CloseWindow事件需要什么参数?我无法弄清如何将要关闭的窗口实例的引用传回WindowLoader,除非它应该以某种方式保留所有打开的窗口的副本? - Bob
窗口加载器不会维护对打开窗口的引用。相反,它会在显示窗口之前向其所给定的视图模型实例中的EventHandler添加一个委托。代码如下:viewModel.RequestClose += delegate(object sender, EventArgs e) { window.Close(); }; - Mark Bostleman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接