如何使用 MVVM Light for WPF 浏览窗口?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9290269/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to navigate through windows with MVVM Light for WPF?
提问by zero51
I've just started a new project in which the presentation layer will be done by WPF and MVVM Lightby GalaSoft.
我刚刚开始了一个新项目,其中表示层将由GalaSoft 的WPF 和MVVM Light完成。
I need a lot of views and it's not clear to me how to manage navigation through windows.
我需要很多视图,但我不清楚如何通过 Windows 管理导航。
First of all, the templates offered in MVVM Light for creating a new "WPF MVVM View" create a new Window
that is not possible to use for navigation by frame (I mean, by putting a frame in mainView
and changing the source path to navigate).
首先,MVVM Light 中提供的用于创建新“WPF MVVM 视图”的模板创建了一个Window
不能用于逐帧导航的新模板(我的意思是,通过放入一个框架mainView
并更改要导航的源路径)。
Do I simply have to change Window
to Page
for all the views I create using templates?
难道我只是必须改变Window
,以Page
我为人人采用范本的意见?
Or is there a different way to perform navigation in WPF with the MVVM Light toolkit?
或者是否有不同的方式使用 MVVM Light 工具包在 WPF 中执行导航?
采纳答案by zero51
Eventually I did it this way.
最后我是这样做的。
Following the idea of o_q, I created NavigationWindow as MainWindow and changed all the the views to page.
按照 o_q 的想法,我将 NavigationWindow 创建为 MainWindow 并将所有视图更改为页面。
Then, I created an inteface and a class which using 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;
}
}
Then, in viewModelLocator I created all the const string nedded to store the paths to my views:
然后,在 viewModelLocator 中,我创建了所有用于存储视图路径的常量字符串:
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
}
In App.cs, in the Application_Startup event handler, with the help of Unity IoC I registered a singleton of NavigationService:
在 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);
Now, in my ViewModelLocator, I can register a "Galasoft" message to catch all the events and navigate to a page; in the constructor I have:
现在,在我的 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;
}
});
}
In this way I keep all the viewModels "ignorant"... they don't know anything about navigation, plus I don't have code behind.
通过这种方式,我让所有的 viewModels 保持“无知”......他们对导航一无所知,而且我没有背后的代码。
If I need to navigate by using a button from a view I can resolve NavigationService from the connected viewModel and navigate to the Page I need.
如果我需要使用视图中的按钮进行导航,我可以从连接的 viewModel 解析 NavigationService 并导航到我需要的页面。
And, most important thing, it works!
而且,最重要的是,它有效!
回答by Rachel
I usually use a ContentControl
to display dynamic content. It's Content
property is usually bound to a CurrentViewModel
property in the parent ViewModel
, and DataTemplates
are used to tell WPF how to draw the child ViewModels
.
我通常使用 aContentControl
来显示动态内容。它的Content
财产通常被绑定到一个CurrentViewModel
在parent属性ViewModel
,并DataTemplates
用来告诉WPF如何绘制孩子ViewModels
。
To change views, simply change the CurrentViewModel
property in the parent ViewModel
要更改视图,只需更改CurrentViewModel
父级中的属性ViewModel
You can find an example at this article of mine
你可以在我的这篇文章中找到一个例子
回答by o_q
For a navigable application, you'll want your start up view to be a NavigationWindow
instead of a Window
对于一个可导航的应用程序,你会希望你的启动视图是一个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" />
Code behind:
后面的代码:
using System.Windows.Navigation;
public partial class MainWindow : NavigationWindow
{
public MainWindow()
{
InitializeComponent();
}
}
The MVVM Light view templates use Window
, but as you have guessed, you can just change it. If you want to be able to navigate to and from this view, make it a Page
.
This is how you navigate:
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>
Code Behind:
背后的代码:
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());
}
}