Как из одного 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 шт):
Абстрагируясь от вашего примера, я бы сделал как-то так. Способ называется "циклическая зависимость". Используется редко, вследствие своих недостатков, но зато выглядит просто.
Завел бы дочерние вьюмодели. Например какая-то логин-ВМ и ВМ элемента.
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 события из дочерней ВМ, а в главной на него подписываться.