Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

XAML Dialog Control: Enabling MVVM and Dialogs in WPF

0.00/5 (No votes)
29 Apr 2009 1  
Add Data Templated dialog to your application with a single line of XAML
MVVMDialogSample

Introduction

Wouldn't it be great if you could use dialogs like any other control in XAML? That is, drop in a <Dialog> element and have a modal dialog window appear? This would let Model-View-ViewModel (MVVM) programs show dialogs without touching the XAML's code behind; a feat not currently possible with Windows Presentation Foundation (WPF). This article presents the Dialog control which both simplifies dialogs and makes them work directly with MVVM.

Background

True proponents of MVVM believe that MVVM applications should have no substantial code behind for XAML files. This restriction guarantees that no ViewModel logic accidentally creeps into the View. Unfortunately, out of the box it's impossible to implement a dialog without writing some code behind. And even with code behind, the dialog won't have access to the automatic data template features of WPF because the dialog is treated as a separate logical tree. Because of these limitations, most MVVM applications simply don't use dialogs. This control solves many of these problems.

Using the Code

The dialog control is defined in the "DialogControl" folder of the sample code. It's all under the namespace MVVMDialogSample.DialogControl. To use it in an XAML file, first add the namespace to the parent element of your XAML:

xmlns:dialog="clr-namespace:MVVMDialogSample.DialogControl"

Then add the Dialog as a child control. The dialog control won't actually appear in the UI, so simply place it where it will correctly inherit any required data templates. A simple dialog element looks like this:

<dialog:Dialog Content="Hello World!" Showing="True" />

After adding the control to your XAML, a window may appear. This is because the Visual Studio XAML previewer is "previewing" your dialog. You have to close it before you can use Visual Studio again as it is a modal dialog. You can hide the dialog by setting Showing="False". Alternatively, the Showing property defaults to false.

Run the code and a window will appear with the content "Hello World!".

Much more interesting is to set or bind the Content property to a complex object. The dialog will pick up any applicable data templates from the main window and apply them to the content shown in the dialog window.

In MVVM, the most common usage of Dialog is to bind a property of the ViewModel to the Content property of the Dialog. For example:

<dialog:Dialog Content="{Binding Path=DialogViewModel}" /> 

Then, set a trigger on the Dialog which shows the dialog only when it has Content. To show the dialog window, simply set the bound ViewModel property to whatever you want to display in the dialog. To hide it, simply set the bound property to null. Here's a style that shows the dialog only when it has content:

<Style TargetType="{x:Type dialog:Dialog}">
 <Style.Triggers>
  <Trigger Property="HasContent" Value="True">
   <Setter Property="Showing" Value="True" />
  </Trigger>
 </Style.Triggers>
</Style>

Additionally, most MVVM applications will bind a ViewModel ICommand to the CancelCommand property. The Dialog will invoke the command stored in the CancelCommand property if the user closes the dialog by clicking the X. This allows the ViewModel to clean up if the user forcibly cancels.

Because the dialog control inherits from ContentControl, it has some extra properties that don't have any effect. In fact, the only properties that do anything are as follows:

  • Content - See the documentation for ContentControl.
  • ContentStringFormat - See the documentation for ContentControl.
  • ContentTemplate - See the documentation for ContentControl. Unfortunately, WPF has a bug where setting this property on a Window with a Template that contains a ContentPresenter will throw an exception, rendering this property pretty much useless. Thus, to format content you must rely on ContentTemplateSelector or a DataTemplate.
  • ContentTemplateSelector - See the documentation for ContentControl. If this property and ContentTemplate property are unspecified, the dialog control will attempt to find an appropriate data template.
  • DataContext - See the documentation for ContentControl.
  • Title - The title of the dialog.
  • Showing - Whether the dialog is showing or not.
  • CancelCommand - ICommand that is invoked when the dialog is cancelled.
  • WindowTemplate - The ControlTemplate for the Window. Must have a root element that derives from or is of type Window. A default Window is specified in "Themes\Generic.xaml".

Points of Interest

This control works mainly by binding properties of Dialog control to an instance of Window so the Window stays in sync. However, getting the DataTemplate from the dialog control to the dialog window takes a little more work. The dialog window has a special DataTemplateSelector which asks the dialog control what DataTemplate to use. Since the dialog control is in the logical tree of the main window, it chooses the correct DataTemplate. In this way, the dialog window gets the DataTemplate as though it were a control in the main window's logical tree. This would all be made much easier if the Window class could be added as a logical child of another tree but the code specifically disallows this.

The control also delays evaluation of the dialog's visibility when the Showing property changes. This is to prevent the dialog's ShowDialog() and Hide() from being called over and over again if the Showing property is changed multiple times due to coercion or styles. It delays evaluation by hooking a delegate to the Windows message pump via Application.Current.Dispatcher. The delegate evaluates the visibility once. While this is not strictly necessary, it reduces the number of Hide() and ShowDialog() calls that are made in complicated cases.

History

  • 2009/04/25
    • Made control lookless
    • Window is destroyed and recreated on each ShowDialog() and Close() which makes IsCancel work all the time
    • Moved Window specification to "Generic.xaml" and added WindowTemplate property
    • Hooked up ContentStringFormat, ContentTemplate, ContentTemplateSelector to Window
  • 2009/04/15
    • First published

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here