View model shouldn't handle view elements. A dialog is a view element.
The view model can trigger user input by raising and event e.g., an error event with an data model as event args. The view that has registered to the event shows a dialog to collect user input and stores them in the previously received data model. The view then executes a command on the view model to pass back the data model.
Instead of an event you can also bind the view to a property of the view model e.g. of type bool
. On property change show the dialog and return the result using a ICommand
.
Alternatively let the view model expose a flag e.g. HasException
and a property ExceptionDialogModel
which can be used to bind a custom dialog or form. Then create a simple modal dialog yourself:
ExampleDialog
<Grid x:Name="ExampleDialog"
Visibility="Visible"
Panel.ZIndex="100"
VerticalAlignment="Top">
<Rectangle Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}, Path=ActualWidth}"
Height="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}, Path=ActualHeight}"
Fill="Gray"
Opacity="0.7" />
<Grid Width="400"
Height="200">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="100" />
</Grid.RowDefinitions>
<Border Grid.RowSpan="2"
Background="LightGray"
BorderBrush="Black"
BorderThickness="1">
<Border.Effect>
<DropShadowEffect BlurRadius="5"
Color="Black"
Opacity="0.6" />
</Border.Effect>
</Border>
<TextBlock Grid.Row="0"
TextWrapping="Wrap"
Margin="30"
Text="I am a modal dialog and my Visibility or Opacity property can be easily modified by a trigger or a nice animation" />
<StackPanel Orientation="Horizontal"
Grid.Row="1"
HorizontalAlignment="Right"
Height="50">
<Button x:Name="OkButton"
Content="Ok"
Width="80" />
<Button x:Name="CancelButton"
Margin="30,0,30,0"
Content="Cancel"
Width="80" />
</StackPanel>
</Grid>
<Grid.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ExampleDialog"
Storyboard.TargetProperty="Visibility"
Duration="0">
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Hidden}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Grid.Triggers>
</Grid>
You can put the Grid
anywhere in your Window
and toggle the Visibility
. It will overlay the parent Window
and has modal behavior.
Bind the DataContext
to the ExceptionDialogModel
so that the data is send back via TwoWay
binding. Use a command to trigger a retry procedure (e.g., an OK or Retry button).
The Visibility
can bind to the HasException
property. You can animate this dialog and give it any look and feel you like.
DialogDataReady
event to your dialog view model. The parent view model can subscribe to this event and handle it. But as I said before this is not good design as it violates MVVM. You introduced a dependency to your view by handling dialogs inside your view models. I think it's absolutely not necessary and very cheap to avoid. See my answer. I tried to show some alternatives that are not violating MVVM. – BionicCode