Подтвердить что ты не робот

Как перемещаться по окнам с помощью MVVM Light для WPF?

Я только что начал новый проект, в котором уровень представления будет выполнен WPF и MVVM Light от GalaSoft.

Мне нужно много просмотров, и мне не ясно, как управлять навигацией через окна.

Прежде всего, шаблоны, предлагаемые в MVVM Light для создания нового "WPF MVVM View", создают новый Window, который невозможно использовать для навигации по кадру (я имею в виду, поставив рамку в mainView и изменение пути источника для навигации).

Мне просто нужно изменить Window на Page для всех представлений, которые я создаю с помощью шаблонов?

Или существует другой способ выполнения навигации в WPF с помощью инструментария MVVM Light?

4b9b3361

Ответ 1

В конце концов я сделал это так.

Следуя идее o_q, я создал NavigationWindow в качестве MainWindow и изменил все представления на страницу.

Затем я создал интерфейс и класс, используя 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;
                }
            });

        }

Таким образом, я держу все viewModels "в неведении"... они ничего не знают о навигации, плюс у меня нет кода позади.

Если мне нужно перейти с помощью кнопки из вида, я могу разрешить NavigationService из подключенной модели представления и перейти на нужную мне страницу.

И, самое главное, это работает!

Ответ 2

Я обычно использую ContentControl для отображения динамического содержимого. Свойство Content обычно привязывается к свойству CurrentViewModel в родительском ViewModel, а DataTemplates используется, чтобы сообщить WPF, как рисовать дочерний элемент ViewModels.

Чтобы изменить представления, просто измените свойство CurrentViewModel в родительском ViewModel

Вы можете найти пример в в этой статье.

Ответ 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());
    }
}