MVVM Light 5.2 и страничная навигация

357
09 декабря 2016, 08:48

Очередной вопрос по навигации в WPF. Пытаюсь использовать MVVM Light Toolkit 5.2. Итак, есть MainWindow и к нему MainViewModel. MainWindow Содержит две панельки и Frame (может быть ContentControl) для отображения остальных вьюшек. В приложении хочется сделать страничную навигацию, да, желательно, так, чтобы не лезть в code behind.

Поскольку решено пользовать MVVM Light Toolkit, мне подумалось что хорошо бы родить какой-нибудь NavigationService, который всё будет знать о вью и этими самыми вью будет рулить. Исходя из хотелок, родился вот такой монстр:

public interface INavigationService
{
    void NavigateTo(string pageKey);
    void RegisterView(string pageKey, Type page);
}
public abstract class NavigationServiceBase<T> : INavigationService
{
    private T _currentPage;
    public T CurrentPage { 
        get{
            return _currentPage;
        } 
    }
    private Dictionary<string,Type> _registeredPages;
    public virtual void NavigateTo(string pageKey){
        if(string.IsNullOrEmpty(pageKey))
            throw new ArgumentNullException("pageKey", "Value can not be null or empty");
        Type view;
        if(_registeredPages.TryGetValue(pageKey, out view))
            _currentPage = (T)Activator.CreateInstance(view);
    }
    public virtual void RegisterView(string pageKey, Type page)
    {
        if(string.IsNullOrEmpty(pageKey) || page == null) 
            throw new ArgumentNullException();
        _registeredPages.Add(pageKey, page);
    }
    public NavigationServiceBase ()
    {
    _registeredPages = new Dictionary<string, Type>();
    }
}
public class PageNavigationService : NavigationServiceBase<Page>{
    public PageNavigationService () : base()
    {
    }
}
public class ViewModelLocator{
        static ViewModelLocator(){
            ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
            SimpleIoc.Default.Register<INavigationService>(() => CreateNavigationService());
        }
        private static INavigationService CreateNavigationService(){
            var navigationService = new PageNavigationService();
            navigationService.RegisterView("EmployeesView",typeof(EmployeesView));
            return navigationService;
        }
}

Однако, после рождения монстра, у меня возникли сомнения в правильности такого решения: предполагалось, что NavigationService будет инжектиться в основную ViewModel и "пробросит" туда свойство CurrentPage, на которое забиндится Content фрейма. Но, поскольку у INavigationService этого свойства нет и быть не может, смысл этого интерфейса теряется полностью, что не хорошо.

Итак, вопросы:

  1. Есть ли способ внутри NavigationService получить каким-то образом ссылку на фрейм, не передавая ее через конструктор и не устанавливая свойств сервиса? Чтобы можно было внутри NavigationService выполнить refToFrame.Content = Activator.CreateInstance(SomeView)

  2. Может быть я вообще не туда смотрю и лучше использовать какой-нибудь Messenger или другой механизм для этой цели?

  3. Может быть лучше сделать NavigationService синглтоном и дергать его в нужную ViewModel по необходимости?

Answer 1

В общем, получилось реализовать задуманное с помощью Мессенджера.

Добавился класс NavigateToMessage

public class NavigateToMessage<T>()
{
 public T View {get; private set;}
 public NavigateToMessage(T view){
  View = view;
}

NaviagtionServiceBase не изменился. PageNavigationService Дополнился переопределенным методом NavigateTo():

...
public override NavigateTo(string pageKey)
{
 base.NavigateTo(pageKey);
 Messenger.Default.Send(new NaviagteToMessage<Page>(_currentPage));
}

В главной ViewModel регистрируемся как получатель сообщения и устанавливаем свойство CurrentPage, которое биндится на Content фрейма в главном вью.

MessengerInstance.Register<NavigateToMessage<Page>>(this, message =>
{
 CurrentPage = message.View;
});

Надеюсь, что решение поможет кому-то ещё, кроме меня.

READ ALSO
Использование x:Bind с ViewModel UWP

Использование x:Bind с ViewModel UWP

Не получается сделать x:Bind для DataTemplate

397
Удаление файла C# Winfrom consoleapp

Удаление файла C# Winfrom consoleapp

Мое WinForms приложение может вызывать консольное, которое завершает процесс приложение WinForms и удаляет егоКогда я запускаю консольное приложение...

235
Сравнение двух одномерных массивов C#

Сравнение двух одномерных массивов C#

День добрый, ситуация следующая:

504
Многопоточность, блокировка доступа

Многопоточность, блокировка доступа

Есть приведенный ниже код, суть в том, что функции Add(), Read(), Modify(), Remove(), вызываются извне и в хаотичном порядке, с разным периодом во времени

233