Click here to Skip to main content
15,868,034 members
Articles / Desktop Programming / WPF

WPF Custom Chrome Library

Rate me:
Please Sign up or sign in to vote.
4.78/5 (32 votes)
3 Dec 2010Ms-PL4 min read 157.1K   12.9K   87   24
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:

XML
<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:

XML
<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:

XML
<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

XML
<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)


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

Comments and Discussions

 
QuestionMaximized Covering Taskbar Pin
Kriangkrai Saengkantha29-Apr-19 1:06
Kriangkrai Saengkantha29-Apr-19 1:06 
GeneralMy vote of 5 Pin
JamesFaix16-Nov-16 7:30
JamesFaix16-Nov-16 7:30 
GeneralThank you, great work Pin
wwwx2-Mar-16 22:30
wwwx2-Mar-16 22:30 
GeneralThanks for the post Pin
Torsten Tiedt7-Jun-15 0:29
Torsten Tiedt7-Jun-15 0:29 
GeneralThanks for the post Pin
Torsten Tiedt7-Jun-15 0:29
Torsten Tiedt7-Jun-15 0:29 
QuestionThe outer frame became black Pin
Anand Bakhal2-Mar-14 22:08
professionalAnand Bakhal2-Mar-14 22:08 
QuestionI have made a modification. Pin
Phillip Givens23-Nov-13 13:32
Phillip Givens23-Nov-13 13:32 
AnswerRe: I have made a modification. Pin
RogerRamjetRogerRamjet8-Apr-16 21:20
RogerRamjetRogerRamjet8-Apr-16 21:20 
QuestionHidden taskbar Pin
Piotr Zimniak31-Oct-13 22:55
Piotr Zimniak31-Oct-13 22:55 
QuestionHow do you change the Caption button colors? Pin
rocky35982-Oct-13 16:04
rocky35982-Oct-13 16:04 
GeneralMy vote of 5 Pin
SuperJMN-CandyBeat9-Nov-12 5:46
SuperJMN-CandyBeat9-Nov-12 5:46 
QuestionHow to enable controls inside the title bar area? Pin
Byron Salau15-Sep-12 21:39
Byron Salau15-Sep-12 21:39 
AnswerRe: How to enable controls inside the title bar area? Pin
Byron Salau16-Sep-12 2:03
Byron Salau16-Sep-12 2:03 
GeneralRe: How to enable controls inside the title bar area? Pin
LGBBM26-Sep-14 16:30
LGBBM26-Sep-14 16:30 
QuestionWindow flash when user drag border to resize. Pin
GGGMM8-Aug-12 17:16
GGGMM8-Aug-12 17:16 
GeneralNot hardware accelerated Pin
GoaZwerg10-Apr-12 1:11
GoaZwerg10-Apr-12 1:11 
The problem with WindowStyle = none is that afaik your complete window including all elements will be rendered in software then which decreases the performance.
GeneralRe: Not hardware accelerated Pin
gbahns14-Apr-12 8:58
gbahns14-Apr-12 8:58 
GeneralRe: Not hardware accelerated Pin
kman13-Aug-14 13:36
kman13-Aug-14 13:36 
QuestionThx Pin
bboyse15-Mar-12 13:46
bboyse15-Mar-12 13:46 
GeneralMy vote of 4 Pin
sureshkumar.y5-Feb-12 22:09
sureshkumar.y5-Feb-12 22:09 
QuestionExcellent Pin
Juan J. Sáez29-Dec-11 1:25
Juan J. Sáez29-Dec-11 1:25 
Bugcurrent issues Pin
ragang16-Aug-11 23:26
ragang16-Aug-11 23:26 
QuestionAdding glow to caption buttons and border shadow Pin
cimframe8-Mar-11 11:20
cimframe8-Mar-11 11:20 
AnswerRe: Adding glow to caption buttons and border shadow Pin
gbahns3-Jul-11 12:39
gbahns3-Jul-11 12:39 

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

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