Click here to Skip to main content
11,709,366 members (51,057 online)
Click here to Skip to main content

WPF Modal Dialog

, 17 Mar 2013 LGPL3 157.8K 7K 85
Rate this:
Please Sign up or sign in to vote.
How to set up a modal (blocking) dialog inside a WPF window.

2009_4_WpfModalDialog

There is a newer article with improved functionality here on CodeProject: http://www.codeproject.com/Tips/563144/WPF-Dialog-MessageBox-Manager.

Introduction 

What can you do if you would like to display a modal / blocking dialog in WPF? By default, there is the possibility to use the Window.ShowDialog() method. This has the disadvantage that a completely new "Windows"-window will be created which is not part of our main application window (which again has several disadvantages that I don’t want to discuss here). I would like to present an alternative solution.

As shown in the image, we would like to have a half transparent overlay with some kind of content (here, just for example, we use a simple text message, but we could also display other controls).

The ModalDialog control

The functionality and design is outsourced in a User Control. The XAML of this control is quite simple: we have the half transparent border that we use as our overlay, the TextBlock to display our message, and two Buttons for OK / Cancel.

<Grid DataContext="{Binding ElementName=root}">
    <Border Background="#90000000" Visibility="{Binding Visibility}">
        <Border BorderBrush="Black" BorderThickness="1" Background="AliceBlue" 
                CornerRadius="10,0,10,0" VerticalAlignment="Center"
                HorizontalAlignment="Center">
            <Border.BitmapEffect>
                <DropShadowBitmapEffect Color="Black" 
                  Opacity="0.5" Direction="270" 
                  ShadowDepth="0.7" />
            </Border.BitmapEffect>
            <Grid Margin="10">
                <Grid.RowDefinitions>
                    <RowDefinition />
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>
                <TextBlock x:Name="MessageTextBlock" 
                    Text="{Binding Message}" 
                    TextWrapping="Wrap" Margin="5" />
                <UniformGrid Grid.Row="1" Margin="5" 
                          Columns="2" HorizontalAlignment="Center"
                          VerticalAlignment="Bottom">
                    <Button x:Name="OkButton" Click="OkButton_Click" 
                          Content="Ok" Margin="2"  />
                    <Button x:Name="CancelButton" 
                          Click="CancelButton_Click" 
                          Content="Cancel" Margin="2" />
                </UniformGrid>
            </Grid>
        </Border>
    </Border>
</Grid>

Of course, it is still not clear how the "modal" or "blocking" behavior of the dialog is achieved. But how is that done? That’s a little bit tricky (you could also say "hacky" Smile | :) ). We have the following problem: "blocking" or "modal" means that the instruction pointer of our execution should remain at its position as long as the dialog is shown, and when the dialog is closed, it should continue. To achieve this, we would have to suspend the calling thread (typically the UI thread). If it is suspended, an interaction with our dialog will also be impossible because it is suspended, too. This is because WPF relies on a single thread model, which means it is impossible to run UI elements in another thread different from the thread of our main window. So we have to use a little hack here (I’m really not a friend of hacks, but here, it’s absolutely necessary).

When the dialog is shown, we start a loop in which we suspend the calling thread (typically the UI thread) for a short time, and we also advise the WPF dispatcher to process the messages (mouse click, movements, keystrokes, repaint, etc.) that occur in the sleeping time. If we choose a sleep time that is small enough, for the user it seems that the application is running fluently. Attention: If you would like to display elements in our dialog that have a lot of "animation" stuff on it, we will run into problems. If we just use some simple elements, it’s OK.

Here is the code for our control:

public partial class ModalDialog : UserControl
{
    public ModalDialog()
    {
        InitializeComponent();
        Visibility = Visibility.Hidden;
    }

    private bool _hideRequest = false;
    private bool _result = false;
    private UIElement _parent;

    public void SetParent(UIElement parent)
    {
        _parent = parent;
    }

    #region Message

    public string Message
    {
        get { return (string)GetValue(MessageProperty); }
        set { SetValue(MessageProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Message.
    // This enables animation, styling, binding, etc...
    public static readonly DependencyProperty MessageProperty =
        DependencyProperty.Register(
            "Message", typeof(string), typeof(ModalDialog), 
            new UIPropertyMetadata(string.Empty));

    #endregion

    public bool ShowHandlerDialog(string message)
    {
        Message = message;
        Visibility = Visibility.Visible;

        _parent.IsEnabled = false;

        _hideRequest = false;
        while (!_hideRequest)
        {
            // HACK: Stop the thread if the application is about to close
            if (this.Dispatcher.HasShutdownStarted ||
                this.Dispatcher.HasShutdownFinished)
            {
                break;
            }

            // HACK: Simulate "DoEvents"
            this.Dispatcher.Invoke(
                DispatcherPriority.Background,
                new ThreadStart(delegate { }));
            Thread.Sleep(20);
        }

        return _result;
    }
    
    private void HideHandlerDialog()
    {
        _hideRequest = true;
        Visibility = Visibility.Hidden;
        _parent.IsEnabled = true;
    }

    private void OkButton_Click(object sender, RoutedEventArgs e)
    {
        _result = true;
        HideHandlerDialog();
    }

    private void CancelButton_Click(object sender, RoutedEventArgs e)
    {
        _result = false;
        HideHandlerDialog();
    }
}

How to use the ModalDialog control

The dialog is used in the main application window, and as we can see, it overlays the complete content of the window:

<Grid>
    <Grid x:Name="ModalDialogParent">
        <StackPanel HorizontalAlignment="Left" VerticalAlignment="Top">
            <TextBox x:Name="MessageTextBox" 
              Text="Hello World!" Margin="3" />
            <Button x:Name="ShowModalDialog" 
              Click="ShowModalDialog_Click"
              Content="Show Modal Dialog" Margin="3" />
            <TextBlock x:Name="ResultText" />
        </StackPanel>
    </Grid>

    <controls:ModalDialog x:Name="ModalDialog" />
</Grid>

Notice that the dialog needs a reference to the element that "holds" the complete content of the window. In our case, this is the grid with the name "ModalDialogParent". This is important so that the dialog can disable it when it is shown (otherwise, the user could cycle with "tab" through the elements of the window).

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        ModalDialog.SetParent(ModalDialogParent);
    }

    private void ShowModalDialog_Click(object sender, RoutedEventArgs e)
    {
        var res = ModalDialog.ShowHandlerDialog(MessageTextBox.Text);
        var resultMessagePrefix = "Result: ";
        if (res)
            ResultText.Text = resultMessagePrefix + "Ok";
        else
            ResultText.Text = resultMessagePrefix + "Cancel";
    }
}

Have fun!

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)

Share

About the Author

Ronald Schlenker
Software Developer (Senior) www.technewlogic.de
Germany Germany
No Biography provided

You may also be interested in...

Comments and Discussions

 
GeneralMy vote of 5 Pin
Pinta4327-Dec-13 12:41
memberPinta4327-Dec-13 12:41 
QuestionWPF Dialog Button(s) disabled Pin
FXDynaRider9-Dec-13 12:46
memberFXDynaRider9-Dec-13 12:46 
Generalgood one Pin
aankur8117-Mar-13 19:50
memberaankur8117-Mar-13 19:50 
GeneralRe: good one Pin
Ronald Schlenker17-Mar-13 20:27
memberRonald Schlenker17-Mar-13 20:27 
GeneralRe: good one Pin
aankur8117-Mar-13 21:08
memberaankur8117-Mar-13 21:08 
GeneralMy vote of 2 Pin
Irina Pykhova17-Mar-13 7:30
memberIrina Pykhova17-Mar-13 7:30 
GeneralMy vote of 1 Pin
Quadiago17-Feb-13 21:47
memberQuadiago17-Feb-13 21:47 
Questioncontrol is not working in xbap application Pin
S.Faizan.Ali9-Feb-13 0:34
memberS.Faizan.Ali9-Feb-13 0:34 
GeneralMy vote of 2 Pin
Sergiy Tkachuk3-Aug-12 9:29
memberSergiy Tkachuk3-Aug-12 9:29 
QuestionChild window also disabling Pin
jeedigunta15-Jun-12 20:21
memberjeedigunta15-Jun-12 20:21 
AnswerRe: Child window also disabling Pin
Javid H. Hosseini14-Jan-13 21:59
memberJavid H. Hosseini14-Jan-13 21:59 
GeneralMy vote of 5 Pin
Assil6-Feb-12 8:10
memberAssil6-Feb-12 8:10 
GeneralMy vote of 3 Pin
jalalx4-Feb-12 9:47
memberjalalx4-Feb-12 9:47 
QuestionWhy the Thread.Sleep() method is required? Pin
Nero.6664-Oct-11 20:27
memberNero.6664-Oct-11 20:27 
GeneralBlurry text Pin
Sue M Maurizio31-May-11 23:51
memberSue M Maurizio31-May-11 23:51 
QuestionWhy not use the Owner-Property of the ChildWindow [modified] Pin
root20-Apr-11 2:00
memberroot20-Apr-11 2:00 
QuestionAdding new modal is NOT WORKING [modified] Pin
yrsk.aravind19-Mar-11 18:52
memberyrsk.aravind19-Mar-11 18:52 
QuestionWhy is that Thread.Sleep() in dispatcher? [modified] Pin
yrsk.aravind18-Mar-11 10:00
memberyrsk.aravind18-Mar-11 10:00 
QuestionKeyUp Event thrown multiple times Pin
SCHRANKK19-Oct-10 9:27
memberSCHRANKK19-Oct-10 9:27 
Generaldrag drop Pin
devvvy8-Aug-10 21:03
memberdevvvy8-Aug-10 21:03 
GeneralMy vote of 1 Pin
LefebvreOli25-Mar-10 1:41
memberLefebvreOli25-Mar-10 1:41 
QuestionWPF modal operations solution? Pin
Tri Q Tran3-Feb-10 14:48
memberTri Q Tran3-Feb-10 14:48 
AnswerRe: WPF modal operations solution? Pin
Callum16-May-10 11:24
memberCallum16-May-10 11:24 
Generaldisable x on modal wpf window Pin
TMags5-Jan-10 5:08
memberTMags5-Jan-10 5:08 
Generalblocking method Pin
Loic Berthollet17-May-09 10:32
memberLoic Berthollet17-May-09 10:32 
GeneralRe: blocking method Pin
Ronald Schlenker18-May-09 20:36
memberRonald Schlenker18-May-09 20:36 
GeneralRe: blocking method Pin
Philipp Sumi30-May-09 23:44
memberPhilipp Sumi30-May-09 23:44 
GeneralRe: blocking method Pin
Ronald Schlenker31-May-09 10:26
memberRonald Schlenker31-May-09 10:26 
GeneralRe: blocking method Pin
Philipp Sumi31-May-09 11:28
memberPhilipp Sumi31-May-09 11:28 
GeneralRe: blocking method Pin
Ronald Schlenker31-May-09 13:13
memberRonald Schlenker31-May-09 13:13 
GeneralRe: blocking method Pin
Jürgen Bäurle22-Apr-11 9:41
memberJürgen Bäurle22-Apr-11 9:41 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.150819.1 | Last Updated 18 Mar 2013
Article Copyright 2009 by Ronald Schlenker
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid