WPF 自定义 窗体(抄袭Fluent.Ribbon仿VS窗体)
先看效果
由于是Demo, 故采用重写Window,并抄袭Fluent.Ribbon加了几个依赖属性,毕竟Fluent.Ribbon这么好的项目又是MIT协议,拆出来大家使用,不过这个窗体全屏可能会有问题,因为WK本人没有在其他机器上测试, 请定位到下面代码中if (innerGrid != null) //限制窗体最大化时的问题,我在Win10上没问题不代表其他系统是否有问题
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Shell;
namespace WinCus
{
[TemplatePart(Name = PART_Root, Type = typeof(FrameworkElement))]
[TemplatePart(Name = PART_Icon, Type = typeof(UIElement))]
public partial class CusWindow : Window
{
const string PART_Root = "PART_Root";
const string PART_Icon = "PART_Icon";
private UIElement iconImage = null;
#region 静态构造函数
static CusWindow()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CusWindow), new FrameworkPropertyMetadata(typeof(CusWindow)));
StyleProperty.OverrideMetadata(typeof(CusWindow), new FrameworkPropertyMetadata(null, OnCoerceStyle));
}
private static object OnCoerceStyle(DependencyObject d, object baseValue)
{
if (baseValue != null) return baseValue;
FrameworkElement fe = d as FrameworkElement;
if (fe != null)
{
baseValue = fe.TryFindResource(typeof(CusWindow));
}
return baseValue;
}
#endregion
#region 初始化, 窗体大小改变修改按钮
public CusWindow() : base()
{ //实例化调用Show后如果鼠标按住并且鼠标移动跟随移动
this.Unloaded += BaseFloatWindow_UnLoaded;
AddCommandBinding();
}
#endregion
#region 注册命令
private void AddCommandBinding()
{
CommandBinding cmdBinding = new CommandBinding(SystemCommands.CloseWindowCommand);
cmdBinding.Executed += OnCmdCloseWindow_Executed;
this.CommandBindings.Add(cmdBinding);
cmdBinding = new CommandBinding(SystemCommands.MaximizeWindowCommand);
cmdBinding.Executed += OnCmdMaximizeWindow_Executed;
this.CommandBindings.Add(cmdBinding);
cmdBinding = new CommandBinding(SystemCommands.MinimizeWindowCommand);
cmdBinding.Executed += OnCmdMinimizeWindow_Executed;
this.CommandBindings.Add(cmdBinding);
cmdBinding = new CommandBinding(SystemCommands.RestoreWindowCommand);
cmdBinding.Executed += OnCmdRestoreWindow_Executed;
this.CommandBindings.Add(cmdBinding);
cmdBinding = new CommandBinding(SystemCommands.ShowSystemMenuCommand);
cmdBinding.Executed += OnCmdShowSystemMenuComman_Executed;
this.CommandBindings.Add(cmdBinding);
KeyBinding keyBinding = new KeyBinding(SystemCommands.ShowSystemMenuCommand, Key.Space, ModifierKeys.Alt);
base.InputBindings.Add(keyBinding);
}
private void OnCmdShowSystemMenuComman_Executed(object sender, ExecutedRoutedEventArgs e)
{
if (this.iconImage != null && iconImage.IsFocused == false)
{
SystemCommands.ShowSystemMenu(this, new Point(Left + Padding.Left, Top + WinTitleHeight));
iconImage.Focus();
}
else if (iconImage != null)
{
iconImage.MoveFocus(new TraversalRequest(FocusNavigationDirection.Down));
}
}
private void OnCmdRestoreWindow_Executed(object sender, ExecutedRoutedEventArgs e)
{
if (e.Source != null)
{
if (WindowState == WindowState.Maximized)
WindowState = WindowState.Normal;
else if (WindowState == WindowState.Normal)
WindowState = WindowState.Maximized;
}
}
private void OnCmdMinimizeWindow_Executed(object sender, ExecutedRoutedEventArgs e)
{
if (e.Source != null)
{
this.WindowState = WindowState.Minimized;
}
}
private void OnCmdMaximizeWindow_Executed(object sender, ExecutedRoutedEventArgs e)
{
WindowState = WindowState.Maximized;
}
private void OnCmdCloseWindow_Executed(object sender, ExecutedRoutedEventArgs e)
{
this.Close();
}
#endregion
#region WindowChrome相关依赖属性,模仿Fluent
//## 按钮没有设置WindowChrome.IsHitTestVisibleInChrome="true" 那按钮是拿不到点击事件的
//窗口顶部标题区域的高度 | 指定WindowChrome的标题栏高度
public double CaptionHeight
{
get { return (double)GetValue(CaptionHeightProperty); }
set { SetValue(CaptionHeightProperty, value); }
}
public static readonly DependencyProperty CaptionHeightProperty = DependencyProperty.Register(
"CaptionHeight", typeof(double), typeof(CusWindow), new PropertyMetadata(25d, OnWindowChrome_ProperthChanged));
//窗口边角的圆角度数
public CornerRadius CornerRadius
{
get { return (CornerRadius)GetValue(CornerRadiusProperty); }
set { SetValue(CornerRadiusProperty, value); }
}
public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register(
"CornerRadius", typeof(CornerRadius), typeof(CusWindow), new PropertyMetadata(new CornerRadius(5), OnWindowChrome_ProperthChanged));
//窗口周围透明边框的宽度 | 用于控制边框
public Thickness GlassFrameThickness
{
get { return (Thickness)GetValue(GlassFrameThicknessProperty); }
set { SetValue(GlassFrameThicknessProperty, value); }
}
public static readonly DependencyProperty GlassFrameThicknessProperty =
DependencyProperty.Register("GlassFrameThickness", typeof(Thickness), typeof(CusWindow), new PropertyMetadata(new Thickness(8), OnWindowChrome_ProperthChanged));
//用于调整窗口大小尺寸边框的宽度 | 用户可以单击并拖动以调整窗口大小的区域的宽度,设置之后则三个按钮隐藏
public Thickness ResizeBorderThickness
{
get { return (Thickness)GetValue(ResizeBorderThicknessProperty); }
set { SetValue(ResizeBorderThicknessProperty, value); }
}
public static readonly DependencyProperty ResizeBorderThicknessProperty = DependencyProperty.Register(
"ResizeBorderThickness", typeof(Thickness), typeof(CusWindow), new PropertyMetadata(new Thickness(3), OnWindowChrome_ProperthChanged));
//船体标题Aero按钮是否启用命中 | 表示标题栏上的那三个默认按钮是否可以命中,因为我们想要自己管理这三个按钮的样式、显示或隐藏,所以设置为False
public bool UseAeroCaptionButtons
{
get { return (bool)GetValue(UseAeroCaptionButtonsProperty); }
set { SetValue(UseAeroCaptionButtonsProperty, value); }
}
public static readonly DependencyProperty UseAeroCaptionButtonsProperty =
DependencyProperty.Register("UseAeroCaptionButtons", typeof(bool), typeof(CusWindow), new PropertyMetadata(false, OnWindowChrome_ProperthChanged));
//Gets wheter DWM can be used
public bool CanUseDwn = false;
private void RefleshCanUseDwn()
{
CanUseDwn = IsDwmEnabled();
}
#region IsDwmEnabled
/// <devdoc>http://msdn.microsoft.com/en-us/library/windows/desktop/aa969518%28v=vs.85%29.aspx</devdoc>
[DllImport("dwmapi", PreserveSig = false, CallingConvention = CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool DwmIsCompositionEnabled();
// Sets in first IsDwmEnabled call
private static bool idDwmDllNotFound;
/// <summary>
/// Is DWM enabled
/// </summary>
/// <returns>Is DWM enabled</returns>
public static bool IsDwmEnabled()
{
if (idDwmDllNotFound) return false;
if (Environment.OSVersion.Version.Major < 6)
{
idDwmDllNotFound = true;
return false;
}
try
{
return DwmIsCompositionEnabled();
}
catch (DllNotFoundException)
{
idDwmDllNotFound = true;
return false;
}
}
#endregion
private static void OnWindowChrome_ProperthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
CusWindow window = d as CusWindow;
if (window != null) window.UpdateWindowChrome();
}
protected virtual void UpdateWindowChrome()
{
var windowChrome = WindowChrome.GetWindowChrome(this);
if (windowChrome == null)
{
windowChrome = new WindowChrome();
WindowChrome.SetWindowChrome(this, windowChrome);
}
windowChrome.CaptionHeight = this.CaptionHeight;
windowChrome.CornerRadius = this.CornerRadius;
windowChrome.GlassFrameThickness = this.GlassFrameThickness;
windowChrome.ResizeBorderThickness = this.ResizeBorderThickness;
windowChrome.UseAeroCaptionButtons = this.UseAeroCaptionButtons && this.CanUseDwn;
this.SetValue(CusWindow.WinTitleHeightPropertyKey, Math.Max(0, this.CaptionHeight) + Math.Max(0, this.ResizeBorderThickness.Top));
}
#region WinTitleHeight
private static readonly DependencyPropertyKey WinTitleHeightPropertyKey = DependencyProperty.RegisterReadOnly(
"WinTitleHeight", typeof(double), typeof(CusWindow),
new FrameworkPropertyMetadata(28d, FrameworkPropertyMetadataOptions.None));
public static readonly DependencyProperty WinTitleHeightProperty = CusWindow.WinTitleHeightPropertyKey.DependencyProperty;
[Browsable(false)]
[ReadOnly(true)]
public double WinTitleHeight
{
get
{
return (double)base.GetValue(CusWindow.WinTitleHeightProperty);
}
}
#endregion
#endregion
//WindowChrome相关
#region OnSourceInitialized 重写
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
this.RefleshCanUseDwn();
this.UpdateWindowChrome();
}
#endregion
#region OnApplyTemplate
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
this.RefleshCanUseDwn();
this.UpdateWindowChrome();
FrameworkElement innerGrid = GetTemplateChild(PART_Root) as FrameworkElement;
if (innerGrid != null) //限制窗体最大化时的问题,我在Win10上没问题不代表其他系统是否有问题
{
innerGrid.MaxWidth = SystemParameters.WorkArea.Width;
innerGrid.MaxHeight = SystemParameters.WorkArea.Height;
}
if (iconImage != null)
{
iconImage.MouseLeftButtonDown -= OnIconImage_MouseLeftDown;
iconImage.MouseRightButtonDown -= OnIconImage_RightDown;
}
iconImage = GetTemplateChild(PART_Icon) as UIElement;
if (iconImage != null)
{
iconImage.Focusable = true;
WindowChrome.SetIsHitTestVisibleInChrome(iconImage, true); //允许在WindowChrome区域进行点击
iconImage.MouseLeftButtonDown += OnIconImage_MouseLeftDown;
iconImage.MouseRightButtonDown += OnIconImage_RightDown;
}
}
private void OnIconImage_RightDown(object sender, MouseButtonEventArgs e)
{
UIElement fEle = sender as UIElement;
if (fEle != null)
{
Point relateTo = e.GetPosition(fEle);
Point mousePoint = fEle.PointToScreen(relateTo);
SystemCommands.ShowSystemMenu(this, new Point(mousePoint.X, mousePoint.Y));
fEle.Focus();
}
}
private void OnIconImage_MouseLeftDown(object sender, MouseButtonEventArgs e)
{
if (e.ClickCount == 2)
{
this.Close();
}
else if (e.ClickCount == 1)
{
UIElement fEle = sender as UIElement;
if (fEle != null && fEle.IsFocused == false)
{
SystemCommands.ShowSystemMenu(this, new Point(Left + Padding.Left, Top + WinTitleHeight));
fEle.Focus();
}
else if (fEle != null)
{
fEle.MoveFocus(new TraversalRequest(FocusNavigationDirection.Down));
}
}
}
#endregion
#region 窗体标题相关
public Brush CaptionTitleBackground
{
get { return (Brush)GetValue(CaptionTitleBackgroundProperty); }
set { SetValue(CaptionTitleBackgroundProperty, value); }
}
public static readonly DependencyProperty CaptionTitleBackgroundProperty = DependencyProperty.Register(
"CaptionTitleBackground", typeof(Brush), typeof(CusWindow), new PropertyMetadata(Brushes.Transparent));
public Brush CaptionTitleForeground
{
get { return (Brush)GetValue(CaptionTitleForegroundProperty); }
set { SetValue(CaptionTitleForegroundProperty, value); }
}
public static readonly DependencyProperty CaptionTitleForegroundProperty = DependencyProperty.Register(
"CaptionTitleForeground", typeof(Brush), typeof(CusWindow), new PropertyMetadata(Brushes.Black));
public double CaptionTitleFontSize
{
get { return (double)GetValue(CaptionTitleFontSizeProperty); }
set { SetValue(CaptionTitleFontSizeProperty, value); }
}
public static readonly DependencyProperty CaptionTitleFontSizeProperty =
DependencyProperty.Register("CaptionTitleFontSize", typeof(double), typeof(CusWindow), new PropertyMetadata(11d));
public FontFamily CaptionTitileFontFamily
{
get { return (FontFamily)GetValue(CaptionTitileFontFamilyProperty); }
set { SetValue(CaptionTitileFontFamilyProperty, value); }
}
public static readonly DependencyProperty CaptionTitileFontFamilyProperty = DependencyProperty.Register(
"CaptionTitileFontFamily", typeof(FontFamily), typeof(CusWindow), new PropertyMetadata(new FontFamily("微软雅黑")));
public FontWeight CaptionTitleFontWeight
{
get { return (FontWeight)GetValue(CaptionTitleFontWeightProperty); }
set { SetValue(CaptionTitleFontWeightProperty, value); }
}
public static readonly DependencyProperty CaptionTitleFontWeightProperty = DependencyProperty.Register(
"CaptionTitleFontWeight", typeof(FontWeight), typeof(CusWindow), new PropertyMetadata(FontWeights.Medium));
public FontStretch CaptionTitleFontStretch
{
get { return (FontStretch)GetValue(CaptionTitleFontStretchProperty); }
set { SetValue(CaptionTitleFontStretchProperty, value); }
}
public static readonly DependencyProperty CaptionTitleFontStretchProperty = DependencyProperty.Register(
"CaptionTitleFontStretch", typeof(FontStretch), typeof(CusWindow), new PropertyMetadata(FontStretches.Normal));
#endregion
#region Icon是否显示
public bool IsIconVisible
{
get { return (bool)GetValue(IsIconVisibleProperty); }
set { SetValue(IsIconVisibleProperty, value); }
}
public static readonly DependencyProperty IsIconVisibleProperty = DependencyProperty.Register(
"IsIconVisible", typeof(bool), typeof(CusWindow), new PropertyMetadata(true));
#endregion
#region Icon宽度
public double IconWidth
{
get { return (double)GetValue(IconWidthProperty); }
set { SetValue(IconWidthProperty, value); }
}
public static readonly DependencyProperty IconWidthProperty = DependencyProperty.Register(
"IconWidth", typeof(double), typeof(CusWindow), new PropertyMetadata(16d));
#endregion
#region Icon高度
public double IconHeight
{
get { return (double)GetValue(IconHeightProperty); }
set { SetValue(IconHeightProperty, value); }
}
public static readonly DependencyProperty IconHeightProperty = DependencyProperty.Register(
"IconHeight", typeof(double), typeof(CusWindow), new PropertyMetadata(16d));
#endregion
#region UnLoaded事件时卸载事件命令
private void BaseFloatWindow_UnLoaded(object sender, RoutedEventArgs e)
{
this.Unloaded -= BaseFloatWindow_UnLoaded;
if (iconImage != null)
{
iconImage.MouseLeftButtonDown -= OnIconImage_MouseLeftDown;
iconImage.MouseRightButtonDown -= OnIconImage_RightDown;
iconImage = null;
}
this.CommandBindings.Clear();
}
#endregion
}
}
解决ICON问题需要用到一个转换器,这是Fluent.Ribbon中的转换器,如果没有Icon会使用默认exe的icon
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Interop;
using System.Windows.Media.Imaging;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace WinCus
{
//取自Fluent dotNet 4.5 Under MIT License
public class IconConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
{
if (Application.Current != null && Application.Current.MainWindow != null)
{
try
{
return GetDefaultIcon((new WindowInteropHelper(Application.Current.MainWindow)).Handle) as BitmapFrame;
}
catch (InvalidOperationException)
{
return null;
}
}
var p = Process.GetCurrentProcess();
if (p.MainWindowHandle != IntPtr.Zero)
{ //return GetDefaultIcon((new WindowInteropHelper(Application.Current.MainWindow)).Handle)
return GetDefaultIcon(p.MainWindowHandle) as BitmapFrame;
}
}
ImageSource imgSour = value as ImageSource;
if (imgSour != null) return value;
BitmapFrame bitmapFrame = value as BitmapFrame;
if (bitmapFrame == null || bitmapFrame.Decoder == null)
{
return null;
}
foreach (var frame in bitmapFrame.Decoder.Frames)
{
var source = GetThumbnail(frame);
if (source != null) return source;
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return Binding.DoNothing;
}
/// <summary>
/// ThumbnailExceptionWorkArround when image cause a format exception by accessing the Thumbnail
/// </summary>
/// <param name="frame"></param>
/// <returns></returns>
static BitmapSource GetThumbnail(BitmapSource frame)
{
try
{
if (frame != null
&& frame.PixelWidth == 16
&& frame.PixelHeight == 16
&& (frame.Format == PixelFormats.Bgra32 || frame.Format == PixelFormats.Bgr24))
{
return frame;
}
return null;
}
catch (Exception)
{
return null;
}
}
internal const int WM_GETICON = 0x7f;
[SuppressMessage("Microsoft.Design", "CA1031")]
static ImageSource GetDefaultIcon(IntPtr hwnd)
{
if (hwnd != IntPtr.Zero)
{
try
{
var iconPtr = SendMessage(hwnd, WM_GETICON, new IntPtr(2), IntPtr.Zero);
if (iconPtr == IntPtr.Zero)
{
iconPtr = GetClassLong(hwnd, -34);
}
if (iconPtr == IntPtr.Zero)
{
iconPtr = LoadImage(IntPtr.Zero, new IntPtr(0x7f00), 1,
(int)SystemParameters.SmallIconWidth, (int)SystemParameters.SmallIconHeight, 0x8000);
}
if (iconPtr != IntPtr.Zero)
{
return BitmapFrame.Create(Imaging.CreateBitmapSourceFromHIcon(
iconPtr, Int32Rect.Empty,
BitmapSizeOptions.FromWidthAndHeight(
(int)SystemParameters.SmallIconWidth,
(int)SystemParameters.SmallIconHeight
)
));
}
}
catch
{
return null;
}
}
return null;
}
#region LoadImage
/// <summary>
/// Loads an icon, cursor, animated cursor, or bitmap.
/// </summary>
/// <param name="hinst">Handle to the module of either a DLL or executable (.exe) that contains the image to be loaded</param>
/// <param name="lpszName">Specifies the image to load</param>
/// <param name="uType">Specifies the type of image to be loaded. </param>
/// <param name="cxDesired">Specifies the width, in pixels, of the icon or cursor</param>
/// <param name="cyDesired">Specifies the height, in pixels, of the icon or cursor</param>
/// <param name="fuLoad">This parameter can be one or more of the following values.</param>
/// <returns>If the function succeeds, the return value is the requested value.If the function fails, the return value is zero. To get extended error information, call GetLastError. </returns>
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr LoadImage(IntPtr hinst, IntPtr lpszName, uint uType, int cxDesired, int cyDesired, uint fuLoad);
#endregion
#region GetClassLong
internal static IntPtr GetClassLong(IntPtr hWnd, int nIndex)
{
if (IntPtr.Size == 4)
{
return new IntPtr(GetClassLong32(hWnd, nIndex));
}
return GetClassLong64(hWnd, nIndex);
}
[DllImport("user32.dll", EntryPoint = "GetClassLong")]
private static extern uint GetClassLong32(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", EntryPoint = "GetClassLongPtr")]
[SuppressMessage("Microsoft.Interoperability", "CA1400:PInvokeEntryPointsShouldExist")]
private static extern IntPtr GetClassLong64(IntPtr hWnd, int nIndex);
#endregion
#region 【使用 1】SendMessage [同步] 发送船体消息
/// <summary>
/// 给指定句柄hWnd的窗体发送窗体消息事件【https://docs.microsoft.com/zh-cn/windows/win32/api/winuser/nf-winuser-sendmessage】
/// 将指定的消息发送到一个或多个窗口,SendMessage函数调用指定窗口的窗口过程,直到窗口过程处理完消息后才返回 / 常见用于窗口拖拽
/// </summary>
/// <param name="hWnd">将接收消息的窗口的句柄,<code>IntPtr windowHandle = new WindowInteropHelper(WPF窗体).Handle;</code></param>
/// <param name="Msg">Win32窗体消息, 如<see cref="Win32Helper.WM_NCLBUTTONDOWN"/></param>
/// <param name="wParam">其他特定参数:示例值:new IntPtr(<see cref="Win32Helper.HT_CAPTION"/>) </param>
/// <param name="lParam">其他特定参数
/// 示例: var mousePosition = this.PointToScreenDPI(Mouse.GetPosition(当前窗体));
/// IntPtr lParam = new IntPtr(((int)mousePosition.X & (int)0xFFFF) | (((int)mousePosition.Y) << 16));
/// </param>
/// <returns>返回值指定消息处理的结果;这取决于发送的消息</returns>
[DllImport("user32.dll")]
internal static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
#endregion
}
}
剩下的把样式解决一下就OK了
<Style x:Key="WindowBtnFocusVisualStyle" TargetType="Control">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle Margin="2" Stroke="Transparent" StrokeDashArray="1 2"
StrokeThickness="1" SnapsToDevicePixels="True"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="WindowButtonStyle" TargetType="{x:Type Button}">
<Setter Property="WindowChrome.IsHitTestVisibleInChrome" Value="True"/>
<Setter Property="VerticalAlignment" Value="Stretch"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="#1E1E1E"/>
<Setter Property="Width" Value="35"/>
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="Padding" Value="4,3"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Name="border" SnapsToDevicePixels="True"
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}">
<ContentPresenter Name="contentPresenter" RecognizesAccessKey="True"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
ContentStringFormat="{TemplateBinding ContentStringFormat}"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" Focusable="False" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Button.IsDefaulted" Value="True">
<Setter Property="Border.BorderBrush"
Value="{DynamicResource ResourceKey={x:Static SystemColors.HighlightBrush}}"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#FCFCFD"/>
<Setter Property="Foreground" Value="#007ACC"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True"/>
<Condition Property="IsPressed" Value="True"/>
</MultiTrigger.Conditions>
<MultiTrigger.Setters>
<Setter Property="Background" Value="#0075C3"/>
<Setter Property="Foreground" Value="White"/>
</MultiTrigger.Setters>
</MultiTrigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Panel.Background" Value="#FFF4F4F4"/>
<Setter Property="Border.BorderBrush" Value="#FFADB2B5"/>
<Setter Property="TextElement.Foreground" Value="#FF838383"/>
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="WinBtnCloseStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource WindowButtonStyle}">
<Style.Triggers>
<Trigger Property="IsDefaulted" Value="true">
<Setter Property="BorderBrush" Value="#FF414141"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" Value="#FFEA6262"/>
<Setter Property="BorderBrush" Value="#FFF01428"/>
<Setter Property="Foreground" Value="White"/>
</Trigger>
<Trigger Property="IsPressed" Value="true">
<Setter Property="Background" Value="#FF940A14"/>
<Setter Property="BorderBrush" Value="#FF940A14"/>
<Setter Property="Foreground" Value="White"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Background" Value="#FF343434"/>
<Setter Property="BorderBrush" Value="#FF3C3C3C"/>
<Setter Property="Foreground" Value="#FFA0A0A0"/>
</Trigger>
</Style.Triggers>
</Style>
<local:IconConverter x:Key="IconCrv"/>
<BooleanToVisibilityConverter x:Key="BoolVisbCrv" />
<Style TargetType="local:CusWindow">
<Setter Property="Background" Value="#EEEEF2"/>
<Setter Property="BorderBrush" Value="#9A9DB2"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="RenderOptions.BitmapScalingMode" Value="HighQuality"/>
<Setter Property="WindowChrome.WindowChrome">
<Setter.Value>
<WindowChrome GlassFrameThickness="1"
ResizeBorderThickness="4"
CaptionHeight="0"/>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:CusWindow">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<Grid x:Name="PART_Root">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<!--TitleBar-->
<Grid x:Name="PART_HeaderBar" Height="{TemplateBinding WinTitleHeight}" Background="{TemplateBinding CaptionTitleBackground}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Image x:Name="PART_Icon" Height="{TemplateBinding IconHeight}" Width="{TemplateBinding IconWidth}" Stretch="Uniform" Margin="8,0,0,0"
Source="{Binding Icon, Converter={StaticResource IconCrv}, RelativeSource={RelativeSource TemplatedParent}}"
Visibility="{TemplateBinding IsIconVisible, Converter={StaticResource BoolVisbCrv}}"
SnapsToDevicePixels="True" />
<TextBlock Grid.Column="1" Grid.Row="0" Margin="5,0,0,0"
Text="{TemplateBinding Title}" TextTrimming="CharacterEllipsis" TextAlignment="Left"
HorizontalAlignment="Stretch" VerticalAlignment="Center"
FontSize="{TemplateBinding CaptionTitleFontSize}"
FontWeight="{TemplateBinding CaptionTitleFontWeight}"
FontStretch="{TemplateBinding CaptionTitleFontStretch}"
FontFamily="{TemplateBinding CaptionTitileFontFamily}"
Foreground="{TemplateBinding Foreground}"
IsEnabled="{TemplateBinding IsActive}"/>
<StackPanel Grid.Row="0" Grid.Column="2" Orientation="Horizontal">
<Button x:Name="PART_MinSizeBtn" Style="{StaticResource WindowButtonStyle}"
Command="{x:Static SystemCommands.MinimizeWindowCommand}">
<Path Width="9" Height="9" VerticalAlignment="Bottom" Stretch="Uniform" UseLayoutRounding="True" StrokeThickness="1"
Fill="{Binding Foreground, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Button}}"
Data="F1M0,6L0,9 9,9 9,6 0,6z"/>
</Button>
<Grid>
<Button x:Name="PART_MaxSizeBtn" Style="{StaticResource WindowButtonStyle}"
Command="{x:Static SystemCommands.MaximizeWindowCommand}">
<Path Width="10" Height="10" SnapsToDevicePixels="True" Stretch="Uniform" UseLayoutRounding="True" StrokeThickness="1"
Fill="{Binding Foreground, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Button}}"
Data="F1M0,0L0,9 9,9 9,0 0,0 0,3 8,3 8,8 1,8 1,3z"/>
</Button>
<Button x:Name="PART_RestoreBtn" Style="{StaticResource WindowButtonStyle}"
Command="{x:Static SystemCommands.RestoreWindowCommand}">
<Path Width="9" Height="9" SnapsToDevicePixels="True" Stretch="Uniform" UseLayoutRounding="True" StrokeThickness="1"
Fill="{Binding Foreground, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Button}}"
Data="F1M0,10L0,3 3,3 3,0 10,0 10,2 4,2 4,3 7,3 7,6 6,6 6,5 1,5 1,10z M1,10L7,10 7,7 10,7 10,2 9,2 9,6 6,6 6,9 1,9z"/>
</Button>
</Grid>
<Button x:Name="PART_CloseBtn" Style="{StaticResource WinBtnCloseStyle}"
Command="{x:Static SystemCommands.CloseWindowCommand}">
<Path Width="10" Height="8" SnapsToDevicePixels="True" Stretch="Uniform" UseLayoutRounding="True" StrokeThickness="1"
Fill="{Binding Foreground, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Button}}"
Data="F1M0,0L2,0 5,3 8,0 10,0 6,4 10,8 8,8 5,5 2,8 0,8 4,4 0,0z"/>
</Button>
</StackPanel>
</Grid>
<AdornerDecorator Grid.Row="1" x:Name="Part_ContentAdorner">
<ContentPresenter x:Name="contentPresenter" Margin="{TemplateBinding Padding}" />
</AdornerDecorator>
<ResizeGrip x:Name="WindowResizeGrip" HorizontalAlignment="Right" VerticalAlignment="Bottom" Grid.Row="1"
Focusable="False" IsTabStop="False" Background="Transparent" UseLayoutRounding="True" Visibility="Collapsed" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsActive" Value="False">
<Setter Property="BorderBrush" Value="#FF9DA1A8" />
</Trigger>
<Trigger Property="IsIconVisible" Value="False">
<Setter Property="Visibility" Value="Collapsed" TargetName="PART_Icon"/>
</Trigger>
<Trigger Property="WindowState" Value="Maximized">
<Setter TargetName="PART_MaxSizeBtn" Property="Visibility" Value="Collapsed" />
<Setter TargetName="PART_RestoreBtn" Property="Visibility" Value="Visible"/>
</Trigger>
<Trigger Property="WindowState" Value="Normal">
<Setter TargetName="PART_MaxSizeBtn" Property="Visibility" Value="Visible" />
<Setter TargetName="PART_RestoreBtn" Property="Visibility" Value="Collapsed" />
</Trigger>
<Trigger Property="WindowStyle" Value="ToolWindow">
<Setter TargetName="PART_MinSizeBtn" Property="Visibility" Value="Collapsed"/>
<Setter TargetName="PART_RestoreBtn" Property="Visibility" Value="Visible"/>
</Trigger>
<Trigger Property="WindowStyle" Value="None">
<Setter TargetName="PART_HeaderBar" Property="Visibility" Value="Collapsed"/>
<Setter TargetName="Part_ContentAdorner" Property="Grid.Row" Value="0"/>
<Setter TargetName="Part_ContentAdorner" Property="Grid.RowSpan" Value="2"/>
</Trigger>
<Trigger Property="ResizeMode" Value="NoResize">
<Setter TargetName="PART_MinSizeBtn" Property="Visibility" Value="Collapsed"/>
<Setter TargetName="PART_MaxSizeBtn" Property="Visibility" Value="Collapsed"/>
<Setter TargetName="PART_RestoreBtn" Property="Visibility" Value="Collapsed"/>
</Trigger>
<Trigger Property="ResizeMode" Value="CanMinimize">
<Setter TargetName="PART_RestoreBtn" Property="Visibility" Value="Collapsed"/>
<Setter TargetName="PART_MaxSizeBtn" Property="Visibility" Value="Collapsed"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="ResizeMode" Value="CanResizeWithGrip" />
<Condition Property="WindowState" Value="Normal" />
</MultiTrigger.Conditions>
<Setter TargetName="WindowResizeGrip" Property="Visibility" Value="Visible" />
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
如何使用
新建WPF窗体, 删除继承Window
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
}
}
在xaml中记得引用名称空间
<Cus:CusWindow x:Class="Demo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:Cus="clr-namespace:WinCus;assembly=WinCus"
xmlns:local="clr-namespace:Demo"
mc:Ignorable="d"
Title="CUS Window STYLE_WK" Height="350" Width="525" Icon="FreeIcon.ico" Padding="4,0,4,4">
<Button Content="Padding 4,0,4,4" />
</Cus:CusWindow>
转载保留源出处即可,商业使用请自行鉴别,使用本博客中公开内容做任何违法犯罪于本作者无关