web-dev-qa-db-fra.com

MVVM Light 5.0: Comment utiliser le service de navigation

Dans la dernière version de MVVM Light note , il a été indiqué que MVVM Light fournit désormais un "service de navigation".

Mais moi et mon ami google sommes incapables de trouver comment l'utiliser.

Je peux voir que je peux demander une INavigationService à ServiceLocator, je vois donc comment je peux demander de passer à une autre page, mais:

  1. J'ai créé une nouvelle fenêtre, où je m'attends à réserver une zone spécifique pour la "page", comment puis-je spécifier cela?
  2. Comment spécifier toutes les pages disponibles? Y a-t-il quelque chose que je devrais appeler?
  3. Quel serait le format des paramètres donnés à la INavigationService

Existe-t-il une documentation officielle pour cette bibliothèque? Parce qu'actuellement, je le trouve bien codé et fonctionne bien, mais quand j'ai à chercher comment l'utiliser, je ne trouve jamais de documentation/exemple montrant comment faire, à l'exception de son blog qui a une entrée. C'est très frustrant. La seule documentation que j'ai trouvée est ceci , je ne connais pas très bien Pluralsight, mais il me semble qu'il est obligatoire de souscrire un abonnement mensuel n'est pas possible). 

15
J4N

Oui, MvvmLight a introduit la NavigationService dans sa dernière version mais elle n’a proposé aucune implémentation concernant Wpf (vous pouvez utiliser la version implémentée NavigationService dans WP, Metroapps, ..), mais malheureusement pas Wpf, vous devez l’implémenter par vous-même, voici comment je le fais actuellement ( crédit )

first crée votre interface de navigation qui implémente la MvvmLightINavigationService 

public interface IFrameNavigationService:INavigationService
    {
        object Parameter { get; }  
    }

Parameter est utilisé pour passer des objets entre ViewModels, et INavigationService fait partie de l'espace de noms GalaSoft.MvvmLight.Views

puis implémenter cette interface comme si 

class FrameNavigationService : IFrameNavigationService,INotifyPropertyChanged
    {
        #region Fields
        private readonly Dictionary<string, Uri> _pagesByKey;
        private readonly List<string> _historic;
        private string _currentPageKey;  
        #endregion
        #region Properties                                              
        public string CurrentPageKey
        {
            get
            {
                return _currentPageKey;
            }

            private  set
            {
                if (_currentPageKey == value)
                {
                    return;
                }

                _currentPageKey = value;
                OnPropertyChanged("CurrentPageKey");
            }
        }
        public object Parameter { get; private set; }
        #endregion
        #region Ctors and Methods
        public FrameNavigationService()
        {
            _pagesByKey = new Dictionary<string, Uri>();
            _historic = new List<string>();
        }                
        public void GoBack()
        {
            if (_historic.Count > 1)
            {
                _historic.RemoveAt(_historic.Count - 1);
                NavigateTo(_historic.Last(), null);
            }
        }
        public void NavigateTo(string pageKey)
        {
            NavigateTo(pageKey, null);
        }

        public virtual void NavigateTo(string pageKey, object parameter)
        {
            lock (_pagesByKey)
            {
                if (!_pagesByKey.ContainsKey(pageKey))
                {
                    throw new ArgumentException(string.Format("No such page: {0} ", pageKey), "pageKey");
                }

                var frame = GetDescendantFromName(Application.Current.MainWindow, "MainFrame") as Frame;

                if (frame != null)
                {
                    frame.Source = _pagesByKey[pageKey];
                }
                Parameter = parameter;
                _historic.Add(pageKey);
                CurrentPageKey = pageKey;
            }
        }

        public void Configure(string key, Uri pageType)
        {
            lock (_pagesByKey)
            {
                if (_pagesByKey.ContainsKey(key))
                {
                    _pagesByKey[key] = pageType;
                }
                else
                {
                    _pagesByKey.Add(key, pageType);
                }
            }
        }

        private static FrameworkElement GetDescendantFromName(DependencyObject parent, string name)
        {
            var count = VisualTreeHelper.GetChildrenCount(parent);

            if (count < 1)
            {
                return null;
            }

            for (var i = 0; i < count; i++)
            {
                var frameworkElement = VisualTreeHelper.GetChild(parent, i) as FrameworkElement;
                if (frameworkElement != null)
                {
                    if (frameworkElement.Name == name)
                    {
                        return frameworkElement;
                    }

                    frameworkElement = GetDescendantFromName(frameworkElement, name);
                    if (frameworkElement != null)
                    {
                        return frameworkElement;
                    }
                }
            }
            return null;
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion
    }

la MainFrame dans le code ci-dessus est le x: nom d'un simple contrôle Frame défini dans Xaml utilisé pour naviguer entre les pages (personnalisez-le en fonction de vos besoins)

Second: Dans la viewmodellocator, lancez votre service de navigation (SetupNavigation()) afin que vous puissiez l'utiliser dans vos modèles de vue:

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

            SetupNavigation();

            SimpleIoc.Default.Register<MainViewModel>();
            SimpleIoc.Default.Register<LoginViewModel>();
            SimpleIoc.Default.Register<NoteViewModel>();            
        }
 private static void SetupNavigation()
        {
            var navigationService = new FrameNavigationService();
            navigationService.Configure("LoginView", new Uri("../Views/LoginView.xaml",UriKind.Relative));
            navigationService.Configure("Notes", new Uri("../Views/NotesView.xaml", UriKind.Relative));            

            SimpleIoc.Default.Register<IFrameNavigationService>(() => navigationService);
        }

Troisième: enfin, utilisez le service, par exemple 

 public LoginViewModel(IFrameNavigationService navigationService)
        {
            _navigationService = navigationService; 
...
_navigationService.NavigateTo("Notes",data);
..

MODIFIER 

Un exemple explicite peut être trouvé à ce repo .

29
SamTheDev

Je ne sais pas si une fonctionnalité de navigation est disponible dans mvvm light. Je l'ai implémenté avec une liaison contentControl:

       <xcad:LayoutDocumentPane>
           <xcad:LayoutDocument x:Name="DetailDoc" CanClose="False">
                 <ContentControl Content="{Binding  DisplayedDetailViewModel}"/>
           </xcad:LayoutDocument>
       </xcad:LayoutDocumentPane>

Et puis la propriété viewmodel. Il hérite de la classe ViewModelBase light de mvvm.

    public ViewModelBase DisplayedDetailViewModel
    {
        get
        {
            return displayedDetailViewModel;
        }
        set
        {
            if (displayedDetailViewModel == value)
            {
                return;
            }
            displayedDetailViewModel = value;
            RaisePropertyChanged("DisplayedDetailViewModel");
        }

Pour que le contrôle de contenu sache quel contrôle utilisateur il doit utiliser, vous définissez DataTemplates dans app.xaml:

 <Application.Resources>
    <ResourceDictionary>
        <!--
        We define the data templates here so we can apply them across the
        entire application.

        The data template just says that if our data type is of a particular
        view-model type, then render the appropriate view.  The framework
        takes care of this dynamically.  Note that the DataContext for
        the underlying view is already set at this point, so the
        view (UserControl), doesn't need to have it's DataContext set
        directly.
    -->
        <DataTemplate DataType="{x:Type viewModel:LoggerViewModel}">
            <views:LogView />
        </DataTemplate>

Le LogView est le UserControl. Vous devez simplement affecter LoggerViewModel à DisplayedDetailViewModel, et Framework effectuera le travail.

2
Eric Bole-Feysot