Как перемещаться по окнам с MVVM Light для WPF? - PullRequest
18 голосов
/ 15 февраля 2012

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

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

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

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

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

Ответы [ 3 ]

20 голосов
/ 15 февраля 2012

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

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

Пример можно найти на этой моей статье

14 голосов
/ 20 февраля 2012

В конце концов я сделал это следующим образом.

Следуя идее 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 Sturtup 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 из подключенной модели представления и перейти к нужной мне странице.

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

0 голосов
/ 16 февраля 2012

Для навигационного приложения вы хотите, чтобы начальный вид был 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 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());
    }
}
...