Как из одного ViewModel открыть другой

Учусь MVVM. Я пытаюсь из страницы HomeView открыть страницу ProductsView

За основу взял Rachel Lim's Blog

ApplicationViewModel

public class ApplicationViewModel : ObservableObject, IPageDisplay
{
...
        public IPageViewModel GetCurrentPage()
        {
            return CurrentPageViewModel;
        }

        void IPageDisplay.ChangeViewModel(IPageViewModel newPage)
        {
            ChangeViewModel(newPage);
        }
...
}

HomeViewModel

public class HomeViewModel : ObservableObject, IPageViewModel
{
        private IPageDisplay _pageDisplay;
        public HomeViewModel(IPageDisplay pageDisplay)
        {
            _pageDisplay = pageDisplay;
        }

        private ICommand _loadDashboardCommand;
        public ICommand LoadDashboardCommand
        {
            get
            {
                if (_loadDashboardCommand == null)
                {
                    _loadDashboardCommand = new RelayCommand(
                        p => LoadOtherView());
                }
                return _loadDashboardCommand;
            }
        }

        private void LoadOtherView()
        {
            _pageDisplay.ChangeViewModel(new ProductsViewModel());
        }

IPageDisplay

public interface IPageDisplay
{

    IPageViewModel GetCurrentPage();
    void ChangeViewModel(IPageViewModel newPage);
}

По итогу получаю ошибку:

Ссылка на объект не указывает на экземпляр объекта

В строке _pageDisplay.ChangeViewModel(new ProductsViewModel()); метода LoadOtherView

В чем проблема? Я долго изучал, но не разобрался. Я только учусь, надеюсь на подробный ответ и примером. Спасибо.

Можете скачать мой проект.


Ответы (1 шт):

Автор решения: aepot

Абстрагируясь от вашего примера, я бы сделал как-то так. Способ называется "циклическая зависимость". Используется редко, вследствие своих недостатков, но зато выглядит просто.

Завел бы дочерние вьюмодели. Например какая-то логин-ВМ и ВМ элемента.

public interface IViewModel
{

}

public class LoginViewModel : IViewModel
{
    private readonly INavigationViewModel _navigator;

    public LoginViewModel(INavigationViewModel navigator)
    {
        _navigator = navigator;
    }

    public ICommand LoginCommand { get; } = new RelayCommand(_ => {
        _navigator.Navigate<ItemViewModel>();
    });
}

public class ItemViewModel : IViewModel
{
    
}

И главную ВМ, где живут дочерние ВМ

public interface INavigationViewModel
{
    void Navigate<T>();
}

public class NavigationViewModel : INavigationViewModel
{
    private IViewModel[] viewModels;

    public IViewModel CurrentViewModel { get; private set; } // INPC

    public NavigationViewModel()
    {
        viewModels = new IViewModel[]
        {
            new LoginViewModel(this),
            new ItemViewModel()
        };
        CurrentViewModel = viewModels[0];
    }

    public void Navigate<T>()
    {
        CurrentViewModel = viewModels.First(vm => vm is T);
    }
}

Вот и получается, что при вызове команды LoginCommand ВМ переключится на другую. Есть способы посложнее, например через вызов кастомного или INPC события из дочерней ВМ, а в главной на него подписываться.

→ Ссылка