(Extended) Modal Window in Silverlight
An extension of the code submitted in the article: "Modal Window in Silverlight". This extension wraps the hosted control in a window frame that provides various modal features.

Introduction
Knowm Ercy's article Modal Window in Silverlight provided a nice way to display a Silverlight UserControl
in a way that looks and feels modal. Here at ProModel, Inc. we were interested in this functionality (which is not natively available within Silverlight at the moment) and its use in our Silverlight based applications. Using Knowm's article as a starting point, we put together an extension that "wraps" the hosted UserControl
inside a window frame which provides for resizing, moving, maximizing, and many of the other features enjoyed with traditional modal Windows forms.
This code is presented "as is" and we are aware of a number of improvements that can and should be made. However, given our in-house time constraints and the lack of a similar modal solution out there (a free one anyway), we decided to make this source available for improvement by anyone who's up for the challenge.
Background
Although we've made some departures from the original architecture, it is basically as we found it, just extended, so reading Knowm Ercy's article Modal Window in Silverlight should prove helpful in understanding the code.
There are two classes that work to provide the basic modal display:
Modal
A simple class containing the popup control which host the "modal" form and provides basic show/hide functionality.
ModalHost
A class that hosts the
UserControl
which is to be displayed modally. This class renders a "background canvas" that covers the entire browser window and prevents interaction with anything other than the hosted control, giving the impression that the hosted control is modal. Also, theModalHost
class provides basic mouse drag functionality such that the hosted control can be moved if a mouse drag occurs on its surface.
Each of the two modal display classes contained in our library (ModalControl
, WindowedModalControl
) contain an instance of each of these class. In the case of ModalControl
, the simple base classes are used (as with Knowm's provided project). In the case of WindowedModalControl
, each class is derived to provide the extended functionality.
Here is a summary of the functionality provided in the derived classes:
WindowedModal
(derived fromModal
)All that is done in this child class is a simple override of a method that sets the
ModalHost
instance within theModal
class. This allows us to insert our customModalHost
(WindowedModalHost
).internal class WindowedModal : Modal { #region Method Declarations protected override void SetHost(IModal ctrl, bool useCanvasPainting) { _host = new WindowedModalHost(ctrl, useCanvasPainting); } #endregion }
WindowsModalHost
(derived fromModalHost
)This class overrides a few basic
ModalHost
behaviors/adds some simple functionality:- Provides
RestoreState
property which keeps track of whether or not theWindowedModalControl
is maximized. - Overrides the
CenterWindow()
method so that it takes theRestoreState
into account. - Overrides mouse events to prevent the base class from taking any action.
public override void CentreWindow() { double dblX = 0.0, dblY = 0.0; UserControl modal = _modal as UserControl; if (RestoreState == RestoreState.Unmaximized) { // width if (_modal != null && !double.IsNaN (WindowHelpers.GetControlSize(modal).Width) && !double.IsNaN(Application.Current.Host.Content.ActualWidth)) { dblX = ((Application.Current.Host.Content.ActualWidth - WindowHelpers.GetControlSize(modal).Width) / 2); modal.SetValue(Canvas.LeftProperty, dblX); } // height if (_modal != null && !double.IsNaN (WindowHelpers.GetControlSize(modal).Height) && !double.IsNaN(Application.Current.Host.Content.ActualHeight)) { dblY = ((Application.Current.Host.Content.ActualHeight - WindowHelpers.GetControlSize(modal).Height) / 2); modal.SetValue(Canvas.TopProperty, dblY); } } protected override void OnMouseLeftButtonDown (object sender, MouseButtonEventArgs e) { // prevent the base class from taking action } protected override void OnMouseMove(object sender, MouseEventArgs e) { // prevent the base class from taking action }
- Provides
The WindowedModalControl
class provides the major functional extensions to Known's original work. This includes:
- Managing the placement of the hosted
UserControl
inside of a window frame - Support for Maximize/Restore
- Support for display of window as both resizing and non-resizing
- A title bar with image and auto-truncating text caption
- Built-in OK, Cancel, Apply button support
- Auto-sizing of the hosted
UserControl
- Usage of custom brushes for form header, background and text
Using the Code
Simply hosting your UserControl
within the WindowedModalControl
will look like this:
public void ShowWindowedModal(DialogClose callback, Panel panel)
{
bool useCanvasPainting = true; // whether of not the non-modal space
// is darkened partially
WindowedModalControl wmc = new WindowedModalControl
(callback, MsgBoxButtons.OKCancelApply);
TestUserControl tc = new TestUserControl();
wmc.HostedControl = tc;
wmc.ShowModal(panel, useCanvasPainting);
}
This sample makes use of some of the more advanced features:
public void ShowWindowedModal(DialogClose callback, Panel panel)
{
bool useCanvasPainting = true; // whether of not the non-modal space
// is darkened partially
WindowedModalControl wmc = new WindowedModalControl
(callback, MsgBoxButtons.OKCancelApply);
TestUserControl tc = new TestUserControl();
wmc.TitleBarBrush = Resources["ModalHeaderBrush1"] as Brush;
wmc.FormBackgroundBrush = Resources["ModalBrush1"] as Brush;
wmc.TitleImage = _titleImage;
wmc.HostedControl = tc;
wmc.ShowModal(panel, useCanvasPainting);
wmc.AllowResizing = true;
wmc.AllowMaximize = true;
wmc.TitleBarText = "It's a Working Title...and it truncates if need be";
}
The provided source comes with a demo application that has source code samples alongside run-time examples. A compiled help file is also included.
Special Thanks
To Knowm Ercy for the work he put into his article.