Custom Chrome in WPF

Some of you may have wondered who the creators of Microsoft Max did the Chrome.

Although this breaks one of the Top 10 Vista rules I will show how to create a WPF window with custom chrome.

You can't get there by simply setting the border of a WPF Window to None because always a thick border remains. You have to do a work around and create an empty Win32 window and fill it with your own WPF controls.

You can use the HwndSource object to do this. This object is intended to place WPF controls into Win32 Applications but you can also use it to place a WPF control onto your Windows Desktop which is also a Win32 application. HwndSource will call the native function CreateWindowEx and create the window for you.

Dim params As HwndSourceParameters = New HwndSourceParameters("CustomChrome 1", 400, 300)
Dim hwnd As HwndSource = New HwndSource(params)
hwnd.RootVisual = New Page1

This code will create a default window for you. The HwndSourceParameters's constructor sets the Name, Width and Height of the window to create. More parameters will be used later in this article.

HwndSource's RootVisual Property points to the WPF control being displayed by HwndSource.

I created a simple page with a green background:

The Window has still the default Windows Chrome but it's very easy to get rid of it. The key is the HwndSourceParameters object passed to the HwndSource constuctor. The
WindowStyle
property lets you define how the window looks like.

Public Const WS_POPUP As Integer = &H80000000
Public Const WS_CLIPCHILDREN As Integer = &H2000000
Public Const WS_VISIBLE As Integer = &H10000000

...

Dim params As HwndSourceParameters = New HwndSourceParameters("CustomChrome 1", 400, 300)
params.WindowStyle = WS_POPUP Or WS_CLIPCHILDREN Or WS_VISIBLE
params.SetPosition(20, 20)
Dim hwnd As HwndSource = New HwndSource(params)
hwnd.RootVisual = New Page1

Now the Chrome has gone but we aren't finished yet. As you can see, the Max Window
has round corners.

To create a non rectangular Window you need a Region, which can be created by serval API functions. In this special case let's pick CreateRoundRectRgn which creates a rectangle with round corners.

Public Declare Auto Function CreateRoundRectRgn Lib "gdi32" Alias "CreateRoundRectRgn" (ByVal X1 As Integer, ByVal Y1 As Integer, ByVal X2 As Integer, ByVal Y2 As Integer, ByVal X3 As Integer, ByVal Y3 As Integer) As IntPtr

X1 and Y1 define the StartPoint of the region, X2 and Y2 the EndPoint. X3 and Y2
define the radius of the edges.

Now you have to set the Window's region to the created one by calling SetWindowRgn.

Public Declare Auto Function SetWindowRgn Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal hRdn As IntPtr, ByVal bRedraw As Boolean) As Integer


SetWinowRgn
requires the Handle to the window whose window region is to be set.
You can get this Handle from HwndSource.Handle.
Dim rgn As IntPtr

rgn = CreateRoundRectRgn(0, 0, 400, 300, 10, 10)
SetWindowRgn(hwnd.Handle, rgn, True)

The result should look like this:

I created the Chrome with WPF Elements using Interactive Designer.

Last but not least you have to react on a closing of your window. The Disposed Event
is raised when the window is either closed by ALT+F4 etc. or HwndSource.Dispose is called (Close Method).

AddHandler hwnd.Disposed, AddressOf hwnd_Disposed

Private Sub hwnd_Disposed(ByVal sender As Object, ByVal e As EventArgs)
MyApp.Current.Shutdown()
End Sub

Creating a Window with custom chrome in WPF is very easy. You can define any shape you want by combining regions and use every effect and animation feature you like.

Our Window does not yet support Sizing and Moving but I will continue this tutorial in a few days ;-)

Read On:

Comments

shivachrome said…
Jan,

I read your blog on "Microsoft Max style window in WPF" and was very impressed. Excellent work! I am working on a project that I would love to use your ideas on. I have become familiar with your example from: http://vb-magazin.de/forums/blogs/janm/archive/2006/06/19/4655.aspx

I have translated the VB into C# code and have it working, except for one problem. The corners of the window border will not round. I have reviewed the code and everything looks correct, however the corner edges stay square and a small border exists around the edge of the window. It is very unusual. In any case, you can download the C# conversion of your code and an example usage. I am completely stumped on this one. Any help is greatly appreciated.

C# version of your WindowStyleExtender
http://citrix.ntsafety.com/ShivaChrome.zip

The WindowStyleExtender solution is named 'WPF'. The implementation is in P2P\MessageMonitor.

These are very basic examples with no fancy stuff.

Thanks for your time!
Chris

chris@reickenbacker.com

Popular posts from this blog

WPF: Binding updates

An Icq Client built on .NET?

InstallShield Applications on Vista 5270