My blog about application development on the .NET platform and Windows®.

Implement a confirmation dialog in WPF using MVVM and Prism

If you are serious about implementing the MVVM pattern in your UI applications you should be well aware of the fact that any call you make to System.Windows.MessageBox.Show from your view models violates this pattern and the separation of concerns that exists between the application’s logic and its presentation.

By honoring the MVVM design pattern and its principles your application is likely to require less effort when you make changes in one area or another as the presentation layer (the view), the presentation logic layer (the view model) and the business model layer (model) are decoupled from each other. Other benefits include testability and the fact that designers and developers can work concurrently and independently.

One of first issues I ran into when I started learning and using MVVM in WPF was with how to display model dialogs and interacting with the user. Prism, the framework and guidance for building WPF and Silverlight applications from the Microsoft Patterns and Practices Team, provides a nice feature called InteractionRequests to tackle this issue.

The view model is responsible for issuing an interaction request by raising an event and Prism provides the IInteractionRequest interface and a concrete implementation InteractionRequest<T> to support this. The interface defines a “Raised” event to initiate an interaction and the generic class has a “Raise” method to publish this event with a context and an optional callback delegate to be called after the interaction completes.

The context is of type Notification, a simple class with a “Title” and a “Content” property to be displayed in the view that defines the actual appearance of the pop-up. There is also another pre-defined subclass of Notification called Confirmation with an additional Boolean property named “Confirmed”. The base class is used in scenarios where you want to display a simple one-way dialog and the latter one is used in two-way notifications with the additional property being used to signify that the user has confirmed or denied the operation.

Below is a sample implementation of a view model that initiates an interaction request when a command is fired from the view. Note that you will have to add references to Microsoft.Practices.Prism.dll and Microsoft.Practices.Prism.Interactivity.dll for the code to compile.

using Microsoft.Practices.Prism.Commands;
using Microsoft.Practices.Prism.Interactivity.InteractionRequest;
using System.Windows.Input;

namespace Mm.ConfirmationDialog.Module
{
    public class ViewModel
    {
        private readonly DelegateCommand _dialogCommand;
        private InteractionRequest<Confirmation> _confirmationInteractionRequest;

        public ViewModel()
        {
            _dialogCommand = new DelegateCommand(ShowDialog);
            _confirmationInteractionRequest = new InteractionRequest<Confirmation>();
        }

        public ICommand DialogCommand
        {
            get { return _dialogCommand; }
        }

        public IInteractionRequest ConfirmationInteractionRequest
        {
            get { return _confirmationInteractionRequest; }
        }

        private void ShowDialog()
        {
            _confirmationInteractionRequest.Raise(
                new Confirmation
            {
                Title = "Confirm",
                Content = "Do you want to continue?"
            }, OnDialogClosed);
        }

        private void OnDialogClosed(Confirmation confirmation)
        {
            if (confirmation.Confirmed)
            {
                //perform the confirmed action...
            }
            else
            {
                
            }
        }
    }
}

While the view model is responsible for initiating the request by calling the Raise method, the user experience and appearance for the interaction is defined in the view. After the event has been raised in the view model, an EventTrigger in the view will invoke a specified action and this action will then decide what will happen. Below is an example on how the view is setup to respond to events issued by the view model.

<UserControl x:Class="Mm.ConfirmationDialog.Module.View"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
             xmlns:dialog="clr-namespace:Mm.ConfirmationDialog.Dialog;assembly=Mm.ConfirmationDialog.Dialog"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <i:Interaction.Triggers>
        <!-- Trigger listening for the "Raised" event on the source object (of type IInteractionRequest) -->
        <i:EventTrigger EventName="Raised" SourceObject="{Binding ConfirmationInteractionRequest}">
            <i:EventTrigger.Actions>
                <dialog:ConfirmationWindowAction />
            </i:EventTrigger.Actions>
        </i:EventTrigger>
    </i:Interaction.Triggers>
    <Grid>
        <Button Content="Show dialog"
                HorizontalAlignment="Center" VerticalAlignment="Center"
                Command="{Binding DialogCommand}"/>
    </Grid>
</UserControl>

The EventTrigger class is defined in System.Windows.Interactivity.dll. It is worth to mention that Prism provides a custom EventTrigger named InteractionRequestTrigger that automatically connects to the Raised event of the IInteractionRequest interface. Using it you don’t have to specify a value for the “EventName” property but apart from that it doesn’t provide any extra functionality at all.

Also note that the specified action ConfirmationWindowAction is a custom one as WPF, unlike Silverlight, does not provide any default action to show a pop-up window out-of-the-box. You define your own action by creating a class that derives from TriggerAction<FrameworkElement> and implementing its Invoke method. In this method you can then add some code to display a window that represents the actual dialog. With this approach it’s possible to define the appearance of the dialog in pure XAML, just the way it should be. Below is an example of a template making the window looking similar to a MessageBox. The actions CallMethodAction and ChangePropertyAction are defined in Microsoft.Expression.Interactions.dll.

<Window x:Class="Mm.ConfirmationDialog.Dialog.ConfirmationWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
        Title="{Binding Title}"
        Width="460"
        MinHeight="185"
        ResizeMode="NoResize"
        ShowInTaskbar="False"
        SizeToContent="Height"
        WindowStartupLocation="CenterOwner"
        x:Name="confirmationWindow">
    <Grid Margin="4">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <ContentPresenter Content="{Binding Content}" Margin="10,10,10,10" Grid.Row="0"/>

        <Button Content="Cancel" Width="75" Height="23" HorizontalAlignment="Right" Margin="0,12,0,0"
                Grid.Row="1">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <ei:CallMethodAction TargetObject="{Binding ElementName=confirmationWindow}"
                                         MethodName="Close"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>
        <Button Content="OK" Width="75" Height="23" HorizontalAlignment="Right" Margin="0,12,79,0"
                Grid.Row="1">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <ei:ChangePropertyAction PropertyName="Confirmed" TargetObject="{Binding}" Value="True"/>
                    <ei:CallMethodAction TargetObject="{Binding ElementName=confirmationWindow}"
                                         MethodName="Close"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>
    </Grid>
</Window>

The ConfirmationWindow will use the context (of type Confirmation in this sample) passed to the Raise method from view model as its own view model or DataContext in order to be able to bind to the “Title” and “Content” properties and to set the value of the “Confirmation” property when any of the buttons are clicked. The window is created and injected with the context inside the cutom action as shown below.

using Microsoft.Practices.Prism.Interactivity.InteractionRequest;
using System;
using System.Windows;
using System.Windows.Interactivity;

namespace Mm.ConfirmationDialog.Dialog
{
    public class ConfirmationWindowAction : TriggerAction<FrameworkElement>
    {
        protected override void Invoke(object parameter)
        {
            InteractionRequestedEventArgs args = parameter as InteractionRequestedEventArgs;
            if (args != null)
            {
                Confirmation confirmation = args.Context as Confirmation;
                if (confirmation != null)
                {
                    ConfirmationWindow window = new ConfirmationWindow(confirmation);
                    EventHandler closeHandler = null;
                    closeHandler = (sender, e) =>
                    {
                        window.Closed -= closeHandler;
                        args.Callback();
                    };
                    window.Closed += closeHandler;
                    window.Show();
                }
            }

        }
    }
}

In the next post I will provide an example on how you can extend the IInteractionRequest interface to implement a dialog to be shown to the user while a request completes and how you can close the pop-up from code without requiring any action from the user.

Advertisements

12 Comments on “Implement a confirmation dialog in WPF using MVVM and Prism”

  1. Stephan says:

    Hi Magnus!

    Thank you for this great post.
    I’m struggling however while trying to set the focus on the Cancel button: what happens for me is that the “show dialog” button doesn’t loose its focus. Therefore, if you hit enter just after clicking, the code will crash…

    Do you have an idea?
    Stephan

  2. Hi Stephan,

    I don’t understand why the code would crash? Anyway, if you want the cancel button to be invoked when pressing the ENTER key, it has an IsDefault property that you can set to true:

    <Button Content=”Cancel” Width=”75″ Height=”23″ HorizontalAlignment=”Right” Margin=”0,12,0,0″ Grid.Row=”1″ IsDefault=”True”>…</Button>

  3. Chris says:

    Doesn’t seem to work, why don’t you link a project where you implement this so we can see the hidden details of how its wired together, references, etc?

  4. Dan says:

    This is incomplete. It only includes the confirmation dialog. This would have been useful if there is a working sample with everything wired up.

    As someone has said, ‘the most beautiful words will never reflect the beauty of a sample.’

  5. Sergey says:

    Where is cunstructor for ConfirmationWindow?

    In this line, VS tells, that constructor has 0 param.
    ConfirmationWindow window = new ConfirmationWindow(confirmation);

    If I don’t pass confirmation object, window doesn’t initialize properly.

  6. Sergey says:

    Sorry, I understood )

  7. Dave says:

    There is something similar to this for WINRT applications?… i cannot use Prism.Interactivity in that sort of projects.

  8. Hi Dave,

    No, there is currently no support for interaction requests in Prism for UWP.

    Also, the Prism.Interactivity package (but not the code itself) for WPF has been deprecated: http://nuget-prod-v2gallery.trafficmanager.net/profiles/brianlagunas

  9. Via Cognita says:

    Hi Magnus,

    Could you please share with us a complete working project with this code? It will be very useful for us.

    Thanks.

  10. hakam says:

    I think this apply for Prism 5 only, there is changes to the Prism 6, Right?

  11. Hi hakam,

    Yes, the this blog post was written before Prism 6 was released. The same principles regarding how to implement a confirmation dialog apply still apply though. You will find some examples using the latest version of Prism at GitHub: https://github.com/PrismLibrary/Prism-Samples-Wpf/tree/master/26-ConfirmationRequest/UsingPopupWindowAction. It includes a built-in PopupWindowAction.

  12. randy hoover says:

    i want the viewmodel constructor to be called each time i call the popup … the trigger code is in the mainwindow xaml … but the popup VM is only hit at startup and not when i call it


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s