Phillip Trelford's Array

POKE 36879,255

Silverlight 5 Native Modal Windows

Multiple Window support is new in Silverlight 5:

You can display multiple Window instances in trusted, out-of-browser applications. This enables you to create non-modal dialog boxes, tear-off windows, and user-adjustable layouts that can span multiple monitors.

Silverlight provides support for modal dialog boxes that work in-browser and out-of-browser against the main window, like the ChildWindow control. However Silverlight’s built-in support for native Modal Windows is limited to the MessageBox class

MessageBox

Silverlight’s MessageBox.Show static method can open a modal dialog box, which is good for error messages, but it looks a bit basic and you can’t modify it’s style:

MessageBox.Show

ShowDialog

WPF provides a Window.ShowDialog method:

ShowDialog shows the window, disables all other windows in the application, and returns only when the window is closed.

This mechanism allows you to provide your own styling on the window.

Using an extension method, Silverlight’s Window class can be extended with a ShowDialog method too. This can be implemented very concisely in F#:

type System.Windows.Window with
   member window.ShowDialog() = 
      async {
          // Show the window
          window.Show()
          // Disable all other windows
          allWindows() |> Seq.filter ((<>) window) |> Seq.iter disableWindow
          // Await window closing
          do! window.Closing |> Async.AwaitEvent |> Async.Ignore
          // Enable all other windows
          allWindows() |> Seq.filter ((<>) window) |> Seq.iter enableWindow
      } |> Async.StartImmediate

Win32 provides an EnableWindow function that we can P/Invoke:

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnableWindow(IntPtr hWnd, bool bEnable);

The EnableWindow function takes a handle to a Window. The code to find a window’s handle is available in the article Silverlight 5 Native Windows P/Invoke that I wrote earlier in the month. The article also demonstrates how a window can be removed from the taskbar which you may want to do for a dialog window.

ShowModal

The ShowDialog method disables all other windows while the Window is shown. Let’s look at a ShowModal extension method in C# that only disable’s the owner window:

public static class ModalWindowExtension
{
    public static void ShowModal(this Window modalWindow, Window ownerWindow)
    {
        ModalWindow.Show(modalWindow, ownerWindow);
    }
}

An internal class instance is required so that we can hook and unhook the Closing event:

internal class ModalWindow
{
    Action _close = () => { };

    internal static void Show(Window modalWindow, Window ownerWindow)
    {
        var instance = new ModalWindow();
        instance.Invoke(modalWindow, ownerWindow);
    }

    internal void Invoke(Window modalWindow, Window ownerWindow)
    {
        modalWindow.Closing += WindowClosing;

        var ownerHwnd = Win32.FindHwnd(ownerWindow);
        bool isOwnerEnabled = Win32.IsWindowEnabled(ownerHwnd);
        Win32.EnableWindow(ownerHwnd, false);

        _close = () =>
        {
            modalWindow.Closing -= WindowClosing;
            Win32.EnableWindow(ownerHwnd, isOwnerEnabled);
            _close = () => { };
        };

        modalWindow.Show();
    }

    private void WindowClosing(object sender, ClosingEventArgs e)
    {
        _close();
    }
}

The C# implementation has to deal with some extra accidental complexity as C# events are not first class, beside that the implementations are quite similar.

Summary

Adding native modal window support for Silverlight 5 out-of-browser applications is pretty easy using the WIn32 EnableWindow and an extension method.

Comments (1) -

  • CB

    4/1/2013 4:16:24 PM |

    I'm guessing this doesn't work on Mac...

Pingbacks and trackbacks (2)+

Comments are closed