不幸的是,我無法重現您的具體問題。我在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
}
}
刷新()方法是在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類。這是在XAML做了你的ChildWindowView:
<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」和「意見」)。
榮譽給予它如此好的努力,以幫助一個隨機的陌生人:) –
感謝您的廣泛答案。你寫道,虛擬機生活在非UI線程中。似乎很清楚Messenger是否也會這樣做,我的問題將會消失。我如何讓ViewModelLocator在不同的線程上創建虛擬機?順便說一下,我讀到了將VM放到非UI線程時,我會在ObservableCollections中遇到其他問題。 – Batuu
對不起,我沒有正確地說出關於UI線程的內容。我的意思是說你的視圖模型中的代碼可以在單獨的線程中運行。我已經更新了我的答案。此外,就ObservableCollection而言,如果您嘗試從另一個線程更新綁定到視圖的集合,則只會遇到問題。這必須在UI線程中完成,所以只需從其他線程執行:'App.Current.Dispatcher.Invoke(new Action((=)=> {//更新集合});' – bugged87