Click here to Skip to main content
16,020,111 members
Articles / Desktop Programming / XAML

Modal Window in Silverlight

Rate me:
Please Sign up or sign in to vote.
4.96/5 (16 votes)
12 Mar 2009CPOL4 min read 138K   2.3K   62   15
Shows a generic mechanism to make modal windows

NOTE: Version 2

This article is an update of the original published in September 2008. After the original article was published, it was noted that there are problems with hosting controls like ComboBox and DataGrid on the modal window. The problem was with the Popup class not being added to the visual tree.
As a solution, I have added a static property that needs to be set only once in the application and ideally it should be initialised to the VisualRoot of the main page and it must be of a Grid class.

C#
public partial class MainPage : UserControl
{
	public MainPage()
	{
		InitializeComponent();

		ModalControl.ParentHost = LayoutRoot; // Init the parent control
	}

	// Rest of the code removed
}

After the initialisation of the ModalControl.ParentHost, you may use modal windows to host ComboBoxes and DataGrids.

The demo project shows how to use the ModalControl and updated MessageBox.

Introduction

This article shows how to implement a class that enables a modal display of any UserControl derived control.

Background

My first implementation of this class required that you derive your controls from it in order for them to be displayed modally.
That works very well, and it is the most complete and easy to use implementation. But, the Expression Blend designer window does not display controls that are not derived directly from UserControl, so we lose all the nice design features of Blend.

That made me think how else I could achieve the same behaviour without losing designing with Blend. After some thinking, I realised that aggregation must be the solution.

Features of the ModalControl Class

  • Modal display of any UserControl derived control
  • Dragging of the hosted control
  • Centering the hosted control when the browser is resized
  • Hosted control is prevented from being dragged outside the browser's window

The Project

This project builds on the Silverlight Wizard project by showing how to show the Wizard modally, and I have also built a MessageBox that demonstrates how the ModalControl class can be wrapped up to create a self contained modal window.

What It Looks Like

Here, we can see the Silverlight Wizard project main page changed so a button shows the wizard modally. I have also added a Show Dialog button that will popup a modal dialog window that I have implemented by aggregating ModalControl.

modal01.png

Here, we see the Silverlight Wizard shown modally without making any changes to it. We use the ModalControl class externally.

modal02.png

And, here is the modal dialog:

modal03.png

Using the Code

You may employ services provided by the ModalControl class in two ways:

  • Use as a helper class and pass in the ShowModal function of the UserControl you want to show modally.
  • Wrap the ModalClass into your control, the MessageBox shows how to use this technique.

ModalControl as a Helper

Notice in the code below that we only will need to define one instance of the ModalControl; it is important that the ShowModal takes the control to display as a parameter and the HideModal returns the UserControl.

C#
// Declare a class instance member of the ModalControl
ModalControl _oModalCtrl = new ModalControl();

void OnShowWizardClick(object sender, RoutedEventArgs e)
{
    // Instantiate the wizard
    Wizard oWizard = new Wizard();

    // Set data context and add pages to the wizard
    oWizard.DataContext = LayoutRoot.DataContext;
    oWizard.Pages.Add(new WizardPage1());
    oWizard.Pages.Add(new WizardPage2());
    oWizard.Pages.Add(new WizardPage3());

    // Add a Pages event listener to the izard
    oWizard.PageEvent += new WizardPageEvent(OnPageEvent);

    // call ShowModal by passing the wizard refernce to the modal control
    // this call will show the wizard modally, it could be any user control
   _oModalCtrl.ShowModal(oWizard);
}

// Here we handle the wizard page events
void OnPageEvent(Wizard sender, WizardEventArgs e)
{
   _txtMsg.Text = string.Format("Action: {0}, Current: {1}, New: {2}",
   e.Action, e.CurrentPageIndex, e.NewPageIndex);

   // When we hit the Finish button on the wizard we call close on the
   // modal control and that returns to us the wizard reference so we could
   // do some processing if we need to - sender prameter does the same
   if(e.Action == WizardAction.Finish)
   {
     // Close the wizard
     Wizard oWizard = (Wizard)_oModalCtrl.HideModal();
   }
}

Wrapping the ModalControl

Encapsulating ModalControl within your own class is just as simple, it is fully demonstrated in the MessageBox class in the ModalWizard project here. The code here is a very simplified version of the actual implementation of the MessageBox, but it shows the important bits.

C#
public class MessageBox : UserControl
{
 // Static demofunction
 public static MessageBox Show(string Title, string Message)
 {
  // Here we create the MessageBox instance
  MessageBox oBox = new MessageBox(Title, Message);
  // Use its private member to show the dialog
  oBox.ModalHost.ShowModal(oBox);
  // Return the reference to the MessageBox
  return oBox;
 }

 // Instance memebers
 // --------------------------------------------------------------------
 // Declare a private instance of the ModalControl
 ModalControl ModalHost;

 // Pass the parameters to the constructor
 private MessageBox(string Title, string Message)
 {
  InitializeComponent();
  txtTitle.Text = Title;
  txtMessage.Text = Message;

  ModalHost = new ModalControl();  // Instantiate the ModalControl

  btClose.Click += OnCloseClick;
 }
 // Handle the close button click
 private void OnCloseClick(object sender, RoutedEventArgs e)
 {
  // On modal control call HideModal to close the message box
  ModalHost.HideModal();
 }
}

Using the MessageBox Class/Control

The following code section shows how to use the MessageBox control; you must remember that the ModalControl does not show the child/hosted control modally, it only gives the illusion of modality. In this version of the MessageBox, we don't need to maintain a reference
to the MessageBox as I have assumed that we will display one MessageBox at a time ever. This assumption allows me to have a single static reference to the MessageBox and therefore makes the MessageBox look more like the WinForms MessageBox.

C#
void OnShowDialogClick(object sender, RoutedEventArgs e)
{
 	MessageBox.Show("Some modal title", "This is some message!",
		MessageBox.Buttons.YesNo,
		MessageBox.Icons.Information, OnDialogClosed);
}

bool OnDialogClosed(object sender, ExitCode e)
{
	Debug.Print("Dialog Closed with code: " + e);
	return true;
}

Points of Interest

It is very important to remember that the modal windows are not actually modal, there is a semi-transparent canvas placed in between the current view and the modal control. If when the modal window is closed an exit code or any other detail is required, you must implement
some callback or an event handler. The MessageBox and ModalWizard classes in this project demonstrate all of these points.

Special Thanks

Reader Predrag Tomasevic for identifying the problem with Popup class not being added to the visual tree.

History

  • 28th September, 2008: Initial post
  • 11th March, 2009: Article updated

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Team Leader
United Kingdom United Kingdom
C, BASIC on XT 8086,
C++, Perl, Java, HTML, SQL
.
.
.
MCTS - Web Applications
MCTS - Windows Forms Applications
MCTS - Distributed Applications
MCPD - Enterprise Systems
.
WCF
WPF
Silverlight
Javascript
JQuery


ebuzoku@hotmail.com


Comments and Discussions

 
QuestionDifferences between this and ChildWindow ? Pin
cesnek2-Jan-10 14:29
cesnek2-Jan-10 14:29 
AnswerRe: Differences between this and ChildWindow ? Pin
Enver Buzoku3-Jan-10 8:15
Enver Buzoku3-Jan-10 8:15 
GeneralThanks Pin
Gabriel_7530-Oct-09 14:33
Gabriel_7530-Oct-09 14:33 
GeneralI Need A Strong-Modal Window Which Means It Will Also Block The Current Thread (Except itself) Pin
Peter Lee14-Aug-09 6:03
Peter Lee14-Aug-09 6:03 
GeneralRe: I Need A Strong-Modal Window Which Means It Will Also Block The Current Thread (Except itself) Pin
Enver Buzoku31-Oct-09 1:32
Enver Buzoku31-Oct-09 1:32 
QuestionCan we add this to codeplex Pin
Member 250331429-Apr-09 23:51
Member 250331429-Apr-09 23:51 
AnswerRe: Can we add this to codeplex Pin
Enver Buzoku30-Apr-09 5:25
Enver Buzoku30-Apr-09 5:25 
AnswerRe: Can we add this to codeplex Pin
Enver Buzoku30-Apr-09 5:28
Enver Buzoku30-Apr-09 5:28 
GeneralError in resize funtion Pin
gisjoe6-Apr-09 21:57
gisjoe6-Apr-09 21:57 
GeneralSimple and to the point Pin
cbertolasio7-Mar-09 18:44
cbertolasio7-Mar-09 18:44 
QuestionError while trying to add a Grid Pin
Member 108861228-Jan-09 0:12
Member 108861228-Jan-09 0:12 
AnswerRe: Error while trying to add a Grid Pin
Enver Buzoku8-Mar-09 13:53
Enver Buzoku8-Mar-09 13:53 
GeneralThanks Pin
lepipele16-Jan-09 6:19
lepipele16-Jan-09 6:19 
Modal.ModalControl is the class I needed... you solution is by far the best from what I've found during couple last few hours of browsing for "Create plain, simple modal window from UserControl".

Best!
P.
GeneralRe: Thanks Pin
lepipele20-Jan-09 11:51
lepipele20-Jan-09 11:51 
GeneralThanks Pin
Jerry Evans24-Oct-08 8:47
Jerry Evans24-Oct-08 8:47 

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

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