Я попытался реализовать шаблон посредника в приложении WPF/MVVM, чтобы сделать возможным обмен данными между ViewModels.MVVM + Посредник: Регистрация посредника происходит слишком поздно
Чтобы применить шаблон посредника, я загрузил образец проекта из this link. И затем я узнал об этом из образца, а затем применил его к моему примеру.
У меня возникли проблемы с использованием этого шаблона, который в свою очередь производит смешной вывод.
Позвольте мне начать это с моим кодом:
Вот мой проект Структура:
SampleWPFMVVMMediatorApp
|
|--Data
| |--MenuItems.xml
|
|--Extensions
| |--MediatorX
| | |--IColleague.cs
| | |--Mediator.cs
| | |--Messages.cs
| | |--MultiDictionary.cs
| |--ViewModelBase.cs
|
|--Models
| |--MenuItem.cs
|
|--ViewModels
| |--MainWindowViewModel.cs
| |--ParentMenuViewModel.cs
| |--ChildMenuViewModel.cs
| |--SamplePageViewModel.cs
|
|--Views
| |--ParentMenuView.xaml
| |--ChildMenuView.xaml
| |--SamplePage.xaml
|
|--App.xaml
|--MainWindow.xaml
Код:
я просто разместить код для ViewModels и моделей сократите длину вопроса.
MenuItem.cs
public class MenuItem
{
public int Id { get; set; }
public string Name { get; set; }
}
MainWindowViewModel.cs
public class MainWindowViewModel : ViewModelBase
{
public MainWindowViewModel()
{
Mediator.Register(this, new[] { Messages.SelectedParentMenuItem, Messages.SelectedChildMenuItem });
}
private string _sourcePage;
public string SourcePage
{
get
{
return _sourcePage;
}
set
{
_sourcePage = value;
NotifyPropertyChanged("SourcePage");
}
}
private MenuItem _currentParentMenuItem;
public MenuItem CurrentParentMenuItem
{
get
{
return _currentParentMenuItem;
}
set
{
_currentParentMenuItem = value;
NotifyPropertyChanged("CurrentParentMenuItem");
}
}
private MenuItem _currentChildMenuItem;
public MenuItem CurrentChildMenuItem
{
get
{
return _currentChildMenuItem;
}
set
{
_currentChildMenuItem = value;
NotifyPropertyChanged("CurrentChildMenuItem");
if (CurrentChildMenuItem != null)
{
SourcePage = (from menuItem in XDocument.Load(Messages.DataDirectory + "MenuItems.xml")
.Element("MenuItems").Elements("MenuItem").Elements("MenuItem")
where (int)menuItem.Parent.Attribute("Id") == CurrentParentMenuItem.Id &&
(int)menuItem.Attribute("Id") == CurrentChildMenuItem.Id
select menuItem.Element("SourcePage").Value).FirstOrDefault();
}
}
}
public override void MessageNotification(string message, object args)
{
switch (message)
{
case Messages.SelectedParentMenuItem:
CurrentParentMenuItem = (MenuItem)args;
break;
case Messages.SelectedChildMenuItem:
CurrentChildMenuItem = (MenuItem)args;
break;
}
}
}
ParentMenuViewModel.cs
public class ParentMenuViewModel : ViewModelBase
{
public ParentMenuViewModel()
{
ParentMenuItems = new ObservableCollection<MenuItem>(
from menuItem in XDocument.Load(Messages.DataDirectory + "MenuItems.xml")
.Element("MenuItems").Elements("MenuItem")
select new MenuItem
{
Id = Convert.ToInt32(menuItem.Attribute("Id").Value),
Name = menuItem.Element("Name").Value
}
);
}
private ObservableCollection<MenuItem> _parentMenuItems;
public ObservableCollection<MenuItem> ParentMenuItems
{
get
{
return _parentMenuItems;
}
set
{
_parentMenuItems = value;
NotifyPropertyChanged("ParentMenuItems");
}
}
private MenuItem _selectedParentMenuItem;
public MenuItem SelectedParentMenuItem
{
get
{
return _selectedParentMenuItem;
}
set
{
_selectedParentMenuItem = value;
NotifyPropertyChanged("SelectedParentMenuItem");
Mediator.NotifyColleagues(Messages.SelectedParentMenuItem, SelectedParentMenuItem);
}
}
public override void MessageNotification(string message, object args)
{
throw new NotImplementedException();
}
}
ChildMenuViewModel.cs
public class ChildMenuViewModel : ViewModelBase
{
public ChildMenuViewModel()
{
Mediator.Register(this, new[] { Messages.SelectedParentMenuItem });
}
private MenuItem _currentParentMenuItem;
public MenuItem CurrentParentMenuItem
{
get
{
return _currentParentMenuItem;
}
set
{
_currentParentMenuItem = value;
NotifyPropertyChanged("CurrentParentMenuItem");
ChildMenuItemsOfSelectedParent
= new ObservableCollection<MenuItem>(
from menuItem in XDocument.Load(Messages.DataDirectory + "MenuItems.xml")
.Element("MenuItems").Elements("MenuItem").Elements("MenuItem")
where (int)menuItem.Parent.Attribute("Id") == CurrentParentMenuItem.Id
select new MenuItem
{
Id = Convert.ToInt32(menuItem.Attribute("Id").Value),
Name = menuItem.Element("Name").Value,
}
);
}
}
private ObservableCollection<MenuItem> _childMenuItemsOfSelectedParent;
public ObservableCollection<MenuItem> ChildMenuItemsOfSelectedParent
{
get
{
return _childMenuItemsOfSelectedParent;
}
set
{
_childMenuItemsOfSelectedParent = value;
NotifyPropertyChanged("ChildMenuItemsOfSelectedParent");
}
}
private MenuItem _selectedChildMenuItem;
public MenuItem SelectedChildMenuItem
{
get
{
return _selectedChildMenuItem;
}
set
{
_selectedChildMenuItem = value;
NotifyPropertyChanged("SelectedChildMenuItem");
Mediator.NotifyColleagues(Messages.SelectedChildMenuItem, SelectedChildMenuItem);
}
}
public override void MessageNotification(string message, object args)
{
switch (message)
{
case Messages.SelectedParentMenuItem:
CurrentParentMenuItem = (MenuItem)args;
break;
}
}
}
SamplePageViewModel.cs
public class SamplePageViewModel : ViewModelBase
{
public SamplePageViewModel()
{
Mediator.Register(this, new[] { Messages.SelectedChildMenuItem });
}
private MenuItem _currentChildMenuItem;
public MenuItem CurrentChildMenuItem
{
get
{
return _currentChildMenuItem;
}
set
{
_currentChildMenuItem = value;
NotifyPropertyChanged("CurrentChildMenuItem");
}
}
public override void MessageNotification(string message, object args)
{
switch (message)
{
case Messages.SelectedChildMenuItem:
CurrentChildMenuItem = (MenuItem)args;
break;
}
}
Пример:
Вы можете скачать образец проекта, который я создал here.
Проблема:
Пожалуйста, загрузите пример проекта, нажав на ссылку, указанную в строке выше, чтобы четко понять мою проблему.
- Запуск приложения.
- Как вы могли ожидать, что ChildMenuView отобразит некоторые элементы, он ничего не показывает. Я думаю, что эта проблема возникает из-за того, что ParentMenuView уведомляет, что selectedParentMenuItem изменен до того, как Регистр ChildMenuView зарегистрируется.
- Когда вы выбираете любой другой ParentMenuItem, ChildMenuView получает некоторые данные, и он отображает его правильно.
- Нажмите на любой дочерний элемент, вы можете ожидать, что страница загружена и какой-то текст в рамке. Но это ничего не отображает. Здесь также я думаю ту же проблему, о которой я упоминал в шаге 2.
- Нажмите на любой другой элемент ChildMenuItem. В этот момент Frame должен отображать некоторые данные, а затем приложение работает, как ожидалось.
Итак, мой вопрос: Как уведомить свойство, которое регистрируется после того, как другое свойство вызвало NotifyColleagues?
Ваш вопрос слишком длинный и, вероятно, не получит ответа в его текущей форме. Попробуйте обобщить и включить только соответствующую информацию. Никто не собирается читать ваш вопрос, если потребуется больше 1 или 2 минут ... –
кажется, что проект немного сложнее, мне интересно, зачем вам нужен пользовательский медиатор, когда у вас есть привязки? – pushpraj
@pushpraj вы можете объяснить мне дальше? – Vishal