2012-02-15 19 views
15

Acabo de comenzar un nuevo proyecto en el que la capa de presentación será realizada por WPF y MVVM Light por GalaSoft.¿Cómo navegar a través de Windows con MVVM Light para WPF?

Necesito muchas vistas y no me queda claro cómo administrar la navegación a través de Windows.

En primer lugar, las plantillas que se ofrecen en MVVM Light para la creación de un nuevo "WPF MVVM ver" Crear un nuevo Window que no es posible utilizar para la navegación por cuadro (quiero decir, por poner un marco en mainView y cambiar el ruta de origen para navegar).

¿Simplemente tengo que cambiar Window por Page para todas las vistas que creo usando plantillas?

¿O existe una forma diferente de realizar navegación en WPF con el juego de herramientas MVVM Light?

Respuesta

12

Finalmente lo hice de esta manera.

Siguiendo la idea de o_q, creé NavigationWindow como MainWindow y cambié todas las vistas a la página.

A continuación, he creado un inteface y una clase que el uso de Navegación:

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

} 

Luego, en viewModelLocator creé toda la cadena const nedded para almacenar los caminos a mis puntos de vista:

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 

En la aplicacióncs, en el controlador de eventos Application_Startup, con la ayuda de la Unidad COI Me he registrado un conjunto unitario de 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); 

Ahora, en mi ViewModelLocator, puedo registrar un mensaje de "Galasoft" para capturar todos los eventos y vaya a una página; en el constructor tengo:

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

    } 

De esta manera guardo todos los ViewModels "ignorante" ... que no saben nada acerca de la navegación, además de que no tienen código detrás.

Si necesito navegar usando un botón de una vista, puedo resolver NavigationService desde el viewModel conectado y navegar a la página que necesito.

Y, lo más importante, ¡funciona!

+0

Me di cuenta de que el constructor ViewModelLocator no es estático en su ejemplo; sin embargo, es estático en la implementación predeterminada ... – User1551892

20

Normalmente utilizo un ContentControl para mostrar contenido dinámico. La propiedad Content está generalmente vinculada a una propiedad CurrentViewModel en el elemento primario ViewModel, y DataTemplates se usan para indicar a WPF cómo dibujar el elemento ViewModels.

Para cambiar las vistas, simplemente cambie la propiedad CurrentViewModel en el padre ViewModel

puede encontrar un ejemplo en this article of mine

+0

Hola, Rachel, si pudieras publicar un ejemplo mínimo de cómo implementar esto además de tu enlace, sería genial. Simplemente ayuda a personas como yo a llegar a esta respuesta 5 años más tarde en caso de que el enlace ya no funcione por alguna razón – Ortund

+0

@Ortund ¿Ayudaría [esto SO] (https://stackoverflow.com/a/12216068/302677) ayuda? Ha pasado un tiempo desde que escribí esta respuesta, pero creo que el código en esa otra respuesta debería ser un ejemplo adecuado. – Rachel

0

Para una aplicación navegable, usted quiere que su puesta en marcha a fin de ser un lugar NavigationWindow de un Código 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" /> 

atrás:

using System.Windows.Navigation; 

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

Las plantillas de vista de MVVM Light usan Window, pero como habrás adivinado, puedes simplemente cambiarlo. Si desea poder navegar hacia y desde esta vista, conviértalo en Page. Esta es la forma de navegar:

Código
<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> 

Detrás:

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

Esto podría ser una posibilidad, incluso si no me gusta poner código en el código detrás. Además, olvidé decirte que mi aplicación será la interfaz hombre-máquina para máquinas expendedoras, por lo que es crucial para mí tener la posibilidad de navegar por las páginas de la forma más fácil, por ejemplo, enviando eventos de las capas inferiores (el el usuario no puede interactuar con la capa de presentación porque no hay mouse, pantalla táctil, teclado, etc.). ¿Es posible navegar por las páginas desde ViewModel de esta manera? – zero51

+0

@ zero51 sobre el tema de navegación en el modelo de vista, he publicado una solución aquí: [¿Cómo navegar de una vista a otra vista desde viewmodel en Silverlight?] (Http://stackoverflow.com/a/9304445/1130842) –

+0

Encontré esta publicación en el sitio de galasoft [link] (http://blog.galasoft.ch/archive/2011/01/06/navigation-in-a-wp7-application-with-mvvm-light.aspx). Explica cómo implementar la navegación en Windows Phone 7 ... Intentaré implementarlo en WPF usando navegación. – zero51

Cuestiones relacionadas