gpt4 book ai didi

c# - MVVM + 中介模式 : Registration of Mediator occurs too late

转载 作者:行者123 更新时间:2023-12-01 21:57:47 29 4
gpt4 key购买 nike

我尝试在 WPF/MVVM 应用程序中实现 Mediator 模式,以使 ViewModel 之间的通信成为可能。

为了应用中介模式,我从 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

代码:

我将只发布 ViewModel 和 Model 的代码以缩短问题的长度。

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 .

问题:

请单击上行中提到的链接下载示例项目,以清楚地了解我的问题。

  1. 运行应用程序。
  2. 正如您可能期望 ChildMenuView 显示一些项目,它最初不会显示任何内容。我认为出现此问题是因为 ParentMenuView 在 ChildMenuView 注册本身之前通知 selectedParentMenuItem 已更改。
  3. 当您选择任何其他 ParentMenuItem 时,ChildMenuView 会获取一些数据并正确显示。
  4. 单击任何子菜单项,您可能会看到加载的页面和框架上的一些文本。但这不显示任何内容。我在这里也想到了我在步骤2中提到的同样的问题。
  5. 单击任何其他 ChildMenuItem。这次 Frame 应该显示一些数据,然后应用程序按预期工作。

所以,我的问题是如何在另一个属性调用 NotifyColleagues 后通知一个注册自身的属性?

最佳答案

查找我的应用程序的更新版本 here .

<Rant>对我来说,中介模式只是一种不必正确构建代码的方法,而且我从未在实际的代码场景中使用过它。您的演示应用程序是一个很好的示例,其中在 ViewModel 上创建子模型集合(例如 ObservableCollection<ChildMenuViewModel>ParentMenuViewModel )非常有意义。相比之下,从(甚至还不存在的)子 ViewModel 监视父 ViewModel 上的属性似乎就像搬起石头砸自己的脚。广播中的每个人都发出了刺耳的声音,而不是原本应该有的良好的等级制度。 </Rant> .

如果您确实想保持在该模式内,则需要确保您的对象已注册到调解器(正如您在问题中已经注意到的那样),然后它才应该捕获调解器通知。

对于 Parent/ChildMenu,这很简单,只需重新排列 MainWindow.xaml:

<Grid Grid.Row="1">
<!-- ColumnDefinitions omitted -->
<views:ChildMenuView Grid.Column="0" />
<Frame Grid.Column="1" NavigationUIVisibility="Hidden" Content="{Binding SourcePage}"/>
</Grid>

<views:ParentMenuView Grid.Row="0" />

但是对于 Frame,情况要复杂得多,因为内容是动态实例化的(简化:通过在 SelectedChildMenuItem 的 setter 中设置 URI)。因此,您需要 BindingEngine 完成 URI 的更新,以便加载 Frame 内容,并且仅然后提高您的 NotifyColleagues(SelectedChildMenuItem)称呼。这真的变得很难看...当然,一切都有一个解决方法,您可以通过更改框架设置、绑定(bind) Content 来规避最糟糕的情况。 (见上文)而不是 Source并在调用 NotifyColleagues 之前实例化内容 ( SamplePage ):

private MenuItem _selectedChildMenuItem;
public MenuItem SelectedChildMenuItem
{
get { return _selectedChildMenuItem; }
set
{
_selectedChildMenuItem = value;
NotifyPropertyChanged("SelectedChildMenuItem");

LoadSourcePage(); // first instantiate the page (register it to mediator)
Mediator.NotifyColleagues(Messages.SelectedChildMenuItem, SelectedChildMenuItem); // only now notify
}
}

/// <summary>
/// Get the SourcePage and pass it to MainWindowViewModel
/// </summary>
private void LoadSourcePage()
{
if (SelectedChildMenuItem != null)
{
var sourceUri = (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") == SelectedChildMenuItem.Id
select menuItem.Element("SourcePage").Value).FirstOrDefault();

var relativePart = sourceUri.Substring(sourceUri.IndexOf(",,,") + 3);

var sourcePage = System.Windows.Application.LoadComponent(new Uri(relativePart, UriKind.Relative)); // instantiation with URI
Mediator.NotifyColleagues(Messages.SourcePage, sourcePage); // pass on
}
}

关于c# - MVVM + 中介模式 : Registration of Mediator occurs too late,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25901102/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com