Click here to Skip to main content
Click here to Skip to main content

WPF Custom Chrome Library

, 3 Dec 2010 Ms-PL
Rate this:
Please Sign up or sign in to vote.
Create fully functional windows with custom chrome and caption buttons in WPF

Introduction

If you’ve ever tried to use WindowStyle=”None” to create a window with a custom chrome, you’ve no doubt noticed that you lose standard Windows functionality. This article shows how to use the WPF Shell Integration Library to solve most of these problems, and builds on this foundation by adding caption buttons (minimize, maximize/restore, and close) and a window icon control that displays the system menu on click and closes on double-click.

Background

The WPF Shell Integration Library provides an easy way to address the following features that are lost when WindowStyle is set to "None":

  • Click-and-drag to move the window
  • Click-and-drag borders to resize
  • Double-click to maximize and restore
  • Right-click to display system menu
  • Drag to top to maximize, drag away to unmaximize
  • When maximized, leave the Windows taskbar visible

However, it doesn't provide much help for the following additional features:

  • Caption buttons (minimize, maximize/restore, close)
  • Caption button hover glow (not addressed in this article)
  • Border shadow (not addressed in this article)
  • Window title abbreviated with ellipsis for smaller window width (not addressed in this article)

In attempting to create a fully-functional window with custom chrome, I was unable to find code for existing buttons similar to the standard Windows min/max/close buttons, and I wanted a convenient way to incorporate this capability into future projects, so I created this new library and named it "WPF Custom Chrome Library".

From Standard Chrome to Custom Chrome

Standard Chrome

Here's the standard Windows chrome (in Windows 7) we're all familiar with:

Window1.png

And here's the basic XAML snippet for the Window with standard chrome:

<Window x:Class="CustomChromeSample.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:CustomChromeSample"
        Title="Window 1 - Standard Chrome"
        Height="350" Width="525">

When you set WindowStyle to "None", you lose the title bar and caption buttons, but you still have the resize border:

Window2.png

Set ResizeMode to "NoResize" in order to remove the resize border:

Window3.png

We now have the basic custom look that we're after, but we've lost standard window functionality like the caption buttons, dragging, double-click to maximize, and the system menu. Here's the XAML for the Window declaration:

<Window x:Class="CustomChromeSample.Window3"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
		xmlns:local="clr-namespace:CustomChromeSample"
		WindowStyle="None"
		ResizeMode="NoResize"
        Title="Window 3 - No Chrome"
        Height="350" Width="525">

Restoring Standard Behavior

The WPF Shell Integration Library restores the basic functionality.

Window4.png

Here's the XAML for the Window declaration as well as the WindowChrome from the Shell Integration Library:

<Window x:Class="CustomChromeSample.Window4"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:shell="http://schemas.microsoft.com/winfx/2006/xaml/presentation/shell"
        xmlns:ccl="clr-namespace:CustomChromeLibrary;assembly=CustomChromeLibrary"
		xmlns:local="clr-namespace:CustomChromeSample"
        Title="Custom Chrome Sample"
        Height="350" Width="525">

	<shell:WindowChrome.WindowChrome>
		<shell:WindowChrome
            ResizeBorderThickness="6"
            CaptionHeight="43"
            CornerRadius="25,25,10,10"
            GlassFrameThickness="0">
		</shell:WindowChrome>
	</shell:WindowChrome.WindowChrome>

The WindowChrome class restores the basic window functionality that we lost when we set WindowStyle to "None". The full capabilities of this class and how to customize it require an article unto itself. Some important points to note:

  • ResizeBorderThickness is set to 6 to provide an adequate area for the user to click to resize the window. This does not affect the window appearance in any way.
  • CaptionHeight specifies how much of the top of the window is occupied by the title bar and should respond to click-and-drag, double-click to maximize, and right-click for system menu.
  • CornerRadius specifies the amount that the window corners are rounded. According to the documentation, CornerRadius only has an effect when the standard window glass frame is disabled (because Aero is not enabled or because GlassFrameThickness is set to 0).
  • GlassFrameThickness is set to 0 in order to disable the standard window glass.

Note that in general these WindowChrome settings do not have any visual effect; they only control behavior (the exception is GlassFrameThickness, which if set to a non-zero value will cause the windows glass to be displayed). It is up to us to match the WindowChrome settings to the visual dimensions of our custom chrome window.

Also note that when the WindowChrome class is applied to our window, it automatically sets WindowStyle="None" and ResizeMode to "NoResize", so we don't have to.

For more information about the WindowChrome class, refer to the MSDN documentation.

Fully Functional Custom Chrome Window

The final steps to completing our custom chrome window are:

  • Add the caption buttons using the pre-defined CaptionButtons user control, or individual CaptionButton controls if we want to customize the buttons.
  • Use the WindowIcon control to display the system menu when the icon is clicked, and close the window when the icon is double-clicked.
  • Derive the window from our own custom window base class that provides a property that correctly calculates the caption button margin when the window is maximized.

First the window and its XAML are presented, and after that the underlying code and supporting library are explained.

Window5.png

<ccl:CustomChromeWindow x:Class="CustomChromeSample.Window5"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:shell="http://schemas.microsoft.com/winfx/2006/xaml/presentation/shell"
        xmlns:ccl="clr-namespace:CustomChromeLibrary;assembly=CustomChromeLibrary"
		xmlns:local="clr-namespace:CustomChromeSample"
        Title="Custom Chrome Sample"
        Height="350" Width="525">

	<shell:WindowChrome.WindowChrome>
		<shell:WindowChrome
            ResizeBorderThickness="6"
            CaptionHeight="43"
            CornerRadius="25,25,10,10"
            GlassFrameThickness="0">
		</shell:WindowChrome>
	</shell:WindowChrome.WindowChrome>

	<Window.Resources>
		<ResourceDictionary>
			<local:CaptionButtonRectToMarginConverter
				x:Key="CaptionButtonMarginConverter"/>

			<ResourceDictionary.MergedDictionaries>
				<ResourceDictionary
				Source="Resources\GlassButton.xaml"/>
				<ResourceDictionary
				Source="Resources\GlassIcon.xaml"/>
			</ResourceDictionary.MergedDictionaries>
		</ResourceDictionary>
	</Window.Resources>

	<Grid>
		<Grid.ColumnDefinitions>
			<ColumnDefinition Width="*"/>
		</Grid.ColumnDefinitions>
		<Grid.RowDefinitions>
			<RowDefinition Height="auto" />
			<RowDefinition Height="*"/>
		</Grid.RowDefinitions>

		<!--provide the background for the entire form.
		In practice, this appears as the window's resize border,
		because the title and window content obscure the rest-->
		<Border CornerRadius="10,10,5,5" Grid.RowSpan="2"
			BorderThickness="3" BorderBrush="LightSteelBlue">
			<Border.Background>
				<LinearGradientBrush StartPoint="0.5,0"
				   EndPoint="0.5,1">
				   <GradientStop Color="#99bbbbff" Offset="0" />
				   <GradientStop Color="#ff7777bb" Offset="1" />
				</LinearGradientBrush>
			</Border.Background>
		</Border>

		<!--title bar-->
		<Border CornerRadius="10,10,0,0" BorderThickness="3,3,3,1"
			BorderBrush="LightSteelBlue"
			Margin="{Binding Path=CaptionButtonMargin}">
			<Border.Background>
				<LinearGradientBrush StartPoint="0.5,0"
				   EndPoint="0.5,1">
				   <GradientStop Color="#ffbbbbff" Offset="0" />
				   <GradientStop Color="#ff7777bb" Offset="1" />
				</LinearGradientBrush>
			</Border.Background>

			<!--Window Icon and Title-->
			<StackPanel Orientation="Horizontal" Margin="0"
				VerticalAlignment="Top">
				<ccl:WindowIcon Width="35" Height="35"
					Background="#ff0000bb"
					Margin="7,3,5,5"
					Style="{StaticResource GlassIcon}" />
				<TextBlock Text="Window 5 - Caption Buttons"
				FontFamily="Calibri" FontWeight="Bold" FontSize="26"
				Foreground="#FF000044" VerticalAlignment="Center"/>
			</StackPanel>
		</Border>

		<!--min/max/close buttons-->
		<ccl:CaptionButtons/>

		<!--Content-->
		<Grid Grid.Row="1">
			<TextBlock Grid.Row="1" Margin="10" FontFamily="Verdana"
				FontSize="14">
				Complete custom chrome with caption buttons.
			</TextBlock>
		</Grid>
	</Grid>
</ccl:CustomChromeWindow>

CustomChromeLibrary

The key to providing complete window functionality in a window with custom chrome is the CustomChromeLibrary. This library provides the following:

  • CaptionButton - Extends Button to provide dependency properties CornerRadius, HoverBackground, and PressedBackground. Serves as a base class for the minimize, maximize, close, and other caption buttons.
    • MinimizeButton
    • MaximizeButton
    • CloseButton
  • CaptionButtons - Combines MinimizeButton, MaximizeButton, and CloseButton into a standard grouping that can be conveniently included in custom chrome windows.
  • WindowIcon - Provides a wrapper for the window icon that displays the system menu when clicked, and closes the window when double-clicked.
  • CustomChromeWindow - Extends Window by adding CaptionButtonMargin, which provides adjusted margins for the caption buttons and window icon when the window is maximized.

Part 2 of this article will explain these classes and how to use them in greater detail.

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)

Share

About the Author

gbahns
Architect
United States United States
Greg has been working in software development in a variety of roles since 1990.

Comments and Discussions

 
QuestionThe outer frame became black PinprofessionalAnand Bakhal2-Mar-14 23:08 
QuestionI have made a modification. PinmemberPhillip Givens23-Nov-13 14:32 
I do not understand it, but when I maximize, part of my app draws outside of the area of the screen. I fixed it with the following code in CustomChromeWindow.OnStateChanged. I have not tested it on other computers.
 
protected override void OnStateChanged(EventArgs e)
{
    base.OnStateChanged(e);
    BorderThickness = (WindowState == System.Windows.WindowState.Maximized)
        ? new Thickness(8)
        : new Thickness();
    OnPropertyChanged("CaptionButtonMargin");
}
 
P.S. Thanks for this post. It was very helpful.
QuestionHidden taskbar PinmemberPiotr Zimniak31-Oct-13 23:55 
QuestionHow do you change the Caption button colors? Pinmemberrocky35982-Oct-13 17:04 
GeneralMy vote of 5 PinmemberCandyBeat9-Nov-12 6:46 
QuestionHow to enable controls inside the title bar area? PinmemberByron Salau15-Sep-12 22:39 
AnswerRe: How to enable controls inside the title bar area? PinmemberByron Salau16-Sep-12 3:03 
GeneralRe: How to enable controls inside the title bar area? PinmemberLGBBM26-Sep-14 17:30 
QuestionWindow flash when user drag border to resize. PinmemberGGGMM8-Aug-12 18:16 
GeneralNot hardware accelerated PinmemberMember 782792110-Apr-12 2:11 
GeneralRe: Not hardware accelerated Pinmembergbahns14-Apr-12 9:58 
GeneralRe: Not hardware accelerated Pinmemberkman13-Aug-14 14:36 
QuestionThx Pinmemberbboyse15-Mar-12 14:46 
GeneralMy vote of 4 Pinmembersureshkumar.y5-Feb-12 23:09 
QuestionExcellent PinmemberJuan J. Sáez29-Dec-11 2:25 
Bugcurrent issues PinmemberRangaswamy G17-Aug-11 0:26 
QuestionAdding glow to caption buttons and border shadow Pinmembercimframe8-Mar-11 12:20 
AnswerRe: Adding glow to caption buttons and border shadow Pinmembergbahns3-Jul-11 13:39 

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

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

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.141223.1 | Last Updated 3 Dec 2010
Article Copyright 2010 by gbahns
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid