Welcome to Pete Brown's 10rem.net

First time here? If you are a developer or are interested in Microsoft tools and technology, please consider subscribing to the latest posts.

You may also be interested in my blog archives, the articles section, or some of my lab projects such as the C64 emulator written in Silverlight.

(hide this)

Silverlight 5: Working with Operating System Windows

Pete Brown - 13 April 2011

In previous versions of Silverlight, we didn't have the ability to create new operating system windows. If we wanted to pop up content over our other application, we had to use the Popup element, or the derived ChildWindow control. Those were great, but didn't act as operating system windows. Specifically, they couldn't escape the bounds of your main application.

Please note that this article and the attached sample code was written using the Silverlight 5 Beta, available at MIX11 in April 2011, and updated for the Silverlight 5 RC.

ChildWindow controls are great for most things, but sometimes you just want something that acts like an operating system Window. Silverlight 4 had a Window class which allowed you to work with the chrome on the main hosting Window. Gladly, Silverlight 5 has extended that to allow you to create new windows of your own, almost like WPF.

Creating a Basic Window

First, you need to running an elevated trust out-of-browser application. Native Windows don't work inside the browser. Native Windows don't work in normal trust applications.

Once you are sure you are running an elevated trust out-of-browser application then we can go ahead and create the window. But first, we'll need to create some content for the window. I like to do that as a UserControl. I called this one, rather uncreatively, PopupWindowContents

<UserControl x:Class="NativeWindowDemo.Views.PopupWindowContents"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">

<Grid x:Name="LayoutRoot" Background="#FFFFE6CD">
<TextBlock Text="This is a native window"
FontSize="20"/>
<Rectangle Margin="44,49,136,131"
Name="rectangle1"
Stroke="Black"
StrokeThickness="1"
Fill="#FF4B86C4" />
<Ellipse Margin="151,105,59,35"
Name="ellipse1"
Stroke="Black"
StrokeThickness="1"
Fill="#FF6CB964" />
</Grid>
</UserControl>

Now, let's put some Xaml in our main window so we can have a UI to launch our new Window.

<Grid x:Name="LayoutRoot" Background="White">
<Button Content="Open"
Height="23"
HorizontalAlignment="Left"
Margin="148,132,0,0"
Name="OpenWindow"
VerticalAlignment="Top"
Width="75"
Click="OpenWindow_Click" />
</Grid>

Double-click the "Open" button in the designer, and put the following code in the event handler:

private void OpenWindow_Click(object sender, RoutedEventArgs e)
{
Window wnd = new Window();
wnd.Width = 500;

wnd.Height = 350;
wnd.Title = "This is a test window";
wnd.Content = new PopupWindowContents();

wnd.Visibility = Visibility.Visible;
}

Then, when you run the application, you'll have your popup native window. In the screen shot below, the window to the left is the main application window, the window to the right is the native window we created in code.

image

If you look in the taskbar, you'll see both of your windows open and available in the thumbnail

image

You may have noticed that there's no Show method in the examples. That's because in Silverlight, you simply set the Visibility to make the window visible. It's not required, but I like to do that as the last step after setting all the other window properties.

Update September 2011: For the RC (and final release) a Show method was indeed added. I'm glad to see that in there, as calling Show() is much more natural vs. setting Visibility. Of course, you can still use Visibility should you so desire.

Speaking of properties, you can open the window in the usual states:

wnd.WindowState = WindowState.Minimized;
wnd.WindowState = WindowState.Maximized;
wnd.WindowState = WindowState.Normal; // default

You can also set its startup location via the Left and Top properties.

Native child windows also allow you to modify their window chrome.

Setting the Window Style

When it comes to altering the chrome (borders and title bar) of a window, you have three choices:

wnd.WindowStyle = WindowStyle.SingleBorderWindow;
wnd.WindowStyle = WindowStyle.BorderlessRoundCornersWindow;
wnd.WindowStyle = WindowStyle.None;

The first "SingleBorderWindow" is the default, shown in the previous screenshots. Don't use BorderlessRoundCornersWindow. It throws an exception right now (at least in the build I'm working on)

And here is what WindowStyle.None gives you:

image

As expected, you get a window with no chrome at all; you are responsible for creating all the fiddly bits required to resize and move the window.

Creating Custom Window Chrome

Creating custom window chrome is more than just prettying up the window itself. You need to provide elements for sizing and moving the window. Luckily, Silverlight provides some helper methods to help you avoid writing all that drag / move / resize code. I know you love dealing with mouse capture, though :)

To help out with all this, I quickly whipped up a user control that contains the window chrome as well as the functionality required for wiring up to the parent window. If you want something truly reusable, create it as a standard templatable control. Here's the XAML for that control:

<UserControl x:Class="NativeWindowDemo.Controls.WindowChrome"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">

<Grid x:Name="LayoutRoot" Background="Transparent">
<Rectangle x:Name="TitleBar" Fill="Beige"
Height="30"
VerticalAlignment="Top" />

<Rectangle x:Name="RightResize"
Fill="Beige"
StrokeThickness="0"
Width="5"
VerticalAlignment="Stretch"
HorizontalAlignment="Right"
Cursor="SizeWE" />

<Rectangle x:Name="LeftResize"
Fill="Beige"
StrokeThickness="0"
Width="5"
VerticalAlignment="Stretch"
HorizontalAlignment="Left"
Cursor="SizeWE" />

<Rectangle x:Name="BottomResize"
Fill="Beige"
StrokeThickness="0"
Height="5"
VerticalAlignment="Bottom"
HorizontalAlignment="Stretch"
Cursor="SizeNS" />


<Rectangle x:Name="LeftBottomResize"
Fill="Beige"
StrokeThickness="0"
Width="5"
Height="5"
VerticalAlignment="Bottom"
HorizontalAlignment="Left"
Cursor="SizeNESW" />

<Rectangle x:Name="RightBottomResize"
Fill="Beige"
StrokeThickness="0"
Width="5"
Height="5"
VerticalAlignment="Bottom"
HorizontalAlignment="Right"
Cursor="SizeNWSE" />


<Button x:Name="CloseButton" Content="X" Width="20" Height="20"
Margin="0,5,5,0"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Click="CloseButton_Click" />
</Grid>
</UserControl>

The UI contains the main elements required for a resizable window with custom chrome:

Item Purpose
Title Bar Area to allow the user to click and drag the window to move it. You could make your entire window draggable (allowing the user to click on any empty area) but making the rectangle take up the whole client area.
Close Button You need some way to close your window. In this case, I created a simple close button. Note that you may also want maximize and minimize/restore buttons as well.
Left Resize, Right Resize, Bottom Resize These are long skinny rectangles docked to the edges of the window. This gives the user a place to click and drag to resize the window. Each has been assigned the appropriate resize cursor.
Left Bottom Resize, Right Bottom Resize These are squares (Rectangles) that sit in the bottom left and bottom right corners, above the other resize rectangles in the z-order. These allow the user to resize the window in two directions at once, and have the appropriate diagonal resize cursors assigned to them.

Due to the nice DragMove and DragResize methods, the code required to resize and move the window is really simple. Here it is, from the code-behind of the WindowChrome user control:

namespace NativeWindowDemo.Controls
{
public partial class WindowChrome : UserControl
{
public WindowChrome()
{
InitializeComponent();
}

// used a property because the parent window isn't in the visual
// tree when the user control is loaded

private Window _parentWindow = null;
public Window ParentWindow
{
get { return _parentWindow; }
set { _parentWindow = value; WireUpParentWindow(); }
}



private void WireUpParentWindow()
{
if (_parentWindow != null)
{
// wire up all our Window goodness

RightResize.MouseLeftButtonDown += (s, ea) =>
{
_parentWindow.DragResize(WindowResizeEdge.Right);
};

LeftResize.MouseLeftButtonDown += (s, ea) =>
{
_parentWindow.DragResize(WindowResizeEdge.Left);
};

BottomResize.MouseLeftButtonDown += (s, ea) =>
{
_parentWindow.DragResize(WindowResizeEdge.Bottom);
};


LeftBottomResize.MouseLeftButtonDown += (s, ea) =>
{
_parentWindow.DragResize(WindowResizeEdge.BottomLeft);
};

RightBottomResize.MouseLeftButtonDown += (s, ea) =>
{
_parentWindow.DragResize(WindowResizeEdge.BottomRight);
};

TitleBar.MouseLeftButtonDown += (s, ea) =>
{
_parentWindow.DragMove();
};
}
}

private void CloseButton_Click(object sender, RoutedEventArgs e)
{
if (_parentWindow != null)
{
_parentWindow.Close();
}
}
}
}

 

You may have noticed the ParentWindow property in the comments. During my initial tests with the control, I could not find a time (via an event or an override) when I could count on the parent Window to show up in the visual tree. So, I cheaped out and provided a property. This, along with the addition of the chrome control itself, necessitates some change to the main page's code behind.

Overlaying the main Window with the Chrome

Again, for a truly reusable control, you'd want to make this a templatable control rather than a usercontrol. In that case, I would also make it a content control and have a true window client area inside the chrome as opposed to the current overlay approach. Either way will work, however.

Here's the main page's code from the code-behind.

private void OpenWindow_Click(object sender, RoutedEventArgs e)
{
Window wnd = new Window();
wnd.Width = 500;

wnd.Height = 350;
wnd.Title = "This is a test window";
wnd.Content = BuildWindowContents(wnd);

wnd.WindowStyle = WindowStyle.None;

wnd.Visibility = Visibility.Visible;

}

private FrameworkElement BuildWindowContents(Window window)
{
Grid grid = new Grid();

WindowChrome chrome = new WindowChrome();
chrome.ParentWindow = window;

grid.Children.Add(new PopupWindowContents());
grid.Children.Add(chrome);

return grid;
}

Once you have all that in place, you'll have a window with active, custom chrome:

image

That's all there is to it. Well, except for bringing in a designer that can create some truly attractive window chrome, that is :)

Multiple Screens

One great advantage of the new native window class, is that you can now support multiple screens in your applications. Cool!

image

My workstation setup has two screens stacked on top of each other. The bottom one is a 30" screen, top is a 20" screen. Those windows are all from the same Silverlight application.

Easy as pie. Go forth and create real operating system windows for your Silverlight applications. I can't wait to see what you all come up with :)

Source code for the Silverlight 5 Beta version of this application may be downloaded via the link below.

A video version of this tutorial will be on Silverlight.net shortly.

       

Source Code and Related Media

Download /media/76812/nativewindowdemo.zip
posted by Pete Brown on Wednesday, April 13, 2011
filed under:        

21 comments for “Silverlight 5: Working with Operating System Windows”

  1. Declansays:
    Hi Pete

    Nice tutorial. I'm wondering how we might implement a tear off window, as demoed in the Firestarter last year, any hints? I imagine it could be implemented with dragging a component to near the edge of the window then make it a pop-out window, but that sounds quite clunky.

    thanks, Declan
  2. Petesays:
    @herbrandson

    Heh, yep :)

    @Declan

    I haven't looked into it, but you may want to make it a real window the moment the tab or whatever is dragged away from its dock area. The hard part would be re-docking it.

    Pete
  3. Chrissays:

    Hi Pete,

    Thanks for the intro. It soudns like this will allow us to continue development on a Outlook style application that has separate windows for each item that is opened. We had an app half way written in Silverlight 4 before the original developer realized that OOB didn't support "real" windows. Opps... This is great. Are there any limitations besides the trusted app requirements?

    Thanks,

    Chris
  4. eldonsays:
    I am playing with Azure Sliverlight business application implemented in C# using SL4 hosted on cloudapp.net. It consists of a Web and Client project. In the Client code, I would like to read the contents of a USB Flash Drive and communicate with another USB peripheral.

    Currently, I can select files from the flash drive using the Open File Dialog box but there is no means to allow the client code to automatically files from the USB drive. Running in Elevated Privileges using OOB restricts you to MyDocs, MyMusic, MyVideo, MyPictures.

    Other USB peripherals that I want to talk to have .NET dlls which are not compiled against the Silverllight Runtime therefore I cannot include them in a Client code.

    Would it be possible to do some of this with an Operating System Window?

    Thanks, Eldon.
  5. Tazsays:
    Windows aren't great in WPF...try hiding the minimize and maximise buttons for a dialog that doesn't have a fixed border....no idea why they missed something thats been in winforms and VS6 since the 90s.

    Stick an option into SL5 to allow you to control which buttons you can show if that doesn't exist.
  6. David Nelsonsays:
    Is this feature broken in SL 5 RC? When I run the downloaded app, I get the child windows but there is additional white border space on the child window to the right and bottom of the PopUpWindowContents.
  7. gksays:
    INCOMPLETE API

    Can't move a window after the application is loaded. Left and Top do nothing outside the App Start up event.

    I can't wait to stop developing this MS crap, its always the same, impressive samples and demos but when you go to do something in the real world its always the same 'oh you can't do that'. Or that doesn't work and never gets fixed.

    Can't wait for Silverlight to go and lie down in a corner and die. Have wasted 4 years developing crap.
  8. Nishit Gandhisays:
    Nice article, Do you have any idea about the below problem:::>
    I have SL 5 OOB application and I have one more window created that opens on some action on the Parent window.,
    Now, When the user clicks on the new window that is opened, I have a Childwindow, modal pop-up that is set to open BUT,
    this childwindow opens on the focus of Parent window., how do I open the child window on the focus of 2nd window that I opened.

    Can we have any property on Child Window to set the window it should be opened in ?

    Please reply asap..!

    Thanks.,
  9. Phillip Trelfordsays:
    Thanks for the info on the Native Window implementation in Silverlight 5 Beta.

    Unfortunately I've found the actual Silverlight 5 RTW Multi-Window support buggy, i.e.:

    * Setting WindowStyle to BorderlessRoundCornersWindow on a new Window throws an ArgumentException
    - https://connect.microsoft.com/VisualStudio/feedback/details/719076/silverlight-5-setting-windowstyle-to-borderlessroundcornerswindow-on-a-new-window-throws-an-argumentexception
    * Silverlight 5 maximizes borderless windows from a second monitor off the screen
    - https://connect.microsoft.com/VisualStudio/feedback/details/718460/borderless-silverlight-out-of-browser-app-maximize-on-second-monitor-issue

    Is there any patch planned?

    P.S. the Silverlight Toolkit (December 2011) is also buggy, e.g.
    * ContextMenu initiated from a child window always pop up in the main window (as the current window is determined via Application.Current.RootVisual)
  10. Petesays:
    @Phillip

    I pointed out in the post above that borderless round corner windows throw an exception

    "The first "SingleBorderWindow" is the default, shown in the previous screenshots. Don't use BorderlessRoundCornersWindow. It throws an exception right now (at least in the build I'm working on)"

    It ended up being the designed behavior. The same class is used for the main window which *does* support rounded corners, so the only thing the team could do was throw an exception when you try and set that on a child window.

    Don't be surprised if they close that one "by design"

    As to the second (maximizing off-screen), that does sound like a bug. Connect will route it to the right people, but thanks for also making me aware of it.

    On the toolkit issue, do you mean a second window like the ones here, or a ChildWindow element?

    Pete
  11. Phillip Trelfordsays:
    Thanks Pete,

    I do really hope there is a fix for maximizing borderless windows.

    We tried a simple workaround using PInvoke (but it has the same behaviour - window moves off-screen):

    var hwnd = FindWindow((string) null, "MaximzeTest Application");
    if (hwnd.ToInt32() != 0) ShowWindow(hwnd.ToInt32(), SW_SHOWMAXIMIZED);

    This leaves us either having to change to displaying the window with a border (changing the application's look and feel) or discover the user's connected displays via PInvoke and implementing maximize ourselves by setting the window positon and size.

    The Silverlight 5 Toolkit (December 2011) ContextMenu issue is with native windows like the ones in this post (not ChildWindows). The context menu window always pops up (a ChildWindow) on the main window (as the current window is determined via Application.Current.RootVisual).

    Thanks again,
    Phil

    P.S. Another issue we've come up against is dragging and dropping windows. The Window.DragMove method lets us begin a drag operation but there doesn't appear to be a mechanism for determing when the drag operation is complete (e.g. can't capture left mouse button up). Any ideas?
  12. Phillip Trelfordsays:
    Hi Nishit Gandhi,

    I experienced the same issue as you using the ChildWindow control in a multi-window environment.

    To workaround it I have created a small project on CodePlex: http://slmultiwindow.codeplex.com/

    The project contains an updated version of the ChildWindow control with a SetWindow method.

    Hope this helps,
    Phil
  13. Phillip Trelfordsays:
    @Pete

    I've been working with Silverlight 5 Operating System Windows for about 6 months now and this is what I've found so far.

    Silverlight 5's multiple window implementation seems to work as expected as long as you stick to the defaults (standard chrome borders, no GPU Acceleration) and you only open a few windows.

    When diverting from the defaults I have found a number of issues:

    Maximizing Windows:

    Borderless Silverlight Out Of Browser App - Maximize on Second Monitor Issue
    - https://connect.microsoft.com/VisualStudio/feedback/details/718460/borderless-silverlight-out-of-browser-app-maximize-on-second-monitor-issue
    - An issue when using a custom chrome border

    Locking Screen:

    Silverlight 5 Window Content Disappears After Unlocking Screen
    - https://connect.microsoft.com/VisualStudio/feedback/details/757744/silverlight-5-window-content-disappears-after-unlocking-screen
    - An issue on Windows XP with GPU Acceleration enabled
    Silverlight 5 Control Updates Are Not Visible When Screen Is Unlocked
    - https://connect.microsoft.com/VisualStudio/feedback/details/758060/silverlight-5-control-updates-are-not-visible-when-screen-is-unlocked
    - An issue when GPU Acceleration is enabled

    Performance:

    Silverlight 5 Responsiveness Degrades After Multiple Windows Are Opened
    - https://connect.microsoft.com/VisualStudio/feedback/details/757631/silverlight-5-responsiveness-degrades-after-multiple-windows-are-opened
    - An issue when many windows (>10) are opened and the windows are not recycled

    White flash:

    WPF Window with black background flashes white when first shown
    - http://social.msdn.microsoft.com/Forums/en/wpf/thread/bdb414fe-9abb-408c-8935-486e1795755b
    - An issue in both WPF & Silverlight

    It would be great to see resolutions to these issues in a patch release, particularly the performance degradation issue.
    Any help you could give in esculating these issues to the Silverlight team would be appreciated as I have had a limited response via Microsoft Connect.

    Thanks in advance,
    Phil

Comment on this Post

Remember me