Sunday, December 1, 2013

Modal Dialog Windows

This entry references WPF 4.0

With WPF a modal dialog window (a window that takes focus and does not release it until it is closed) is simply a window that is opened in a special way. This is not very different from .Net modal dialogs. Let's walk through the process.

Start by creating a new WPF window, let's call it VendorSearchPopup. We will add one label, one textbox, a Cancel button and an OK button. The XAML looks something like this...

<Window x:Class="VendorSearchPopup"
    xmlns="
http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="
http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Vendor Search"
    Height="300" Width="300">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="auto"></RowDefinition>
            <RowDefinition Height="auto"></RowDefinition>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"></ColumnDefinition>
            <ColumnDefinition Width="*"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Label Name="VendorNumberLabel" Content="Vendor Number" Grid.Row="0" Grid.Column="0"/>
        <TextBox Name="VendorNumberTextBox" Grid.Row="0" Grid.Column="1" />
        <Button Name="OKButton" Grid.Row="1" Grid.Column="0" Content="OK"></Button>
        <Button Name="CancelButton" Grid.Row="1" Grid.Column="1" Content="Cancel"></Button>
    </Grid>
</Window>


At this point there is nothing to suggest this is anything other than a normal window. However, if we open it using the ShowDialog method it is opened modally. The code in the calling XAML.VB would look like this. The ShowDialog method returns a nullable(of Boolean) that lets us know if the user cancelled the dialog box.

Dim Dlg As New VendorSearchPopup
Dlg.Owner = me
If Dlg.ShowDialog() Then

    ' Do things here
End If

Note: If you are opening the dialog box from a user control you would replace 'me' with 'Application.Current.MainWindow' or some other appropriate window object.

There are some window attributes you can set that are useful for dialog boxes. For example...
ResizeMode="NoResize"
ShowInTaskbar="False"
WindowStartupLocation="CenterOwner"
FocusManager.FocusedElement="{Binding ElementName=VendorNumberTextBox}"

Normally you open a dialog box to get some information from the user. You do this with public properties. Let's add a public property to the code behind called VendorNumber.

Public Property VendorNumber As String

After instantiating the window but before calling ShowDialog you can set this property so it's available for binding. In the calling code, before ShowDialog add this line...

Dlg.VendorNumber = "123456"

This causes the VendorNumber property to be populated after the dialog box is instantiated but before binding occurs. Now you can bind the VendorNumberTextBox to the VendorNumber property by setting the window's datacontext to itself and specifying a binding attribute on the VendorNumberTextBox.

After the dialog box's InitializeComponent() add the line...

DataContext = Me

and add the following binding attribute to the VendorNumberTextBox in the XAML...

Text={Binding Path=VendorNumber}

Note: Funny thing - as I was researching this I found someone asking how to bind a text box to a property and the first person that responded claimed this was a 'basic binding question' and then got the answer wrong :-) Fortunately the next poster got it right.

After the ShowDialog method returns your calling code can get the user's response by looking at the dialog box's properties. For example...

MessageBox.Show("You entered " & Dlg.VendorNumber)

You also need to specify the result to return from the ShowDialog method. You can do this in code using the me.DialogResult property. Setting it true or false will cause the dialog box to exit and return true or false.

You can use the IsCancel="True" attribute to specify buttons that should cancel the dialog box when the user clicks on them. The IsCancel attribute shown below causes the dialog box to be closed and return false from the ShowDialog method (indicating the user cancelled)

<Button Name="CancelButton" Grid.Row="1" Grid.Column="1" Content="Cancel" IsCancel="true"></Button>

However, for the buttons that should close the dialog box and return true you have to write some code. In the XAML attach an event handler to the OKButton.

<Button Name="OKButton" Grid.Row="1" Grid.Column="0" Content="OK" Click="OKButton_Click"></Button>

and in the event handler you set Me.DialogResult = true. This causes the dialog box to immediately close and return true to ShowDialog. Be sure to set all the public properties that the calling code needs before you exit. Of course, if you used two-way binding they should already be set.

Private Sub OKButton_Click(sender As System.Object, e As System.Windows.RoutedEventArgs)
    Me.DialogResult = True
End Sub


One last thing (I promise) is that many users expect the Enter key to  activate the [OK] button. You can specify which button is activated when the user hits the enter key by specifying the IsDefault attribute. I have no idea what happens if you specify this on more than one button. I also hope this is ignored when a multiline text box has focus.

<Button Name="OKButton" Grid.Row="1" Grid.Column="0" Content="OK" Click="OKButton_Click" IsDefault="true"></Button>

No comments:

Post a Comment