我正在开发一个基于 mvvm light 工具包的项目。我有一个 MainView
和一个 DetailsView
及其
相应的 View 模型。两个 VM 都注册了一个 NotificationMessage
。
// MainViewModel.cs and DetailsViewModel.cs
private void RegisterMessages()
{
Messenger.Default.Register<NotificationMessage>(this, NotificationMessageHandler);
}
当收到“ShowDetails”消息时,MainViewModel
调用创建“DetailsView”的服务
// MainViewModel.cs
private void NotificationMessageHandler(NotificationMessage msg)
{
if (msg.Notification == "ShowDetails")
{
_detailsService.ShowDetails(); // Does something like (new DetailsView).ShowDialog()
}
}
DetailsView
使用 ViewModelLocator
获取现有的 DetailsViewModal
作为 DataContext。
DetailsViewModel
应该收到“ShowDetails”消息以更新其内部状态或请求一些数据。
// DetailsViewModel.cs
private void NotificationMessageHandler(NotificationMessage msg)
{
if (msg.Notification == "ShowDetails")
{
UpdateViewModel();
}
}
现在的问题是:
因为我希望 DetailsView
成为模态窗口,所以我对其调用了 ShowDialog()
。这似乎会阻止 Messenger,直到 DetailsView
再次关闭。所以 DetailsViewModal
在模态窗口关闭后收到消息。有解决办法吗?
如果我可以在 MainViewModel
之前注册 DetailsViewModal
,我认为它会起作用。这将更改 MessageHandler 调用的顺序,并且 VM 更新发生在阻塞 ShowDialog()
之前。但是 MainViewModel
是首先创建和注册的,因为它就是这样。 DetailsViewModel
是在第一次需要时由 ViewModalLocator
创建的,因此它总是输掉比赛。
最佳答案
很遗憾,我无法重现您的具体问题。我在我的 MainWindowView Loaded 事件处理程序中触发了一个单独的线程;一个除了不断发送特定消息之外什么都不做的线程。然后,我在我的 SecondWindowView 上调用了 ShowDialog(),它的 View 模型已注册以收听此特定消息。第二个窗口的 View 模型中的消息处理程序重复执行。事实上,处理程序甚至在调用 ShowDailog() 之前就被调用了,因为我的 View 模型已经在应用程序启动时由 ViewModelLocator 创建。我需要查看更多代码才能更好地了解您的情况(即您正在创建详细信息窗口的服务,或者我可以编译以重现该问题的内容)。
您可以为您的子窗口尝试以下方法。在您的应用程序中的某处定义以下类:
public class ShowChildWindowMessage : MessageBase { }
public class HideChildWindowMessage : MessageBase { }
public class DisplayDetailsMessage : MessageBase { }
现在创建以下 ChildWindowVM 类并在您的 ViewModelLocator 中初始化它,方法与初始化 MainWindowVM 的方式相同:
public class ChildWindowVM : ViewModelBase
{
private ViewModelBase m_currentContent;
public ViewModelBase CurrentContent
{
get { return m_currentContent; }
set
{
NotifySetProperty(ref m_currentContent, value, () => CurrentContent);
if (m_currentContent != null)
{
m_currentContent.Refresh();
Messenger.Default.Send(new ShowChildWindowMessage());
}
}
}
public ChildWindowVM()
{
Messenger.Default.Register<DisplayDetailsMessage>(this, OnDisplayDetails);
}
private void OnDisplayDetails(DisplayDetailsMessage msg)
{
CurrentContent = ViewModelLocator.DetailsViewModel; // or whatever view model you want to display
}
}
Refresh() 方法将在 DetailsViewModel 类中定义,并负责处理您希望在显示窗口之前执行的任何初始化。请注意,设置 CurrentContent 属性后,将向 MainWindowView 发送一条消息,以创建一个 ChildWindowView 实例,在该实例中显示您的内容。
MainWindowView 代码如下所示:
public partial class MainWindowView : Window
{
private ChildWindowView m_childWindowView;
public MainWindowView()
{
InitializeComponent();
Closing += () => ViewModelLocator.CleanUp();
Messenger.Default.Register<ShowChildWindowMessage>(this, OnShowChildWindow);
Messenger.Default.Register<HideChildWindowMessage>(this, OnHideChildWindow);
}
private void OnShowChildWindow(ShowChildWindowMessage msg)
{
m_childWindowView = new ChildWindowView();
m_childWindowView.ShowDialog();
}
private void OnHideChildWindow(HideChildWindowMessage msg)
{
m_childWindowView.Close();
}
}
最后一步是将 ChildWindowVM 类的 CurrentContent 属性绑定(bind)到您的 ChildWindowView 类。这是在您的 ChildWindowView 的 xaml 中完成的:
<Window x:Class="Garmin.Cartography.AdminBucketTools.ChildWindowView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
DataContext="{Binding Path=ChildWindowVm, Source={StaticResource Locator}}">
<Grid>
<ContentPresenter Content="{Binding Path=CurrentContent}" />
</Grid>
现在您只需调用即可在应用程序的任何位置显示您的详细信息
Messenger.Default.Send(new DisplayDetailsMessage());
您可以通过调用以编程方式关闭窗口
Messenger.Default.Send(new HideChildWindowMessage());
您还可以根据需要从 MessageBase 派生任意数量的类,并在您的 ChildWindowVM 类中注册它们。在每个消息处理程序中,您可以通过将 CurrentContent 属性设置为适当的 View 模型来指定要显示的内容。
事实上,还有一件事。如果你真的想在你的子窗口中看到任何有用的东西,你需要指定你的 View 和 View 模型之间的模板绑定(bind)。这可以通过应用程序资源中的 xaml 完成:
<DataTemplate DataType="{x:Type viewmodels:DetailsViewModel}">
<views:DetailsView />
</DataTemplate>
不要忘记定义命名空间(即“viewmodels”和“views”)。
关于c# - 有什么解决方案可以避免 ShowDialog() 阻塞 Messenger?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12449511/