如何用MVVM Light for WPF在窗口中导航?[英] How to navigate through windows with MVVM Light for WPF?

本文是小编为大家收集整理的关于如何用MVVM Light for WPF在窗口中导航?的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

我刚刚启动了一个新项目,其中的演示层将由WPF和 mvvm light Galasoft. p>

我需要很多视图,我不清楚如何通过Windows管理导航.

首先,在MVVM Light中提供的模板用于创建新的" WPF MVVM视图"创建一个新的Window,不可能通过框架进行导航(我的意思是,通过将框架放入mainView>>>>并更改导航的源路径).

我是否只需要将Window更改为Page对于我使用模板创建的所有视图?

或使用MVVM Light工具包在WPF中执行导航的方法?

推荐答案

最终我这样做了.

遵循O_Q的想法,我创建了NavigationWindow作为MainWindow,并将所有视图更改为页面.

然后,我创建了一个使用导航:

的Inteface和一个类
    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;
        }

    }

然后,在ViewModelocator中,我创建了所有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);

现在,在我的ViewModelocator中,我可以注册一条" 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;
                }
            });

        }

以这种方式,我将所有ViewModels保持"无知" ...他们对导航一无所知,而且我没有后面的代码.

如果我需要使用从视图中的按钮导航,我可以从连接的ViewModel解决Navigationservice并导航到我需要的页面.

,最重要的是,它有效!

其他推荐答案

我通常使用ContentControl显示动态内容.它是Content属性通常与父ViewModel中的CurrentViewModel属性约束,并且DataTemplates用于告诉WPF如何绘制孩子ViewModels.

要更改视图,只需更改父CurrentViewModel ViewModel

中的属性

您可以在上找到一个示例/a>

其他推荐答案

对于可通道的应用程序,您将希望启动视图为NavigationWindow而不是NavigationWindow

<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 View模板使用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());
    }
}

本文地址:https://www.itbaoku.cn/post/627747.html

问题描述

I've just started a new project in which the presentation layer will be done by WPF and MVVM Light by GalaSoft.

I need a lot of views and it's not clear to me how to manage navigation through 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).

Do I simply have to change Window to Page for all the views I create using templates?

Or is there a different way to perform navigation in WPF with the MVVM Light toolkit?

推荐答案

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.

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:

    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:

    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:

        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.

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.

And, most important thing, it works!

其他推荐答案

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.

To change views, simply change the CurrentViewModel property in the parent ViewModel

You can find an example at this article of mine

其他推荐答案

For a navigable application, you'll want your start up view to be a NavigationWindow instead of a 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:

<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());
    }
}