2010-07-27 7 views
10

Estoy intentando encontrar una forma de que mi ViewModel gestione el guardado o restablezca el estado de la página cuando se navega desde o hasta la página.Gestionar los eventos OnNavigatedFrom/OnNavigatedTo en ViewModel

Lo primero que probé fue agregar un comportamiento de EventToCommand a la página, pero los eventos (OnNavigatedFrom y OnNavigatedTo) se declararon protegidos y EventToCommand no ve los eventos para vincular.

siguiente pensé que iba a tratar de usar la clase Messenger para pasar un mensaje al modelo de vista utilizando el código en el código de la vista atrás:

protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e) 
{ 
    Messenger.Default.Send<PhoneApplicationPage>(this); 
    base.OnNavigatedFrom(e); 
} 

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) 
{ 
    Messenger.Default.Send<PhoneApplicationPage>(this); 
    base.OnNavigatedTo(e); 
} 

Pero esto parece tener dos problemas, primero es tener este código en el código detrás de la página. En segundo lugar, ViewModel no puede diferenciar entre los eventos OnNavigatedFrom y OnNavigatedTo sin tener que crear un conjunto de clases contenedoras para el objeto PhoneApplicationPage (ver UPDATE a continuación).

¿Cuál es la forma más amigable con MVVM-Light de manejar estos eventos?

ACTUALIZACIÓN: que fue capaz de resolver el segundo problema mediante el envío de los mensajes como este:

protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e) 
{ 
    Messenger.Default.Send<PhoneApplicationPage>(this,"NavigatedFrom"); 
    base.OnNavigatedFrom(e); 
} 

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) 
{ 
    Messenger.Default.Send<PhoneApplicationPage>(this, "NavigatedTo"); 
    base.OnNavigatedTo(e); 
} 

y registrarlas como esto:

Messenger.Default.Register<PhoneApplicationPage>(this, "NavigatedFrom", false, (action) => SaveState(action)); 
Messenger.Default.Register<PhoneApplicationPage>(this, "NavigatedTo", false, (action) => RestoreState(action)); 

Respuesta

1

Parece que tienes una solución a su problema ya También me gustaría sugerir lo siguiente:

contemplar la utilización de uno de los valores de mensaje previstas en el MVVM-kit de herramientas, tales como:

NotificationMessage<T> 

De esta manera:

Messenger.Default.Send<NotificationMessage<PhoneApplicationPage>>(
new NotificationMessage<PhoneApplicationPage>(this, "Message")); 
5

la ejecución de un comando desde el código detrás es mucho más limpio que pasar por todo el lío de los mensajes. Después de todo, no hay nada de malo en que la vista conozca su DataContext.

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) 
    { 
     base.OnNavigatedTo(e); 
     viewModel.NavigatedToCommand.Execute(e.Uri); 
    } 

    ProfileViewModel viewModel 
    { 
     get 
     { 
      return this.DataContext as ProfileViewModel; 
     } 
    } 

Actualización: Pasando en NavigationContext.QueryString es probablemente más útil, puesto que ya analiza los parámetros y valor.

+0

No estoy de acuerdo con MVVM Light. Solo estoy pensando en el tiempo de ejecución. Pasando de VIEW a ViewModel a ViewModelLocator –

0

Creo que a lo que Ryan se refería era al hecho de que está utilizando PhoneApplicationPage como el mensaje que se está enviando, en lugar de un mensaje real.

Estás haciendo esto:

Messenger.Default.Send<PhoneApplicationPage>(this); 

que está enviando un mensaje de tipo PhoneApplicationPage. Probablemente no necesite enviar toda la PhoneApplicationPage como mensaje.

Puede hacer algunos mensajes para NavigatingTo/NavigatingFrom, es decir.

Messenger.Default.Send<NavigatingToMessage>(new NavigatingToMessage()); 

etc.

Estoy seguro de que hay un millón de mejores maneras de hacer esto, sólo iba junto con la forma en que había preparar las cosas.Personalmente, mi clase ViewModelBase tiene métodos NavigatingTo/NavigatingFrom y anulo los métodos respectivos en la Vista y los envío a mi ViewModel.

3

Lo siento por haber llegado tres años tarde a esta pregunta. Sí, todavía estoy usando Silverlight. Está bien que quiero escribir en Page de código subyacente de esta manera:

// Executes when the user navigates to this page. 
protected override void OnNavigatedTo(NavigationEventArgs e) 
{ 
    this.HandleOnNavigatedTo(e); 
} 

estoy usando un método de extensión de esta manera:

método
public static void HandleOnNavigatedTo(this Page page, NavigationEventArgs e) 
{ 
    var vm = page.DataContext as IPageNavigationViewModel; 
    if (vm == null) return; 
    vm.HandleOnNavigatedTo(e); 
} 

La extensión implica que el Page debe tener una vista del modelo que implementa IPageNavigationViewModel en DataContext. Para mí, este es un compromiso de separación de preocupaciones donde la página solo conoce los tipos de datos de propósito más general en el Dominio. Esta interfaz:

using System.Windows.Navigation; 

namespace Fox.Silverlight.ViewModels 
{ 
    /// <summary> 
    /// Defines View Model members for frame-navigation pages. 
    /// </summary> 
    public interface IPageNavigationViewModel 
    { 
     /// <summary> 
     /// Handles the <see cref="Page.OnNavigatedTo"/> method in the View Model. 
     /// </summary> 
     /// <param name="e">The <see cref="NavigationEventArgs"/> instance containing the event data.</param> 
     void HandleOnNavigatedTo(NavigationEventArgs e); 

     /// <summary> 
     /// Handles the <see cref="Page.OnNavigatedFrom"/> method in the View Model. 
     /// </summary> 
     /// <param name="e">The <see cref="NavigationEventArgs"/> instance containing the event data.</param> 
     void HandleOnNavigatedFrom(NavigationEventArgs e); 
    } 
} 
+0

por cierto: Soy un usuario de MVVM Light desde hace mucho tiempo ... – rasx

0

hago una muestra usando la respuesta actualizada dentro de la pregunta: ¿

MainViewModel.xaml.cs:

public class MainViewModel : ViewModelBase 
{ 
    public MainViewModel() 
    { 
     Messenger.Default.Register<PhoneApplicationPage>(this, "NavigatedTo", false, ExecuteNavigatedTo); 
    } 

    // action contains everything you want. 
    private void ExecuteNavigatedTo(Page page) 
    { 
     // example 
     bool b = page.NavigationContext.QueryString.ContainsKey("id"); 
    } 
} 

MainViewModel.xaml.cs:

protected override void OnNavigatedTo(NavigationEventArgs e) 
{ 
    Messenger.Default.Send<PhoneApplicationPage>(this, "NavigatedTo"); 
    base.OnNavigatedTo(e); 
} 
Cuestiones relacionadas