Saying that a view-model belongs to the Application layer, and the Application layer doesn't references upper layers, and must not create or use visual objects, how can I open a Window, Dialog or any kind of Message Box on-the-fly, based on some logic triggered by the view or view-model?
Well, there are several options doing that, one is using kind of service which encapsulates that, providing an interface, so the view-model don't really work directly with the upper layer or WPF.
This solution is somehow problematic since the service should be implemented in the Presentation layer and somehow should be exposed to the view-model.
Having DI container is possible but still a bit tricky.
What other options we've got?
Say that you have a view-model contains list of email messages and the view renders it as an ItemsControl. Now you want displaying the email message details in a separate window triggered by:
The View - Double clicking or selecting an email and then press Enter same way as Outlook does.
The View-model - Property of a view-model changes, for example: ShowMessageDetails.
Before discussing my solution, I would like to say something about these two options.
- Opening a window triggered by the view when Routed event is raised or Routed command is executed is quite simple, in that case you should have a OpenWindowAction, triggered by event or command.
- Opening a window triggered by the view or view-model based on property change may be trickier, since property is a state, and it may by synchronized with the window state: Opened or Closed. In that case, changing the property should open or close the window, also closing the window should update the property.
Considering the fact that the window may be opened by the view or the view-model, based on event, command or property change, I propose two options: Custom Action and Behavior.
In this post I'll cover the custom Action solution, and in the next post I'll cover the Behavior solution which is a bit trickier.
Say that you've got: MessageListViewModel, MessageListView for the email messages view and MessageDetailsViewModel, MessageDetailsView for the email details view should be presented inside a window, lets say MessageDetailsDialog.
Having a SelectedMessage property in MessageListViewModel, lets look at the MessageListView:
<UserControl x:Class="WPFOutlook.PresentationLayer.Views.MessageListView"
xmlns:viewmodels="http://schemas.sela.co.il/advancedwpf"
xmlns:views="clr-namespace:WPFOutlook.PresentationLayer.Views"
xmlns:behaviors="clr-namespace:WPFOutlook.PresentationLayer.Behaviors"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.DataContext>
<viewmodels:MessageListViewModel />
</UserControl.DataContext>
<Grid>
<DataGrid ItemsSource="{Binding Messages}"
SelectedItem="{Binding SelectedMessage}"
AutoGenerateColumns="False"
CanUserAddRows="False"
CanUserDeleteRows="False">
<DataGrid.Columns>
Read more: Essential WPF and Young Brothers