Here is what you will end up with, looks like a window doesn't it? But you can customize every aspect of it.
Create a new project of type
Class Library named CustomControls.
CustomWindow.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Interop;
using System.Runtime.InteropServices;
namespace CustomControls
{
public partial class CustomWindow : Window
{
#region Click events
protected void MinimizeClick(object sender, RoutedEventArgs e)
{
WindowState = WindowState.Minimized;
}
protected void RestoreClick(object sender, RoutedEventArgs e)
{
WindowState = (WindowState == WindowState.Normal) ? WindowState.Maximized : WindowState.Normal;
}
protected virtual void CloseClick(object sender, RoutedEventArgs e)
{
Close();
}
#endregion
static CustomWindow()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomWindow),
new FrameworkPropertyMetadata(typeof(CustomWindow)));
}
public CustomWindow()
: base()
{
PreviewMouseMove += OnPreviewMouseMove;
}
private HwndSource _hwndSource;
protected override void OnInitialized(EventArgs e)
{
SourceInitialized += OnSourceInitialized;
base.OnInitialized(e);
}
private void OnSourceInitialized(object sender, EventArgs e)
{
_hwndSource = (HwndSource)PresentationSource.FromVisual(this);
}
public override void OnApplyTemplate()
{
Rectangle moveRectangle = GetTemplateChild("moveRectangle") as Rectangle;
if (moveRectangle != null)
moveRectangle.PreviewMouseDown += moveRectangle_PreviewMouseDown;
Button minimizeButton = GetTemplateChild("minimizeButton") as Button;
if (minimizeButton != null)
minimizeButton.Click += MinimizeClick;
Button restoreButton = GetTemplateChild("restoreButton") as Button;
if (restoreButton != null)
restoreButton.Click += RestoreClick;
Button closeButton = GetTemplateChild("closeButton") as Button;
if (closeButton != null)
closeButton.Click += CloseClick;
Grid resizeGrid = GetTemplateChild("resizeGrid") as Grid;
if (resizeGrid != null)
{
foreach (UIElement element in resizeGrid.Children)
{
Rectangle resizeRectangle = element as Rectangle;
if (resizeRectangle != null)
{
resizeRectangle.PreviewMouseDown += ResizeRectangle_PreviewMouseDown;
resizeRectangle.MouseMove += ResizeRectangle_MouseMove;
}
}
}
base.OnApplyTemplate();
}
protected void ResizeRectangle_MouseMove(Object sender, MouseEventArgs e)
{
Rectangle rectangle = sender as Rectangle;
switch (rectangle.Name)
{
case "top":
Cursor = Cursors.SizeNS;
break;
case "bottom":
Cursor = Cursors.SizeNS;
break;
case "left":
Cursor = Cursors.SizeWE;
break;
case "right":
Cursor = Cursors.SizeWE;
break;
case "topLeft":
Cursor = Cursors.SizeNWSE;
break;
case "topRight":
Cursor = Cursors.SizeNESW;
break;
case "bottomLeft":
Cursor = Cursors.SizeNESW;
break;
case "bottomRight":
Cursor = Cursors.SizeNWSE;
break;
default:
break;
}
}
private void moveRectangle_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
if (Mouse.LeftButton == MouseButtonState.Pressed)
DragMove();
}
protected void OnPreviewMouseMove(object sender, MouseEventArgs e)
{
if (Mouse.LeftButton != MouseButtonState.Pressed)
Cursor = Cursors.Arrow;
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, UInt32 msg, IntPtr wParam, IntPtr lParam);
protected void ResizeRectangle_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
Rectangle rectangle = sender as Rectangle;
switch (rectangle.Name)
{
case "top":
Cursor = Cursors.SizeNS;
ResizeWindow(ResizeDirection.Top);
break;
case "bottom":
Cursor = Cursors.SizeNS;
ResizeWindow(ResizeDirection.Bottom);
break;
case "left":
Cursor = Cursors.SizeWE;
ResizeWindow(ResizeDirection.Left);
break;
case "right":
Cursor = Cursors.SizeWE;
ResizeWindow(ResizeDirection.Right);
break;
case "topLeft":
Cursor = Cursors.SizeNWSE;
ResizeWindow(ResizeDirection.TopLeft);
break;
case "topRight":
Cursor = Cursors.SizeNESW;
ResizeWindow(ResizeDirection.TopRight);
break;
case "bottomLeft":
Cursor = Cursors.SizeNESW;
ResizeWindow(ResizeDirection.BottomLeft);
break;
case "bottomRight":
Cursor = Cursors.SizeNWSE;
ResizeWindow(ResizeDirection.BottomRight);
break;
default:
break;
}
}
private void ResizeWindow(ResizeDirection direction)
{
SendMessage(_hwndSource.Handle, 0x112, (IntPtr)(61440 + direction), IntPtr.Zero);
}
private enum ResizeDirection
{
Left = 1,
Right = 2,
Top = 3,
TopLeft = 4,
TopRight = 5,
Bottom = 6,
BottomLeft = 7,
BottomRight = 8,
}
}
}
Themes\Generic.xaml
<resourcedictionary xmlns:local="clr-namespace:CustomControls" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<!-- Window Button style -->
<style targettype="{x:Type Button}" x:key="WindowButtonStyle">
<setter Property="Background" Value="Transparent"/>
<setter Property="Foreground" Value="{DynamicResource GreyLightBrush}" />
<setter Property="BorderBrush" Value="{DynamicResource BorderBrush}"/>
<setter Property="FontFamily" Value="Webdings"/>
<setter Property="FontSize" Value="13.333" />
<setter Property="Margin" Value="1,1,1,0"/>
<setter Property="Template">
<Setter.Value>
<controltemplate TargetType="{x:Type ButtonBase}">
<border x:Name="Chrome"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
Margin="0"
SnapsToDevicePixels="True">
<ContentPresenter
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
ContentStringFormat="{TemplateBinding ContentStringFormat}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<trigger Property="IsMouseOver" Value="True">
<setter Property="Foreground" Value="{DynamicResource WhiteBrush}" />
</Trigger>
</Style.Triggers>
</style>
<!-- Window style -->
<style targettype="{x:Type local:CustomWindow}">
<setter Property="WindowStyle" Value="None"/>
<setter Property="ResizeMode" Value="NoResize"/>
<setter Property="Foreground" Value="{DynamicResource ForegroundBrush}" />
<setter Property="Background" Value="{DynamicResource BackgroundBrush}"/>
<setter Property="BorderBrush" Value="{DynamicResource BorderBrush}"/>
<setter Property="BorderThickness" Value="1"/>
<setter Property="Template">
<Setter.Value>
<controltemplate TargetType="{x:Type local:CustomWindow}">
<border BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}">
<grid>
<grid>
<Grid.RowDefinitions>
<rowdefinition Height="Auto"/>
<rowdefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<columndefinition />
<columndefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<rectangle x:Name="moveRectangle" Fill="Transparent" Grid.Row="0" Grid.Column="0"/>
<textblock x:Name="windowTitle" Margin="10 0"
FontSize="16"
Grid.Column="0" Grid.Row="0" Panel.ZIndex="-1"
Foreground="{DynamicResource GreyLightBrush}"
Text="{TemplateBinding Title}"/>
<stackpanel Grid.Row="0" Grid.Column="1" Orientation="Horizontal">
<button x:Name="minimizeButton" Style="{StaticResource WindowButtonStyle}"
Content="0" />
<button x:Name="restoreButton" Style="{StaticResource WindowButtonStyle}"
Content="1" />
<button x:Name="closeButton" Style="{StaticResource WindowButtonStyle}"
Content="r" />
</StackPanel>
<grid Background="{TemplateBinding Background}"
Grid.Row="1" Grid.ColumnSpan="2" Margin="5,5,5,5">
<adornerdecorator>
<ContentPresenter/>
</AdornerDecorator>
</Grid>
</Grid>
<grid x:Name="resizeGrid">
<Rectangle
Stroke="{x:Null}"
Fill="Transparent"
VerticalAlignment="Top"
Height="5"
x:Name="top"
Margin="5,0,5,0" />
<Rectangle
Stroke="{x:Null}"
Fill="Transparent"
x:Name="bottom"
Height="5"
VerticalAlignment="Bottom"
Margin="5,0,5,0" />
<Rectangle
Stroke="{x:Null}"
Fill="Transparent"
HorizontalAlignment="Left"
Margin="0,5,0,5"
Width="5"
x:Name="left"/>
<Rectangle
Stroke="{x:Null}"
Fill="Transparent"
Margin="0,5,0,5"
Width="5"
HorizontalAlignment="Right"
x:Name="right" />
<Rectangle
Stroke="{x:Null}"
Fill="Transparent"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Width="5"
Height="5"
x:Name="bottomLeft" />
<Rectangle
Stroke="{x:Null}"
Fill="Transparent"
VerticalAlignment="Bottom"
Height="5"
Width="5"
HorizontalAlignment="Right"
x:Name="bottomRight" />
<Rectangle
Stroke="{x:Null}"
Fill="Transparent"
HorizontalAlignment="Right"
Width="5"
Height="5"
VerticalAlignment="Top"
x:Name="topRight" />
<Rectangle
Stroke="{x:Null}"
Fill="Transparent"
HorizontalAlignment="Left"
Width="6"
VerticalAlignment="Top"
Height="5"
x:Name="topLeft" />
</Grid>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</style>
</resourcedictionary>
Now you can include this custom controls project as a reference in whichever project you want to use the custom window. After adding it as a reference, here is how to implement it, very simple!
MainWindow.xaml
<control:customwindow height="350" title="MainWindow" width="525"
x:class="YourApp.MainWindow"
xmlns:control="clr-namespace:CustomControls;assembly=CustomControls"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<grid>
</grid>
</control:customwindow>
And in the code behind we inherit from our custom class:
MainWindow.xaml.cs
public partial class MainWindow : CustomControls.CustomWindow
{
public MainWindow()
{
InitializeComponent();
}
}