Jeff Prosise's Blog

Silverlight 3's New Child Windows

If you've worked with Silverlight 3, you may have noticed that Visual Studio's Add New Item dialog includes an option for adding a "Silverlight Child Window" to your Silverlight project:

Silverlight Child Window

The new child window feature makes it easy to add modal dialogs to Silverlight applications. A child window derives from the new ChildWindow class, and its content is defined in XAML (of course!). So you can now embellish an application with modal popups containing rich content.

To see this feature in action, create a new Silverlight project and add a Silverlight child window to it. Replace "ChildWindow1.xaml" in the Name box with "ErrorDialog.xaml" and click OK. Visual Studio responds by adding two new files to your project: ErrorDialog.xaml, which contains the child window's UI, and ErrorDialog.xaml.cs, which contains the child window's code-behind class. You can display your new child window with two simple lines of code:

ErrorDialog dlg = new ErrorDialog();

dlg.Show();

When you do, an empty dialog appears with OK and Cancel buttons at the bottom. The content behind the dialog grays out and the user has to dismiss the dialog before doing anything else in the application.

You can add content to the dialog by declaring the content in ErrorDialog.xaml. You can also remove the OK and Cancel buttons by deleting the Button declarations. Here's some content you can plug into ErrorDialog.xaml to customize the dialog's appearance:

<StackPanel Orientation="Vertical">

  <Image Source="Images/UnhappyFace.png" Stretch="None" Margin="8" />

  <TextBlock Text="An unforeseen error has occurred. Please contact a system administrator or, better yet, use our competitor's Web site until we get the problem resolved." TextWrapping="Wrap" />

</StackPanel>

<Button x:Name="CloseButton" Content="Close" Click="CloseButton_Click"

  Width="75" Height="23" HorizontalAlignment="Center" Margin="16"

  Grid.Row="1" />

Add the following line of code to ErrorDialog's constructor to customize the title bar:

this.Title = "Error";

And add the following method to the ErrorDialog class to handle clicks of the Close button:

private void CloseButton_Click(object sender, RoutedEventArgs e)

{

    this.DialogResult = false;

}

When you display the dialog, here's what you get:

Child Window 

It's not earth-shaking, but it's certainly nice to have the ability to dress up your apps with genuine modal dialogs.

This is all rather straightforward, but certain aspects of a child window's operation merit further explanation. For example, the ChildWindow class has a Close() method that you can call to close a dialog, but my CloseButton_Click handler, which is patterned after the click handlers provided by Visual Studio, doesn't call it. DialogResult's setter calls Close for you, so simply assigning a value to the DialogResult property is sufficient to close the dialog.

Another aspect of child windows that may not be obvious is that Show() is an asynchronous call. That is, it doesn't wait for the dialog to be dismissed; it returns immediately. That's why Show() returns void rather than a DialogResult. If you want to know how the dialog was dismissed (that is, what the DialogResult value is once the dialog is closed), you handle the dialog's Closed event and check DialogResult there:

ErrorDialog dlg = new ErrorDialog ();

dlg.Closed += new EventHandler(OnErrorDialogClosed);

dlg.Show();

  ...

private void OnErrorDialogClosed(object sender, EventArgs e)

{

    ErrorDialog dlg = (ErrorDialog)sender;

    bool? result = dlg.DialogResult;

}

Note that DialogResult is a nullable bool, so it isn't necessarily set to true or false.

One last item to consider is how to retrieve input from a child window that allows the user to input data. Generally you build public properties into the dialog class and transfer values from the dialog's input controls into these properties in the OK button's click handler. After the dialog is dismissed, you then retrieve the user input from the dialog properties. For example, suppose a child-window class named InputDialog contains a TextBox named "InputBox" so the user can enter text. You could do this in the dialog class:

public string Input { get; set; }

  ...

private void OKButton_Click(object sender, RoutedEventArgs e)

{

    this.Input = InputBox.Text;

    this.DialogResult = true;

}

And after the dialog is dismissed, you could do this to find out what the user typed into the TextBox:

private void OnInputDialogClosed(object sender, EventArgs e)

{

    InputDialog dlg = (InputDialog)sender;

    bool? result = dlg.DialogResult;

 

    if (result.HasValue && result.Value)

    {

        string input = dlg.Input;

    }

}

This is how we used to retrieve input from dialog boxes in MFC. And now, 15 years later, it comes in handy again. I guess useful patterns never die!

On Apr 29 2009 7:39 AMBy jprosise With 25 Comments

Comments (25)

  1. I had to write a very similar function for SL2 - can't wait to kick SL3's wheels. Can the window leave the scope of the browser (or application in the case of an out-of-browser scenario?) Or will it still be confined to the primary grid/canvas? Thanks!

  2. I really hope that its not confined by the time its released - it makes it worthless I will have to continue with my hack using the bridge to javascript.

    Also it would be good to have other window modes - e.g. always on top, modeless.

  3. Is it possible to change the behavior of the ChildWindow the way it opens and closes? It kind of jumps out at you and disappears just as dramatically. I don't think this effect is appropriate in the business application when you open hundreds of windows a day.

  4. Is there a way to get a ChildWindow and/or its buttons to respond to an Escape keypress (for a Cancel button) and to respond to an Enter keypress (for an OK button)?

    Thank you in advance, and thanks for writing the article.

  5. John, You can always refactor the control itself..
    Take a look at tims page:
    http://timheuer.com/blog/archive/2009/05/10/silverlight-childwindow-non-modal-refactor.aspx


    /Roy

  6. Hi I want to open a PDF document in the child window, can this be done?? I mean the child window when popped up will have only the PDF document that can be scrolled vertically.

  7. Hi!
    Great Article!

    I was wondering how one can access resource files in the child window class?

    Im able to access it normally through a page in the xaml by using the tag but it doesnt work in a child window and I need it for localization.

    Thanks!

  8. Thx! Really helpfull post!
    "One last item to consider is how to retrieve input from a child window that allows the user to input data."
    private void OnInputDialogClosed(object sender, EventArgs e)
    {
    InputDialog dlg = (InputDialog)sender;
    bool? result = dlg.DialogResult;
    if (result.HasValue && result.Value)
    {
    string input = dlg.InputBox.Text; //it's work too
    }
    }

  9. Thanks a lot.
    i was stuck for hours till trying to figure out whats wrong with my code, until i read here that Show() is an asynchronous call.

  10. http://www.wintellect.com/CS/bhttp://www.wintellect.com/CS/blogs/JpegImage.aspxlhttp://www.wintellect.com/CS/blogs/JpegImage.aspxogs/JpegIhttp://www.wintellect.com/CS/blogs/JpegImage.aspxmaghttp://http://www.wintellect.com/CS/blogs/JpegImage.aspxhttp://www.wintellect.com/CS/blogs/JpegImage.aspxwwhttp://www.winthttp://www.wintellect.com/CS/blogs/JpegImage.aspxellect.com/http://www.wintellect.com/http://www.wintellect.com/CS/blogs/JpegImage.aspxCS/blogs/JpegImage.aspxCS/blogs/Jphttp://www.wintellect.com/CS/blogs/JpegImage.http://www.wintellect.com/CS/blogs/JpegImage.aspxaspxegImage.aspxhthttp://www.wintellect.com/CS/blogs/JpegImage.aspxtp://www.htthttp://www.wintellect.com/CS/blogs/JpegImage.aspxp://www.wintellect.com/CS/blogs/JpegImage.aspxwintellect.com/CS/blogs/JpegImhttp://www.wintellect.com/CS/blogs/JpegImage.aspxage.aspxw.http://www.wintellect.com/CS/blogs/JpegImage.aspxwintellhttp://www.wintellect.com/CS/blogs/JpegImage.ahttp://www.wintellect.com/CS/blhttp://www.wintellect.com/CS/blogs/JpegImage.aspxogs/JpegImage.aspxspxecthttp://www.winhttp://www.wintellect.com/CS/blogs/JpegImage.aspxtellect.com/CS/blogs/JpegIhttp://www.wintellect.com/CS/blogs/JpegImage.ahttp://www.wintellect.com/CS/blogs/JpegImage.aspxspxmaghttp://www.wintellect.com/CS/blogs/JpegImage.aspxe.aspx.com/CS/http://www.wintellect.com/CS/blogs/JpegImage.aspxblogs/Jpeghttp://www.wintellect.com/CS/blogs/JpegImage.aspxImage.ashttp://http://www.wintellect.com/CS/blogs/JpegImage.aspxwhttp://www.wintellect.com/CS/blogs/JpegImage.aspxww.wintellect.com/CS/blogs/JpegImage.aspxphttp://wwhttp://wwhttp://www.wintellect.cohttp://www.wintellect.com/CS/blogs/JpegImage.aspxm/CS/blogs/JpegImage.ahttp://www.wintellect.com/CS/blogs/JpegImage.aspxspxw.wintellect.com/CS/blogs/JpegImage.aspxw.wintellect.com/CS/bloghttp://www.wintellect.com/CS/blogs/JpegImage.aspxs/JpegImage.aspxxe.aspxhttp://wwhttp://www.wihttp://www.wintellechttp://wwwhttp://www.wintellehttp://www.wintellect.com/CS/blogs/JpegImage.aspxct.com/CS/blogs/JpegImage.aspx.wintellect.com/CS/blogs/JpegImage.aspxt.com/CS/blogs/JpegImage.aspxnhttp://whttp://www.wintellect.http://www.wintellect.com/CS/blogs/JpegImage.aspxcom/CS/blogs/JpegImage.aspxww.wintellect.com/CS/blogs/JpegImage.aspxtehttp://www.wintellect.com/CS/blogs/JpegImage.aspxllect.com/CS/blogs/http://www.wintellect.com/CS/blhttphttp://www.winthttp://www.wintellect.com/CS/blogs/JpegImage.aspxellect.com/CS/blogs/JpegImage.aspx://www.wintellect.com/CS/blogs/JpegImage.aspxogs/JpegImage.aspxJphttp://www.wintellect.com/CS/blogs/JpegImage.aspxegImage.aspxw.wintellect.com/http://www.wintellect.cohttp://whttp://www.wintellect.com/CS/blogs/JpegImage.aspxwhttp://www.wintellect.com/CS/blogs/JpegImage.aspxw.wintellect.com/CS/blogs/JpegImage.aspxm/CS/blogs/JpegImage.aspxCS/blogs/JpegImahttp://www.winhttp://www.wintehttp://www.wintellect.com/CS/blogs/JpegImage.aspxllect.com/CS/blogs/JpegImage.aspxtellect.cohttp://www.wintellect.com/CS/blogs/JpegImage.aspxm/CS/blogs/JpegImage.aspxge.aspxhttp://wwwhttp://www.wintellect.com/CS/blogs/JpegImage.aspx.wintellect.com/CS/blogs/JpegImage.aspxhhttp://www.wintellect.com/CS/blogs/JpegImage.aspxttp://www.wintellect.com/CS/blogs/JpegImage.aspxhttp://www.wintellect.com/CS/blogs/JpegImage.aspxhttp://www.wintellect.com/CS/blogs/JpegImaghttp://www.wintellect.com/CS/blogs/JpegImage.aspxe.aspxhttp://www.wintellect.com/CS/blogs/JpegImage.aspxhttp://www.wintelhttp://www.wintellect.com/CS/blogs/JpegImage.aspxlect.com/CS/blogs/JpegImage.aspxhttp://www.wintellect.com/CS/blogs/JpegImage.aspxhttp://www.wintellect.com/CS/blogs/JpegImage.aspxhttp://www.wintellect.com/CS/blogs/JpegImage.aspxhttp://www.wintehttp://www.wintellect.com/CS/blogs/JpegImage.aspxllect.com/CS/blogs/JpegImage.aspxhttp://www.wintellect.com/CS/blogs/JpegImage.aspx

Leave a Comment