一个WPF自定义窗体的例子,我封装成一个WPF自定义控件库
新建的Window窗体继承XianJian.Controls.Window,如下:
可以设置窗体的背景样式,可以是绿色,蓝色或使用背景图片。
运行效果:
以下代码:
Window.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="WindowStyle" TargetType="Window">
<Setter Property="AllowsTransparency" Value="True"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="WindowStyle" Value="None"/>
</Style>
<ControlTemplate x:Key="WindowTemplate" TargetType="Window">
<!--若不设置margin,阴影无法显示(被挡住了)-->
<Border x:Name="FussWindowBorder" CornerRadius="5" Margin="8" Background="White" BorderBrush="#6A6A6A" BorderThickness="1" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" >
<Border.Effect>
<DropShadowEffect BlurRadius="8" ShadowDepth="0" Color="#00000000"/>
</Border.Effect>
<Border x:Name="BorderBack" CornerRadius="5">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Border Name="TitleBar" Height="25" CornerRadius="5">
<DockPanel Margin="0">
<Image DockPanel.Dock="Left" Name="ImgApp" VerticalAlignment="Top" Margin="10 5 0 0" Width="20" Height="20"></Image>
<TextBlock DockPanel.Dock="Left" Name="TitleText" VerticalAlignment="Top" Margin="2 5 0 0" FontSize="14" FontWeight="Bold" Foreground="#101010"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" DockPanel.Dock="Right" Height="25" VerticalAlignment="Top">
<Rectangle Style="{DynamicResource Splitter}"/>
<Button Name="MiniButton" Width="30" Template="{DynamicResource MiniButton}"/>
<Rectangle Style="{DynamicResource Splitter}"/>
<Button Name="MaxButton" Width="30" Style="{DynamicResource WinNormalButton}"/>
<Rectangle Name="MaxSplitter" Style="{DynamicResource Splitter}"/>
<Button Name="CloseButton" Width="35" Style="{DynamicResource CloseButton}"/>
</StackPanel>
</DockPanel>
</Border>
<AdornerDecorator Grid.Row="1" Height="Auto" Width="Auto">
<ContentPresenter/>
</AdornerDecorator>
</Grid>
</Border>
</Border>
</ControlTemplate>
<Style x:Key="BackStyleWhite" TargetType="Border">
<Setter Property="Background" Value="White"></Setter>
</Style>
<Style x:Key="BackStyleImage" TargetType="Border">
<Setter Property="Background" Value="Transparent"></Setter>
</Style>
<Style x:Key="HeadStyleGreen" TargetType="Border">
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<GradientStop Color="#29B9AC" Offset="0.3"/>
<GradientStop Color="#00FFFFFF" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="HeadStyleBlue" TargetType="Border">
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<GradientStop Color="#431EC2" Offset="0.3"/>
<GradientStop Color="#00FFFFFF" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="HeadStyleTransparent" TargetType="Border">
<Setter Property="Background" Value="Transparent"></Setter>
</Style>
<Style x:Key="Splitter" TargetType="Rectangle">
<Setter Property="Width" Value="1"/>
<Setter Property="Stroke" Value="Transparent"/>
<Setter Property="StrokeThickness" Value="0"/>
<Setter Property="Fill">
<Setter.Value>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<LinearGradientBrush.GradientStops>
<GradientStop Color="#FF000000" Offset="0"/>
<GradientStop Color="#80000000" Offset="0.6"/>
<GradientStop Color="#00000000" Offset="1.0"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>
<LinearGradientBrush x:Key="MinMaxBrush" StartPoint="0.5,0" EndPoint="0.5,1">
<LinearGradientBrush.GradientStops>
<GradientStop Color="#F0FFFFFF" Offset="0"/>
<GradientStop Color="#00FFFFFF" Offset="1"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="MinMaxPressedBrush" StartPoint="0.5,0" EndPoint="0.5,1">
<LinearGradientBrush.GradientStops>
<GradientStop Color="#E0BBBBBB" Offset="0"/>
<GradientStop Color="#00BBBBBB" Offset="1"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<DrawingBrush x:Key="CloseButtonBrush">
<DrawingBrush.Drawing>
<GeometryDrawing Geometry="M 36.0396,7.62939e-006L -6.10352e-005,7.62939e-006L -6.10352e-005,25L 39.9999,25L 39.9999,3.90626C 39.9999,1.74885 38.2269,7.62939e-006 36.0396,7.62939e-006 Z ">
<GeometryDrawing.Brush>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<LinearGradientBrush.GradientStops>
<GradientStop Color="#FFFF0000" Offset="0"/>
<GradientStop Color="#00FF0000" Offset="1"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</GeometryDrawing.Brush>
</GeometryDrawing>
</DrawingBrush.Drawing>
</DrawingBrush>
<DrawingBrush x:Key="CloseButtonPressBrush">
<DrawingBrush.Drawing>
<GeometryDrawing Geometry="M 36.0396,7.62939e-006L -6.10352e-005,7.62939e-006L -6.10352e-005,25L 39.9999,25L 39.9999,3.90626C 39.9999,1.74885 38.2269,7.62939e-006 36.0396,7.62939e-006 Z ">
<GeometryDrawing.Brush>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<LinearGradientBrush.GradientStops>
<GradientStop Color="#FF5A022F" Offset="0"/>
<GradientStop Color="#005A022F" Offset="1"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</GeometryDrawing.Brush>
</GeometryDrawing>
</DrawingBrush.Drawing>
</DrawingBrush>
<ControlTemplate x:Key="MiniButton" TargetType="Button">
<!--一定要初始化Grid的Background属性-->
<Grid x:Name="MiniGrid" Background="Transparent">
<Path Data="F1 M 14.7587,4.59057L 0.5,4.59057L 0.5,0.499992L 14.7587,0.499992L 14.7587,4.59057 Z "
Fill="#FFFCFCFD" StrokeLineJoin="Round" Stroke="#FF4A4B4D" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0 5 0 0" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" TargetName="MiniGrid" Value="{StaticResource MinMaxBrush}"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" TargetName="MiniGrid" Value="{StaticResource MinMaxPressedBrush}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style x:Key="WinMaxButton" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid x:Name="MaxButton" Background="Transparent">
<Canvas Width="15" Height="15" VerticalAlignment="Center" HorizontalAlignment="Center" >
<Canvas.Background>
<DrawingBrush>
<DrawingBrush.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="#FFFCFCFD" Geometry="M 3.06549,0.500031L 15.5,0.500031L 15.5,12.9346L 12.4866,12.9346L 12.4866,3.6337L 3.06549,3.6337L 3.06549,0.500031 Z ">
<GeometryDrawing.Pen>
<Pen LineJoin="Round" Brush="#FF040404"/>
</GeometryDrawing.Pen>
</GeometryDrawing>
<GeometryDrawing Brush="#FFFCFCFD" Geometry="M 0.5,3.06546L 12.9345,3.06546L 12.9345,15.5L 0.5,15.5L 0.5,3.06546 Z M 3.60864,6.1741L 3.60864,12.3914L 9.82587,12.3914L 9.82587,6.1741L 3.60864,6.1741 Z ">
<GeometryDrawing.Pen>
<Pen LineJoin="Round" Brush="#FF040404"/>
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Canvas.Background>
</Canvas>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" TargetName="MaxButton" Value="{StaticResource MinMaxBrush}"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" TargetName="MaxButton" Value="{StaticResource MinMaxPressedBrush}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="WinNormalButton" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid x:Name="MaxButton" Background="Transparent">
<Canvas Width="15" Height="15" VerticalAlignment="Center" HorizontalAlignment="Center" >
<Canvas.Background>
<DrawingBrush>
<DrawingBrush.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="#FFFCFCFD" Geometry="M 0.5,3.06546L 12.9345,3.06546L 12.9345,15.5L 0.5,15.5L 0.5,3.06546 Z M 3.60864,6.1741L 3.60864,12.3914L 9.82587,12.3914L 9.82587,6.1741L 3.60864,6.1741 Z ">
<GeometryDrawing.Pen>
<Pen LineJoin="Round" Brush="#FF040404"/>
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Canvas.Background>
</Canvas>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" TargetName="MaxButton" Value="{StaticResource MinMaxBrush}"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" TargetName="MaxButton" Value="{StaticResource MinMaxPressedBrush}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="CloseButton" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid x:Name="CloseGrid" Background="Transparent">
<Path Data="F1 M 8,3.21448L 6.02069,0.5L 0.507629,0.5L 5.24347,6.99478L 0.5,13.5L 6.013,13.5L 8,10.7751L 9.987,13.5L 15.5,13.5L 10.7565,6.99478L 15.4924,0.5L 9.97937,0.5L 8,3.21448 Z "
Fill="#FFFCFCFD" StrokeLineJoin="Round" Stroke="#FF4A4B4D" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" TargetName="CloseGrid" Value="{StaticResource CloseButtonBrush}"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" TargetName="CloseGrid" Value="{StaticResource CloseButtonPressBrush}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Window.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace XianJian.Controls
{
/// <summary>
/// 自定义窗口
/// </summary>
public class Window : System.Windows.Window
{
private readonly ResourceDictionary mWindowResouce = new ResourceDictionary();
private readonly ControlTemplate mTemplate;
private const int WM_NCHITTEST = 0x0084;
private const int WM_GETMINMAXINFO = 0x0024;
private const int CORNER_WIDTH = 12; //拐角宽度
private const int MARGIN_WIDTH = 4; // 边框宽度
private Point mMousePoint = new Point(); //鼠标坐标
private Button mMaxButton;
private bool mIsShowMax = true;
/// <summary>
/// 是否显示最大化按钮
/// </summary>
public bool IsShowMax
{
get
{
return mIsShowMax;
}
set
{
mIsShowMax = value;
}
}
private BackGroundType mBackGroundType;
/// <summary>
/// 背景类型
/// </summary>
public BackGroundType BackGroundType
{
get
{
return mBackGroundType;
}
set
{
mBackGroundType = value;
}
}
private ImageSource mBackImage;
/// <summary>
/// 背景图片
/// </summary>
public ImageSource BackImage
{
get
{
return mBackImage;
}
set
{
mBackImage = value;
}
}
/// <summary>
/// 窗口
/// </summary>
public Window()
{
mWindowResouce.Source = new Uri("XJControls;component/Themes/Window.xaml", UriKind.Relative);
this.Resources.MergedDictionaries.Add(mWindowResouce);
this.Style = (Style)mWindowResouce["WindowStyle"];
var windowTemplate = (ControlTemplate)mWindowResouce["WindowTemplate"];
this.Template = windowTemplate;
mTemplate = windowTemplate;
this.Loaded += new RoutedEventHandler(WindowBase_Loaded);
this.MaxWidth = SystemParameters.MaximizedPrimaryScreenWidth;
this.MaxHeight = SystemParameters.MaximizedPrimaryScreenHeight;
mBackGroundType = BackGroundType.Blue;
}
private void WindowBase_Loaded(object sender, RoutedEventArgs e)
{
((Border)mTemplate.FindName("FussWindowBorder", this)).MouseLeftButtonDown += (s1, e1) => this.DragMove();
((TextBlock)mTemplate.FindName("TitleText", this)).Text = this.Title;
((Image)mTemplate.FindName("ImgApp", this)).Source = this.Icon;
var backBorder = (Border)mTemplate.FindName("BorderBack", this);
var headBorder = (Border)mTemplate.FindName("TitleBar", this);
switch (mBackGroundType)
{
case BackGroundType.Green:
backBorder.Style = (Style)mWindowResouce["BackStyleWhite"];
headBorder.Style = (Style)mWindowResouce["HeadStyleGreen"];
break;
case BackGroundType.Blue:
backBorder.Style = (Style)mWindowResouce["BackStyleWhite"];
headBorder.Style = (Style)mWindowResouce["HeadStyleBlue"];
break;
case BackGroundType.Image:
backBorder.Style = (Style)mWindowResouce["BackStyleImage"];
backBorder.Background = new ImageBrush(mBackImage);
headBorder.Style = (Style)mWindowResouce["HeadStyleTransparent"];
break;
default:
backBorder.Style = (Style)mWindowResouce["BackStyleWhite"];
headBorder.Style = (Style)mWindowResouce["HeadStyleGreen"];
break;
}
mMaxButton = (Button)mTemplate.FindName("MaxButton", this);
if (!IsShowMax)
{
mMaxButton.Visibility = Visibility.Collapsed;
var rectangle = mTemplate.FindName("MaxSplitter", this) as Rectangle;
if (rectangle != null)
rectangle.Visibility = Visibility.Collapsed;
}
else mMaxButton.Visibility = Visibility.Visible;
this.SizeChanged += (s1, e1) =>
{
if (this.WindowState == WindowState.Normal)
{
mMaxButton.Style = (Style)mWindowResouce["WinNormalButton"];
}
else if (mMaxButton.Style != (Style)mWindowResouce["WinMaxButton"]
&& this.WindowState == WindowState.Maximized)
{
mMaxButton.Style = (Style)mWindowResouce["WinMaxButton"];
}
};
((Button)mTemplate.FindName("MiniButton", this)).Click += (s2, e2) =>
{
this.WindowState = WindowState.Minimized;
};
mMaxButton.Click += (s3, e3) =>
{
this.WindowState = (this.WindowState == WindowState.Normal) ? WindowState.Maximized : WindowState.Normal;
};
((Button)mTemplate.FindName("CloseButton", this)).Click += (s4, e4) => this.Close();
var hwndSource = PresentationSource.FromVisual(this) as HwndSource;
if (hwndSource != null)
{
hwndSource.AddHook(new HwndSourceHook(WndProc));
}
}
/// <summary>
/// 窗口消息
/// </summary>
/// <param name="hwnd"></param>
/// <param name="msg"></param>
/// <param name="wParam"></param>
/// <param name="lParam"></param>
/// <param name="handled"></param>
/// <returns></returns>
protected virtual IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch (msg)
{
case WM_NCHITTEST:
mMousePoint.X = (lParam.ToInt32() & 0xFFFF);
mMousePoint.Y = (lParam.ToInt32() >> 16);
handled = true;
//窗体为最大化时(如果最大化,Left、Top属性都会造成影响)
if (this.WindowState == WindowState.Normal)
{
#region 拖拽改变窗体大小
//左上角
if ((mMousePoint.Y - Top <= CORNER_WIDTH) && (mMousePoint.X - Left <= CORNER_WIDTH))
{
return new IntPtr((int)HitTest.HTTOPLEFT);
}
//左下角
if ((this.ActualHeight + this.Top - this.mMousePoint.Y <= CORNER_WIDTH) && (this.mMousePoint.X - this.Left <= CORNER_WIDTH))
{
return new IntPtr((int)HitTest.HTBOTTOMLEFT);
}
//右上角
if ((this.mMousePoint.Y - this.Top <= CORNER_WIDTH) && (this.ActualWidth + this.Left - this.mMousePoint.X <= CORNER_WIDTH))
{
return new IntPtr((int)HitTest.HTTOPRIGHT);
}
//右下角
if ((this.ActualWidth + this.Left - this.mMousePoint.X <= CORNER_WIDTH) && (this.ActualHeight + this.Top - this.mMousePoint.Y <= CORNER_WIDTH))
{
return new IntPtr((int)HitTest.HTBOTTOMRIGHT);
}
//左侧
if (this.mMousePoint.X - (this.Left + 4) <= MARGIN_WIDTH)
{
return new IntPtr((int)HitTest.HTLEFT);
}
//右侧
if (this.ActualWidth + this.Left - 4 - this.mMousePoint.X <= MARGIN_WIDTH)
{
return new IntPtr((int)HitTest.HTRIGHT);
}
//上侧
if (this.mMousePoint.Y - (this.Top + 4) <= MARGIN_WIDTH)
{
return new IntPtr((int)HitTest.HTTOP);
}
//下侧
if (this.ActualHeight + this.Top - 4 - this.mMousePoint.Y <= MARGIN_WIDTH)
{
return new IntPtr((int)HitTest.HTBOTTOM);
}
#endregion
//正常情况下移动窗体
if (this.mMousePoint.Y - this.Top > 0 && this.mMousePoint.Y - this.Top < 25 && this.Left + this.ActualWidth - mMousePoint.X > 100)
{
return new IntPtr((int)HitTest.HTCAPTION);
}
}
//最大化时移动窗体,让窗体正常化
if (this.WindowState == WindowState.Maximized)
{
if (this.mMousePoint.Y < 40 && this.ActualWidth - mMousePoint.X > 110)
{
return new IntPtr((int)HitTest.HTCAPTION);
}
}
//将q其他区域设置为客户端,避免鼠标事件被屏蔽
return new IntPtr((int)HitTest.HTCLIENT);
}
return IntPtr.Zero;
}
}
/// <summary>
/// 包含了鼠标的各种消息
/// </summary>
public enum HitTest : int
{
/// <summary>
/// HTERROR
/// </summary>
HTERROR = -2,
/// <summary>
/// HTTRANSPARENT
/// </summary>
HTTRANSPARENT = -1,
/// <summary>
/// HTNOWHERE
/// </summary>
HTNOWHERE = 0,
/// <summary>
/// HTCLIENT
/// </summary>
HTCLIENT = 1,
/// <summary>
/// HTCAPTION
/// </summary>
HTCAPTION = 2,
/// <summary>
/// HTSYSMENU
/// </summary>
HTSYSMENU = 3,
/// <summary>
/// HTGROWBOX
/// </summary>
HTGROWBOX = 4,
/// <summary>
/// HTSIZE
/// </summary>
HTSIZE = HTGROWBOX,
/// <summary>
/// HTMENU
/// </summary>
HTMENU = 5,
/// <summary>
/// HTHSCROLL
/// </summary>
HTHSCROLL = 6,
/// <summary>
/// HTVSCROLL
/// </summary>
HTVSCROLL = 7,
/// <summary>
/// HTMINBUTTON
/// </summary>
HTMINBUTTON = 8,
/// <summary>
/// HTMAXBUTTON
/// </summary>
HTMAXBUTTON = 9,
/// <summary>
/// HTLEFT
/// </summary>
HTLEFT = 10,
/// <summary>
/// HTRIGHT
/// </summary>
HTRIGHT = 11,
/// <summary>
/// HTTOP
/// </summary>
HTTOP = 12,
/// <summary>
/// HTTOPLEFT
/// </summary>
HTTOPLEFT = 13,
/// <summary>
/// HTTOPRIGHT
/// </summary>
HTTOPRIGHT = 14,
/// <summary>
/// HTBOTTOM
/// </summary>
HTBOTTOM = 15,
/// <summary>
/// HTBOTTOMLEFT
/// </summary>
HTBOTTOMLEFT = 16,
/// <summary>
/// HTBOTTOMRIGHT
/// </summary>
HTBOTTOMRIGHT = 17,
/// <summary>
/// HTBORDER
/// </summary>
HTBORDER = 18,
/// <summary>
/// HTREDUCE
/// </summary>
HTREDUCE = HTMINBUTTON,
/// <summary>
/// HTZOOM
/// </summary>
HTZOOM = HTMAXBUTTON,
/// <summary>
/// HTSIZEFIRST
/// </summary>
HTSIZEFIRST = HTLEFT,
/// <summary>
/// HTSIZELAST
/// </summary>
HTSIZELAST = HTBOTTOMRIGHT,
/// <summary>
/// HTOBJECT
/// </summary>
HTOBJECT = 19,
/// <summary>
/// HTCLOSE
/// </summary>
HTCLOSE = 20,
/// <summary>
/// HTHELP
/// </summary>
HTHELP = 21
}
/// <summary>
/// 背景类型
/// </summary>
public enum BackGroundType
{
/// <summary>
/// 绿色调
/// </summary>
Green,
/// <summary>
/// 蓝色调
/// </summary>
Blue,
/// <summary>
/// 背景图片
/// </summary>
Image
}
}