I'm using a Messenger class in order to send data between view models. There is an AppView
that hosts two main views in a content control, and up until now have had no issue with sending/receiving data this way.
Issue:
Now I added a ProductView
that shows a separate dialog to the AppView. But when I call Messenger.Default.Send<ProductModel>(SelectedProduct);
after calling .ShowDetailDialog() this blocks the Send
code call, until the dialog is closed.
I tried the other way around, calling the Send
code first, then opening the dialog. But this means that the message handler in the receiving VM doesn't register in time before the message is sent.
Does anyone know of a solution, to prevent the dialog from blocking the send call? Or alternatively register the ProductVM message handler prior to sending message and showing dialog?
Below is a summary of the related classes:
CustomerOrdersVM (sending code):
private void EditOrder(object obj)
{
_dialogService.ShowDetailDialog();
Messenger.Default.Send<ProductModel>(SelectedProduct);
}
ProductVM (receiving code):
public ProductViewModel()
{
Messenger.Default.Register<ProductModel>(this, OnSelectedProductReceived);
}
DialogService:
class DialogService : IDialogService
{
Window productView = null;
public DialogService()
{
}
public void ShowDetailDialog()
{
productView = new ProductView();
productView.ShowDialog();
}
}
AppVM (Main VM's are registered, ProductVM is independent of this VM):
public ApplicationViewModel()
{
// Add available pages
PageViewModels.Add(new CustomerDetailsViewModel(customerDataService, countryDataService, dialogService));
PageViewModels.Add(new CustomerOrdersViewModel(orderDataService, dialogService));
PageViewModels.Add(new OrderStatisticsViewModel());
// Set starting page
CurrentPageViewModel = PageViewModels[0];
}
AppView: (holds the AppVM views):
<Window x:Class="MongoDBApp.Views.ApplicationView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:views="clr-namespace:MongoDBApp.Views"
xmlns:vm="clr-namespace:MongoDBApp.ViewModels">
<Window.Resources>
<DataTemplate DataType="{x:Type vm:CustomerDetailsViewModel}">
<views:CustomerDetailsView />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:CustomerOrdersViewModel}">
<views:CustomerOrdersView />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:OrderStatisticsViewModel}">
<views:OrderStatisticsView />
</DataTemplate>
</Window.Resources>
<Window.DataContext>
<vm:ApplicationViewModel />
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height=".07*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<TabControl Grid.Row="1"
ItemsSource="{Binding PageViewModels}"
SelectedItem="{Binding CurrentPageViewModel}"
TabStripPlacement="Top">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ItemContainerStyle>
<Style TargetType="{x:Type TabItem}">
<Setter Property="IsEnabled" Value="{Binding IsEnabled}" />
</Style>
</TabControl.ItemContainerStyle>
</TabControl>
</Grid>
</Window>
You could solve the problem a few ways:
ShowDialog()
. UseShow()
, and make the dialog window TopMost and parented to the main window.Register the
ProductView
in the constructor of the DialogService (do you really need a newProductView
each time anyway?)Make the
DialogService
(or a utility class inside of it) register at construction time for the message, and then pass the message on to any displayedProductView
sPersonally I like #2- since you are using
ShowDialog
, it implies that only oneProductView
is ever needed at a time. For example: