不幸的是,我无法重现您的具体问题。我在 MainWindowView Loaded 事件处理程序中启动了一个单独的线程;一个除了不断发送特定消息之外什么都不做的线程。然后我在我的 SecondWindowView 上调用了 ShowDialog(),它的视图模型被注册来监听这个特定的消息。第二个窗口的视图模型中的消息处理程序重复执行。事实上,甚至在调用 ShowDailog() 之前就调用了处理程序,因为我的视图模型已经由 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 属性绑定到您的 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 属性设置为适当的视图模型来指定要显示的内容。
实际上,还有一件事。如果你真的想在你的子窗口中看到任何有用的东西,你需要在你的视图和视图模型之间指定模板绑定。这可以通过应用程序资源中的 xaml 来完成:
<DataTemplate DataType="{x:Type viewmodels:DetailsViewModel}">
<views:DetailsView />
</DataTemplate>
不要忘记定义命名空间(即“viewmodels”和“views”)。