如何使用 MVVM Light for WPF 在窗口中导航?
Posted
技术标签:
【中文标题】如何使用 MVVM Light for WPF 在窗口中导航?【英文标题】:How to navigate through windows with MVVM Light for WPF? 【发布时间】:2012-03-06 14:39:40 【问题描述】:我刚刚开始了一个新项目,其中表示层将由 WPF 完成,MVVM Light 由 GalaSoft 完成。
我需要很多视图,但我不清楚如何通过窗口管理导航。
首先,MVVM Light 中提供的用于创建新“WPF MVVM 视图”的模板会创建一个新的 Window
,它不能用于逐帧导航(我的意思是,通过在 mainView
中放置一个框架)并更改要导航的源路径)。
对于我使用模板创建的所有视图,我是否只需将Window
更改为Page
?
或者是否有其他方法可以使用 MVVM Light 工具包在 WPF 中执行导航?
【问题讨论】:
【参考方案1】:我通常使用ContentControl
来显示动态内容。它的Content
属性通常绑定到父ViewModel
中的CurrentViewModel
属性,而DataTemplates
用于告诉WPF 如何绘制子ViewModels
。
要更改视图,只需更改父 ViewModel
中的 CurrentViewModel
属性
你可以在this article of mine找到一个例子
【讨论】:
嗨,Rachel,如果您可以在链接之外发布一个如何实现此功能的最小示例,那就太好了。它只是帮助像我这样的人在 5 年后得到这个答案,以防链接由于任何特定原因不再有效 @Ortund this SO answer 有帮助吗?我写这个答案已经有一段时间了,但我认为其他答案的代码应该是一个合适的例子。【参考方案2】:最终我是这样做的。
按照 o_q 的思路,我将 NavigationWindow 创建为 MainWindow,并将所有视图更改为 page。
然后,我创建了一个使用 Navigation 的接口和一个类:
public interface INavigationService
event NavigatingCancelEventHandler Navigating;
void NavigateTo(Uri pageUri);
void GoBack();
public class NavigationService : INavigationService
private NavigationWindow _mainFrame;
#region Implementation of INavigationService
public event NavigatingCancelEventHandler Navigating;
public void NavigateTo(Uri pageUri)
if (EnsureMainFrame())
_mainFrame.Navigate(pageUri);
public void GoBack()
if (EnsureMainFrame()
&& _mainFrame.CanGoBack)
_mainFrame.GoBack();
#endregion
private bool EnsureMainFrame()
if (_mainFrame != null)
return true;
_mainFrame = System.Windows.Application.Current.MainWindow as NavigationWindow;
if (_mainFrame != null)
// Could be null if the app runs inside a design tool
_mainFrame.Navigating += (s, e) =>
if (Navigating != null)
Navigating(s, e);
;
return true;
return false;
然后,在 viewModelLocator 中,我创建了所有用于存储视图路径的 const 字符串:
public class ViewModelLocator
#region Views Paths
public const string FrontendViewPath = "../Views/FrontendView.xaml";
public const string BackendViewPath = "../Views/BackendView.xaml";
public const string StartUpViewPath = "../Views/StartUpView.xaml";
public const string LoginViewPath = "../Views/LoginView.xaml";
public const string OutOfOrderViewPath = "../Views/OutOfOrderView.xaml";
public const string OperativeViewPath = "../Views/SubViews/OperativeView.xaml";
public const string ConfigurationViewPath = "../Views/SubViews/ConfigurationView.xaml";
#endregion
在 App.cs 的 Application_Startup 事件处理程序中,在 Unity IoC 的帮助下,我注册了一个 NavigationService 的单例:
public partial class App : System.Windows.Application
private static IUnityContainer _ambientContainer;
public static IServiceLocator AmbientLocator get; private set;
...
private void Application_Startup(object sender, System.Windows.StartupEventArgs e)
_ambientContainer =
new UnityContainer();
_ambientContainer.RegisterType<INavigationService, NavigationService>(new ContainerControlledLifetimeManager());
AmbientLocator = new UnityServiceLocator(_ambientContainer);
ServiceLocator.SetLocatorProvider(() => AmbientLocator);
现在,在我的 ViewModelLocator 中,我可以注册一个“Galasoft”消息来捕获所有事件并导航到一个页面;在我的构造函数中:
public ViewModelLocator()
CreateMain();
CreateFrontend();
CreateBackend();
CreateStartUp();
CreateOperative();
CreateLogin();
CreateConfiguration();
CreateOutOfOrder();
// Set Startup Page...
ServiceLocator.Current.GetInstance<INavigationService>().NavigateTo(new Uri(StartUpViewPath, UriKind.Relative));
Messenger.Default.Register<MoveToViewMessage>(this, message =>
switch (message.StateInfo.StateType)
case StateType.StartUpState:
ServiceLocator.Current.GetInstance<INavigationService>().NavigateTo(new Uri(StartUpViewPath,UriKind.Relative));
break;
case StateType.LoginState:
ServiceLocator.Current.GetInstance<INavigationService>().NavigateTo(new Uri(LoginViewPath, UriKind.Relative));
break;
case StateType.OperativeState:
ServiceLocator.Current.GetInstance<INavigationService>().NavigateTo(new Uri(OperativeViewPath, UriKind.Relative));
break;
case StateType.ConfigurationState:
ServiceLocator.Current.GetInstance<INavigationService>().NavigateTo(new Uri(ConfigurationViewPath, UriKind.Relative));
break;
case StateType.ClosedState:
case StateType.OutOfOrderState:
ServiceLocator.Current.GetInstance<INavigationService>().NavigateTo(new Uri(OutOfOrderViewPath, UriKind.Relative));
break;
default:
ServiceLocator.Current.GetInstance<INavigationService>().NavigateTo(new Uri(StartUpViewPath, UriKind.Relative));
break;
);
通过这种方式,我让所有的 viewModel 保持“无知”......他们对导航一无所知,而且我没有代码。
如果我需要使用视图中的按钮进行导航,我可以从连接的 viewModel 解析 NavigationService 并导航到我需要的页面。
而且,最重要的是,它有效!
【讨论】:
我注意到 ViewModelLocator 构造函数在您的示例中不是静态的,但在默认实现中它是静态的...【参考方案3】:对于可导航的应用程序,您会希望您的启动视图是 NavigationWindow
而不是 Window
<NavigationWindow
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="MainWindow"
Title="My Application Title"
Height="300"
Width="400" />
后面的代码:
using System.Windows.Navigation;
public partial class MainWindow : NavigationWindow
public MainWindow()
InitializeComponent();
MVVM Light 视图模板使用Window
,但正如您所猜测的,您可以更改它。如果您希望能够在此视图之间导航,请将其设为Page
。
这就是您导航的方式:
<Page
x:Class="Page1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Page1">
<Grid>
<!-- this button will navigate to another page -->
<Button
Content="Go to Page 2"
Click="Button_Click" />
</Grid>
</Page>
代码背后:
using System.Windows;
using System.Windows.Controls;
public partial class Page1 : Page
public Page1()
InitializeComponent();
private void Button_Click(object sender, RoutedEventArgs e)
// the Page class has a property "NavigationService" which allows you to navigate.
// you can supply the "Navigate" method with a Uri or an object instance of the page
base.NavigationService.Navigate(new Page2());
【讨论】:
这可能是一种可能性,即使我不喜欢将代码放在代码后面。此外,我忘了告诉你,我的应用程序将成为自动售货机的人机界面,因此能够以更简单的方式浏览页面对我来说至关重要,例如通过从较低层发送事件(用户无法与表示层交互,因为没有鼠标、没有触摸屏、没有键盘等等。)。是否可以通过这种方式从 ViewModel 导航页面? @zero51 关于在视图模型中导航的问题,我在这里发布了解决方案:How to navigate from one view to another view from viewmodel in silverlight? 我在 Galasoft 网站 link 找到了这篇文章。它解释了如何在 Windows phone 7 中实现导航...我将尝试在 WPF 中使用导航实现它。 @Zero51:你有没有解决这个问题。我也在寻找一个例子,但一直无法这样做? @user101010101:我实现了导航,正如我在回答中解释的那样。它就像一个魅力!以上是关于如何使用 MVVM Light for WPF 在窗口中导航?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 MVVM Light Toolkit 打开一个新窗口