2014-10-15 11 views
8

Sto lavorando ad un'applicazione universale per Windows Phone 8.1 e voglio trovare il modo migliore di gestire le navigazioni di pagina senza avere una grande quantità di logica nel codice. Voglio mantenere il codice nascosto nella mia vista nel modo più semplice possibile. Qual è il modo MVVM accettato di navigare verso una nuova pagina in risposta a un clic del pulsante?Navigazione verso una nuova pagina dal modello di vista nell'app universale di Windows Phone 8.1

Attualmente devo inviare un messaggio RelayComnmand dal ViewModel alla vista con i dettagli della pagina per navigare. Ciò significa che il codice ha dietro di essere cablato come segue:

public MainPage() 
    { 
     InitializeComponent(); 
     Messenger.Default.Register<OpenArticleMessage>(this, (article) => ReceiveOpenArticleMessage(article)); 
... 
} 

    private object ReceiveOpenArticleMessage(OpenArticleMessage article) 
    { 
    Frame.Navigate(typeof(ArticleView)); 
    } 

Questo non sembra il modo migliore anche se funziona. Come posso fare le navigazioni di pagina direttamente da ViewModel? Sto usando MVVM-Light nel mio progetto.

+0

Forse questo può aiutarti: http://stackoverflow.com/questions/10971023/page-navigation-through-viewmodel-using-mvvmlight-in-windows-8 –

risposta

10

Ok, ho trovato una risposta a questa domanda. Ho preso un po 'di indagine ma alla fine ho trovato il modo preferito MVVM-Light per farlo. In ogni caso, non mi rendo conto di questa risposta, ma la scrivo qui nel caso in cui le persone stiano cercando una risposta a questa domanda.

creare un'interfaccia INavigationService come segue:

public interface INavigationService 
{ 
    void Navigate(Type sourcePageType); 
    void Navigate(Type sourcePageType, object parameter); 
    void GoBack(); 
} 

Creare una classe NavigationService come segue:

public class NavigationService : INavigationService 
{ 
    public void Navigate(Type sourcePageType) 
    { 
     ((Frame)Window.Current.Content).Navigate(sourcePageType); 
    } 

    public void Navigate(Type sourcePageType, object parameter) 
    { 
     ((Frame)Window.Current.Content).Navigate(sourcePageType, parameter); 
    } 

    public void GoBack() 
    { 
     ((Frame)Window.Current.Content).GoBack(); 
    } 
} 

Ora, nel ViewModelLocator, configurarlo in questo modo:

[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", 
     "CA1822:MarkMembersAsStatic", 
     Justification = "This non-static member is needed for data binding purposes.")] 
    public MainViewModel Main 
    { 
     get 
     { 
      return ServiceLocator.Current.GetInstance<MainViewModel>(); 
     } 
    } 

    static ViewModelLocator() 
    { 
     ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default); 

     if (ViewModelBase.IsInDesignModeStatic) 
     { 
      SimpleIoc.Default.Register<INavigationService, Design.DesignNavigationService>(); 
     } 
     else 
     { 
      SimpleIoc.Default.Register<INavigationService>(() => new NavigationService()); 
     } 

     SimpleIoc.Default.Register<MainViewModel>(); 
    } 

Quindi impostare un servizio di navigazione per l'ora di progettazione come segue:

public class DesignNavigationService : INavigationService 
{ 
    // This class doesn't perform navigation, in order 
    // to avoid issues in the designer at design time. 

    public void Navigate(Type sourcePageType) 
    { 
    } 

    public void Navigate(Type sourcePageType, object parameter) 
    { 
    } 

    public void GoBack() 
    { 
    } 
} 

mio MainViewModel costruttore è come segue:

public MainViewModel(INavigationService navigationService) 
    { 
     _navigationService = navigationService; 

     ... 

Ora si può semplicemente utilizzare questo per navigare nel vostro ViewModel:

_navigationService.Navigate(typeof(WelcomeView)); 

Per maggiori dettagli su l'autore originale Laurent Bugnion vedere questo articolo e il codice associato. http://msdn.microsoft.com/en-us/magazine/jj651572.aspx

+0

in qualsiasi modo possiamo usare questo per accedere alle voci del backstack ? –

+5

Il problema qui è che i tuoi modelli di vista hanno una dipendenza dalle classi di vista (typeof (...)) che dovrebbero essere evitate in un ambiente MVVM rigido ... –

+0

Dovresti creare una mappatura del modello View-to-View usando un dizionario nel tuo servizio di navigazione. Il modello di visualizzazione indicherà il tipo di modello di vista che desidera esplorare e il servizio di navigazione visualizzerà il tipo di modello di vista (come chiave) e troverà la vista corrispondente. In questo modo le viste e i modelli di visualizzazione sono completamente indipendenti l'uno dall'altro. – bleepzter

1

C'è una nuova e più semplice implementazione qui: https://marcominerva.wordpress.com/2014/10/10/navigationservice-in-mvvm-light-v5/
Per prima cosa creare il NavigationService e DialogService (per la pagina di navigazione params):

public ViewModelLocator() { 
    ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default); 

    var navigationService = this.CreateNavigationService(); 
    SimpleIoc.Default.Register<INavigationService>(() => navigationService); 

    SimpleIoc.Default.Register<IDialogService, DialogService>(); 

    SimpleIoc.Default.Register<MainViewModel>(); 
    SimpleIoc.Default.Register<DetailsViewModel>(); 
} 

private INavigationService CreateNavigationService() { 
    var navigationService = new NavigationService(); 
    navigationService.Configure("Details", typeof(DetailsPage)); 
    // navigationService.Configure("key1", typeof(OtherPage1)); 
    // navigationService.Configure("key2", typeof(OtherPage2)); 

    return navigationService; 
} 

viene creato un RelayCommand e NavigationService nella vostra ViewModel , così:

public class MainViewModel : ViewModelBase { 
    private INavigationService _navigationService; 
    public RelayCommand<Tuple<string, string>> DetailsCommand { get; set; } 

    public MainViewModel(INavigationService navigationService) { 
     this._navigationService = navigationService; 
     DetailsCommand = new RelayCommand<Tuple<string, string>>((args) => NavigateTo(args)); 
    } 

    public void NavigateTo(Tuple<string, string> args) { 
     this._navigationService.NavigateTo(args.Item1, args.Item1); 
    } 

    public void ClickAndNavigate() { 
     NavigateTo(new Tuple<string, string>("AdminPivotPage", "Test Params")); 
    } 
} 

Un la d, infine, siamo in grado di ottenere i params pagina di navigazione in questo modo:

public sealed partial class DetailsPage : Page { 
    // ... 
    protected override void OnNavigatedTo(NavigationEventArgs e) { 
     var parameter = e.Parameter as string; // "My data" 
     base.OnNavigatedTo(e); 
    } 
} 

Ma per leggere gli argomenti passati Navigazione Pagina nel modello MVVM, si può dare un'occhiata here.

+0

Per favore! Come posso associare il DetailsCommand a un oggetto GridView che sto popolando con dati sorgente JSON esterni? –

+1

Questo non è correlato a questa domanda, tuttavia puoi dare un'occhiata qui: [Come associare l'evento ItemClick a un comando e passare l'elemento cliccato su di esso] (https://marcominerva.wordpress.com/2013/03/ -e pass-how-to-bind-the-itemClick-evento-a-un-comando-the-clic-item-to-it 07//) –

0

Sono d'accordo con ricochete sopra, è più semplice, anche se la mia implosione diretta ha incasinato il mio Design Data Binding in Blend.

ho deciso di creare un una classe che ha ereditato dal NavigationService

public class NavigationServiceHelper : NavigationService 
{ 
    public NavigationServiceHelper() 
    { 
     this.Configure("Page1", typeof(View.Page1)); 
     this.Configure("Page2", typeof(View.Page2)); 
    } 
} 

Poi nel ViewModelLocator ho Registerred in questo modo

SimpleIoc.Default.Register<INavigationService, NavigationServiceHelper>(); 

My Design View Data Bindings ha funzionato di nuovo. Se qualcuno potrebbe spiegare perché i dati di progettazione non funzionano in ricochete sopra, per favore fallo. Grazie!

Problemi correlati