Loading,你用IE,难怪你打不开

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>
posted @ 2022-04-06 12:20  老板娘的神秘商店  阅读(716)  评论(0编辑  收藏  举报