如何使用 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 23:18:04  来源:igfitidea点击:

How to navigate through windows with MVVM Light for WPF?

wpfdesign-patternsmvvmmvvm-light

提问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 Windowthat is not possible to use for navigation by frame (I mean, by putting a frame in mainViewand changing the source path to navigate).

首先,MVVM Light 中提供的用于创建新“WPF MVVM 视图”的模板创建了一个Window不能用于逐帧导航的新模板(我的意思是,通过放入一个框架mainView并更改要导航的源路径)。

Do I simply have to change Windowto Pagefor 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 ContentControlto display dynamic content. It's Contentproperty is usually bound to a CurrentViewModelproperty in the parent ViewModel, and DataTemplatesare used to tell WPF how to draw the child ViewModels.

我通常使用 aContentControl来显示动态内容。它的Content财产通常被绑定到一个CurrentViewModel在parent属性ViewModel,并DataTemplates用来告诉WPF如何绘制孩子ViewModels

To change views, simply change the CurrentViewModelproperty 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 NavigationWindowinstead 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());
    }
}