Jak poruszać się po oknach za pomocą MVVM Light for WPF?

Właśnie rozpocząłem nowy projekt, w którym warstwę prezentacyjną wykonają WPF i MVVM Light firmy GalaSoft.

Potrzebuję dużo widoków i nie jest dla mnie jasne, jak zarządzać nawigacją przez windows.

Przede wszystkim szablony oferowane w MVVM Light do tworzenia nowego "widoku WPF MVVM" tworzą nowy Window, którego nie można użyć do nawigacji po ramce (chodzi mi o umieszczenie ramki w mainView i zmianę ścieżki źródłowej na nawigować).

Czy po prostu muszę zmienić Window na Page dla wszystkich widoków, które tworzę za pomocą szablonów?

A może istnieje inny sposób wykonywania nawigacji w WPF za pomocą zestawu narzędzi MVVM Light?

Author: Alex Angas, 2012-02-15

3 answers

Zwykle używam ContentControl do wyświetlania dynamicznej zawartości. To Content właściwość jest zwykle związana z CurrentViewModel właściwością w rodzicu ViewModel, a {[4] } są używane do informowania WPF, jak narysować dziecko ViewModels.

Aby zmienić widok, po prostu zmień właściwość CurrentViewModel w rodzicu ViewModel

Możesz znaleźć przykład na Ten mój artykuł

 23
Author: Rachel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-15 13:39:06

W końcu zrobiłem to w ten sposób.

Podążając za ideą o_q, stworzyłem NavigationWindow jako MainWindow i zmieniłem wszystkie widoki na stronę.

Potem stworzyłem inteface i klasę, która używając nawigacji:

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

    }

Następnie, w viewmodellocatorze stworzyłem cały łańcuch const nedded do przechowywania ścieżek do moich widoków:

    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
     }

W Aplikacji.cs, w application_startup event handler, przy pomocy Unity IOC zarejestrowałem singleton z 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);

Teraz, moim zdaniem, mogę zarejestrować komunikat "Galasoft", aby wychwycić wszystkie zdarzenia i przejść do strony; w konstruktorze Mam:

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

        }

W ten sposób zachowuję wszystkie viewmodele "ignorantami"... nie wiedzą nic o nawigacji, a ja nie mam kodu.

Jeśli muszę nawigować za pomocą przycisku z widoku, mogę rozwiązać NavigationService z połączonego modelu widoku i przejść do strony, której potrzebuję.

Oraz, najważniejsze, że działa!

 15
Author: zero51,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-09-24 18:39:43

W przypadku aplikacji nawigacyjnej, widok startowy powinien być NavigationWindow zamiast 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" />

Kod za:

using System.Windows.Navigation;

public partial class MainWindow : NavigationWindow
{
    public MainWindow()
    {
        InitializeComponent();
    }
}

Szablony widoku świetlnego MVVM używają Window, ale jak się domyślasz, możesz to po prostu zmienić. Jeśli chcesz mieć możliwość nawigowania do i z tego widoku, zrób z niego Page. Tak się nawiguje:

<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>

Kod Za:

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());
    }
}
 0
Author: o_q,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-16 01:06:58