Create custom windows in WPF with ease
Introduction
One of the features I wanted to add to Synergy toolkit was the ability to quickly create custom theme windows with all the features of a standard windows. In this article I am demonstrating how to create a custom window theme visually using declarative XAML and apply it to windows in your applications.
You can download Synergy SDK with full source code here.
You may also want to see my window docking solution
in Synergy here.
I will be posting updates on Synergy SDK on my
twitter account: MixModes
The sample application Synergy uses main window
as the custom window whose theme is defined within Windows.xaml resource
dictionary within MixModes.Synergy.Themes project.
Declarative is the key
As we all know XAML is declarative and simple and so there is no reason why traditional approach of writing code for windows and controls should apply. One must be able to simply create a visual and stick it in a control template to get things working. That was exactly my motivation when I started out developing look-less window functionality in Synergy.
Declare a template
The first thing you may want to do in creating a custom window is to actually create a visual template. The easiest way to create this template is to create a user control in Microsoft Blend and then define extension points in XAML that look-less control will liven up once the template is applied. Once the visual is ready all that needs to be done is a style creation for CustomWindow where the template can be pasted and then the temporary user control can be discarded.
Following extension points are supported for current implementation:
-
PART_TITLEBAR (UIElement) - For displaying window title, dragging and maximize / restore operations
-
PART_MINIMIZE (Button) – Window minimize button
-
PART_MAXIMIZE_RESTORE (Button) – Maximize restore button
-
PART_CLOSE (Button) – Close button
-
PART_LEFT_BORDER (UIElement) – Left resizable border
-
PART_RIGHT_BORDER (UIElement) – Right resizable border
-
PART_TOP_BORDER (UIElement) – Top resizable border
-
PART_BOTTOM_BORDER (UIElement) – Bottom resizable border
One more thing to note is that while defining the window template, you must declare the ContentPresenter (which ultimately contains window content) within AdornerDecorator tag (which is the adorner layer for the window) as this is WPF requirement.
Here is the template I have created within Windows.xaml resource dictionary within MixModes.Synergy.Themes project:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="MainWindow"
TargetType="{x:Type
Window}">
<Setter Property="Foreground"
Value="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type
Window}">
<Grid>
<Border x:Name="MainBorder"
BorderBrush="{DynamicResource MainWindowBorderBrush}"
BorderThickness="1"
CornerRadius="2"
Background="{DynamicResource
MainWindowBackgroundBrush}">
<DockPanel
LastChildFill="True">
<Rectangle
x:Name="PART_LEFT_BORDER"
Width="2"
Cursor="SizeWE">
<Rectangle.Fill>
<SolidColorBrush
Color="Transparent" />
</Rectangle.Fill>
</Rectangle>
<Rectangle x:Name="PART_RIGHT_BORDER"
Cursor="SizeWE"
Width="2"
DockPanel.Dock="Right">
<Rectangle.Fill>
<SolidColorBrush
Color="Transparent" />
</Rectangle.Fill>
</Rectangle>
<Rectangle x:Name="PART_TOP_BORDER"
Cursor="SizeNS"
DockPanel.Dock="Top"
Height="2">
<Rectangle.Fill>
<SolidColorBrush
Color="Transparent" />
</Rectangle.Fill>
</Rectangle>
<Rectangle x:Name="PART_BOTTOM_BORDER"
Cursor="SizeNS"
Height="2"
DockPanel.Dock="Bottom">
<Rectangle.Fill>
<SolidColorBrush
Color="Transparent" />
</Rectangle.Fill>
</Rectangle>
<Border x:Name="PART_TITLEBAR"
Margin="2,0,2,2"
Height="40"
DockPanel.Dock="Top"
CornerRadius="2"
Background="Transparent">
<DockPanel LastChildFill="False">
<TextBlock Margin="8,0,0,4"
VerticalAlignment="Center"
FontStretch="UltraExpanded"
Foreground="Black"
TextTrimming="CharacterEllipsis"
TextWrapping="NoWrap"
Text="{TemplateBinding
Title}"
FontSize="16"
/>
<Button x:Name="PART_CLOSE"
DockPanel.Dock="Right"
Style="{DynamicResource
FlatButton}"
VerticalAlignment="Center"
Margin="0,0,4,0">
<Image
Source="/MixModes.Synergy.Resources;component/Resources/Close.png"
Stretch="None"
Margin="4" />
</Button>
<Button
x:Name="PART_MAXIMIZE_RESTORE"
DockPanel.Dock="Right"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Style="{DynamicResource
FlatButton}">
<Image
x:Name="MaximizeRestoreImage"
Source="/MixModes.Synergy.Resources;component/Resources/Restore.png"
Stretch="None"
Margin="4" />
</Button>
<Button x:Name="PART_MINIMIZE"
HorizontalAlignment="Center"
Style="{DynamicResource
FlatButton}"
VerticalAlignment="Center"
DockPanel.Dock="Right">
<Image Margin="4"
Source="/MixModes.Synergy.Resources;component/Resources/Minimize.png"
Stretch="None" />
</Button>
</DockPanel>
</Border>
<!-- Title bar separator-->
<Border Height="1"
DockPanel.Dock="Top"
Background="{DynamicResource
MainWindowTitleBarSeparator}" />
<!-- Actual Window Content -->
<AdornerDecorator
DockPanel.Dock="Bottom">
<ContentPresenter />
</AdornerDecorator>
</DockPanel>
</Border>
</Grid>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding
RelativeSource={RelativeSource Self}, Path=Maximized}"
Value="False">
<Setter TargetName="MaximizeRestoreImage"
Property="Source"
Value="/MixModes.Synergy.Resources;component/Resources/Maximize.png" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
This is a pretty simple theme which creates a rounded rectangle window with 2 pixel wide resizers and custom window minimize, maximize and restore buttons. It also contains a template trigger that changes the image of maximize restore button if window is not maximized.
The window created using this theme looks like the following:
The final step is to inherit from CustomWindow class (which in turn inherits from Window class) instead of directly inheriting from Window class and refer to the style created in the previous step. This is again very simple:
-
Import visual framework namespace:
xmlns:visualFx="http://mixmodes.com/visualFx" -
Inherit from CustomWindow class:
use “visualFx:CustomWindow” as your window tag in XAML -
Refer to the style created in previous step in your visualFx:CustomWindow tag:
Style="{DynamicResource MainWindow}"
That’s all you have to do to get your custom window working !
How does it work?
If you crack open the CustomWindow class you will see that bulk
of the work happens in the AttachToVisualTree method which is called from
OnApplyTemplate (which in turn is called anytime template is applied to our
custom window).
AttachToVisualTree in turn calls AttachCloseButton,
AttachMaximizeButton, AttachMaximizeRestoreButton, AttachTitleBar and
AttachBorders methods, each of which queries for visual parts (the PART_… named
parts we defined in the template) and attaches functionality via events.
So that’s it ! Creating custom windows using Synergy is really that simple !
Post Comment
Very informative blog post.Really looking forward to read more. Cool.
My blog site is in the exact same niche as yours and my visitors would definitely benefit from some of the information you provide here.
IaаАабТТаЂааАабТТаБТm a lengthy time watcher and I just considered IaаАабТТаЂааАабТТаБТd drop by and say hi there for the very very first time.
Wow, superb blog layout! How long have you been blogging for? you make blogging look easy. The overall look of your site is great, as well as the content!
Very nice article and straight to the point. I don at know if this is in fact the best place to ask but do you people have any thoughts on where to employ some professional writers? Thx
Looking forward to reading more. Great blog article. Much obliged.
Usually I don at read post on blogs, but I wish to say that this write-up very forced me to take a look at and do so! Your writing taste has been amazed me. Thanks, very great post.
Some really select content on this internet site , saved to bookmarks.
There is evidently a bunch to realize about this. I consider you made various nice points in features also.
Really enjoyed this article post.Really looking forward to read more. Awesome.
Some times its a pain in the ass to read what people wrote but this site is real user friendly !.
This particular blog is definitely cool and also factual. I have picked a bunch of helpful things out of this blog. I ad love to return again and again. Thanks a bunch!
I similar to Your Write-up about Khmer Karaoke Celebrities
Looking forward to reading more. Great post.Much thanks again. Much obliged.
I value the article.Thanks Again. Awesome.
You could definitely see your skills in the paintings you write. The world hopes for more passionate writers such as you who aren at afraid to mention how they believe. All the time follow your heart.
There is apparently a bundle to know about this. I suppose you made certain good points in features also.
topic. I needs to spend some time learning more
Really appreciate you sharing this article.Much thanks again. Keep writing.
This is a really good tip particularly to those fresh to the blogosphere. Short but very accurate info Appreciate your sharing this one. A must read article!
Im no expert, but I suppose you just crafted an excellent point. You clearly comprehend what youre talking about, and I can really get behind that. Thanks for being so upfront and so truthful.
Simply wanna input that you have a very decent website , I like the style and design it actually stands out.
Wow, great blog article.Thanks Again. Fantastic.
Pretty part of content. I simply stumbled upon your
Thank you ever so for you blog article.Much thanks again. Awesome.
Thanks for the article post.Really thank you!
Thanks-a-mundo for the article post.Really looking forward to read more. Awesome.
This excellent website certainly has all the info I wanted about this subject and didn at know who to ask.
You made some good points there. I checked on the net for more information about the issue and found most individuals will go along with your views on this site.
I think you have mentioned some very interesting points, thankyou for the post.
Wow, superb blog layout! How long have you been blogging for? you make blogging look easy. The overall look of your web site is magnificent, let alone the content!
This is one awesome post.Really looking forward to read more. Much obliged.
Way cool! Some extremely valid points! I appreciate you penning this article plus the rest of the site is really
Normally I do not learn post on blogs, however I wish to say that this write-up very pressured me to take a look at and do it! Your writing style has been surprised me. Thanks, very great article.
eVTdJE I regard something truly special in this internet site.
You have remarked very interesting details ! ps decent site. I didn at attend the funeral, but I sent a nice letter saying that I approved of it. by Mark Twain.
It as not all on Vince. Folks about him ended up stealing his money. Also when you feel his professional career is more than, you are an idiot.
I will also like to express that most individuals that find themselves without having health insurance can be students, self-employed and those that are not working.
we came across a cool site that you simply may well take pleasure in. Take a appear should you want
This blog is definitely entertaining additionally informative. I have picked a lot of helpful stuff out of it. I ad love to visit it again soon. Cheers!
You completed various nice points there. I did a search on the subject matter and found a good number of persons will agree with your blog.
Valuable Website I have been checking out some of your posts and i can claim clever stuff. I will definitely bookmark your blog.
I value the blog post.Really looking forward to read more.
very handful of websites that occur to become comprehensive beneath, from our point of view are undoubtedly effectively really worth checking out
Whoa! This blog looks exactly like my old one! It as on a entirely different topic but it has pretty much the same page layout and design. Outstanding choice of colors!
It as nearly impossible to find well-informed people on this topic, however, you sound like you know what you are talking about! Thanks
Thank you ever so for you blog article.Thanks Again. Much obliged.
I was suggested this web site by my cousin. I am not sure whether this post is written by him as nobody else know such detailed about my difficulty. You are incredible! Thanks!
wow, awesome article post.Much thanks again. Awesome.
I think this is a real great post. Great.