2010-07-27 11 views
10

Sto cercando di capire come il mio ViewModel possa gestire il salvataggio o il ripristino dello stato della pagina quando la pagina viene spostata da o verso.Gestione degli eventi OnNavigatedFrom/OnNavigatedTo nel ViewModel

La prima cosa che ho provato è stato aggiungere un comportamento EventToCommand alla pagina, ma gli eventi (OnNavigatedFrom e OnNavigatedTo) sono dichiarati protetti e EventToCommand non vede gli eventi a cui associarsi.

successivo ho pensato di provare a utilizzare la classe Messenger per passare un messaggio al ViewModel utilizzando il codice nel codice del Vista dietro:

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

Ma questo sembra avere due problemi, in primo luogo sta avendo questo codice in il codice dietro la pagina. In secondo luogo, ViewModel non è in grado di rilevare la differenza tra gli eventi OnNavigatedFrom e OnNavigatedTo senza dover creare un set di classi wrapper per l'oggetto PhoneApplicationPage (vedere AGGIORNAMENTO in basso).

Qual è il modo MVVM-Light più amichevole per gestire questi eventi?

UPDATE: sono stato in grado di risolvere il secondo problema con l'invio dei messaggi come questo:

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

e la loro registrazione in questo modo:

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

risposta

1

Sembra che tu abbia una soluzione al vostro problema già. Vorrei anche suggerire il seguente:

guardare con uno dei valori dei messaggi forniti nel MVVM-toolkit, come ad esempio:

NotificationMessage<T> 

Ti piace questa:

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

esecuzione di un comando da il codice dietro è molto più pulito che passare attraverso l'intero casino di messaggistica. Dopotutto, non c'è niente di sbagliato nella vista che sa del suo 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; 
     } 
    } 

Aggiornamento: Passando NavigationContext.QueryString è probabilmente più utile, dal momento che analizza già i parametri e il valore.

+0

Non sono agitato con MVVM Light. Sto solo pensando al suo tempo di esecuzione. Passando da VIEW a ViewModel tramite ViewModelLocator –

0

Penso che quello che Ryan stava ottenendo, era il fatto che si sta utilizzando PhoneApplicationPage come messaggio che viene inviato, invece di un messaggio effettivo.

Lo stai facendo:

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

che sta inviando un messaggio di tipo PhoneApplicationPage. Probabilmente non è necessario inviare l'intera PhoneApplicationPage come messaggio.

È possibile effettuare alcuni messaggi per NavigatingTo/NavigatingFrom, ad es.

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

ecc

Sono sicuro che ci sono un milione di modi migliori per fare questo, stavo andando insieme a come si era impostare le cose.Personalmente, la mia classe ViewModelBase ha metodi NavigatingTo/NavigatingFrom e sovrascrivo i rispettivi metodi nella View e li invio al mio ViewModel.

3

Mi dispiace per essere arrivato con tre anni di ritardo a questa domanda. Sì, sto ancora utilizzando Silverlight. Va bene che voglio scrivere in Page code-behind in questo modo:

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

Sto usando un metodo di estensione in questo modo:

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

L'estensione implica che il Page deve avere una vista del modello che implementa IPageNavigationViewModel in DataContext. Per me, questo è un compromesso separazione-di-preoccupazioni in cui la Pagina conosce solo i tipi di dati più generici nel Dominio. Questo l'interfaccia:

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

btw: Sono un utente MVVM Light di lunga data ... – rasx

0

Faccio un esempio utilizzando la risposta aggiornata dentro la domanda:

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