WPF利用WindowChrome实现自定义窗口

作者:黑夜中的潜行者 时间:2021-06-08 07:33:55 

简介

Microsoft官网关于 WindowChome 的介绍

截取Microsoft文章的一段话:

若要在保留其标准功能时自定义窗口,可以使用该 WindowChrome 类。 该 WindowChrome 类将窗口框架的功能与视觉对象分开,并允许你控制应用程序窗口的客户端和非客户端区域之间的边界。 通过 WindowChrome 该类,可以通过扩展工作区来覆盖非工作区,将 WPF 内容置于窗口框架中。 同时,它通过两个不可见区域保留系统行为: 调整边框 和 标题 区域的大小。

效果图

WPF利用WindowChrome实现自定义窗口

WPF利用WindowChrome实现自定义窗口

自定义最小化、最大化、关闭按钮

最小化按钮

<Style
   x:Key="SystemCloseButtonStyle"
   BasedOn="{StaticResource SystemButtonStyleBase}"
   TargetType="{x:Type Button}">
   <Setter Property="Template">
       <Setter.Value>
           <ControlTemplate TargetType="{x:Type Button}">
               <Grid Background="{TemplateBinding Background}">
                   <Viewbox Width="12" Height="12">
                       <Path Data="M550.848 502.496l308.64-308.896a31.968 31.968 0 1 0-45.248-45.248l-308.608 308.896-308.64-308.928a31.968 31.968 0 1 0-45.248 45.248l308.64 308.896-308.64 308.896a31.968 31.968 0 1 0 45.248 45.248l308.64-308.896 308.608 308.896a31.968 31.968 0 1 0 45.248-45.248l-308.64-308.864z" Fill="{TemplateBinding BorderBrush}" />
                   </Viewbox>
                   <ContentPresenter
                       HorizontalAlignment="Center"
                       VerticalAlignment="Center"
                       Content="{TemplateBinding Content}" />
               </Grid>
               <ControlTemplate.Triggers>
                   <Trigger Property="IsMouseOver" Value="True">
                       <Setter Property="Background" Value="{StaticResource CloseColor}" />
                       <Setter Property="BorderBrush" Value="{StaticResource DominantColor}" />
                   </Trigger>
                   <Trigger Property="IsFocused" Value="True">
                       <Setter Property="FocusVisualStyle" Value="{x:Null}" />
                   </Trigger>
               </ControlTemplate.Triggers>
           </ControlTemplate>
       </Setter.Value>
   </Setter>
</Style>

最大化按钮

<Style
   x:Key="SystemMaxButtonStyle"
   BasedOn="{StaticResource SystemButtonStyleBase}"
   TargetType="{x:Type Button}">
   <Setter Property="Template">
       <Setter.Value>
           <ControlTemplate TargetType="{x:Type Button}">
               <Grid Background="{TemplateBinding Background}">
                   <Viewbox Width="12" Height="12">
                       <Path Data="M959.72 0H294.216a63.96 63.96 0 0 0-63.96 63.96v127.92H64.28A63.96 63.96 0 0 0 0.32 255.84V959.4a63.96 63.96 0 0 0 63.96 63.96h703.56a63.96 63.96 0 0 0 63.96-63.96V792.465h127.92a63.96 63.96 0 0 0 63.96-63.96V63.96A63.96 63.96 0 0 0 959.72 0zM767.84 728.505V959.4H64.28V255.84h703.56z m189.322 0H831.8V255.84a63.96 63.96 0 0 0-63.96-63.96H294.216V63.96H959.72z" Fill="{TemplateBinding BorderBrush}" />
                   </Viewbox>
                   <ContentPresenter
                       HorizontalAlignment="Center"
                       VerticalAlignment="Center"
                       Content="{TemplateBinding Content}" />
               </Grid>
               <ControlTemplate.Triggers>
                   <Trigger Property="IsMouseOver" Value="True">
                       <Setter Property="Background" Value="{StaticResource SuspensionColor}" />
                   </Trigger>
                   <Trigger Property="IsFocused" Value="True">
                       <Setter Property="FocusVisualStyle" Value="{x:Null}" />
                   </Trigger>
               </ControlTemplate.Triggers>
           </ControlTemplate>
       </Setter.Value>
   </Setter>
</Style>

关闭按钮

<Style
   x:Key="SystemMinButtonStyle"
   BasedOn="{StaticResource SystemButtonStyleBase}"
   TargetType="{x:Type Button}">
   <Setter Property="Template">
       <Setter.Value>
           <ControlTemplate TargetType="{x:Type Button}">
               <Grid Background="{TemplateBinding Background}">
                   <Viewbox Width="12" Height="10">
                       <Path Data="M928.2 548h-832c-17.7 0-32-14.3-32-32s14.3-32 32-32h832c17.7 0 32 14.3 32 32s-14.3 32-32 32z" Fill="{TemplateBinding BorderBrush}" />
                   </Viewbox>
                   <ContentPresenter
                       HorizontalAlignment="Center"
                       VerticalAlignment="Center"
                       Content="{TemplateBinding Content}" />
               </Grid>
               <ControlTemplate.Triggers>
                   <Trigger Property="IsMouseOver" Value="True">
                       <Setter Property="Background" Value="{StaticResource SuspensionColor}" />
                   </Trigger>
                   <Trigger Property="IsFocused" Value="True">
                       <Setter Property="FocusVisualStyle" Value="{x:Null}" />
                   </Trigger>
               </ControlTemplate.Triggers>
           </ControlTemplate>
       </Setter.Value>
   </Setter>
</Style>
/// <summary>
/// 窗口移动
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Move_Click(object sender, System.Windows.Input.MouseButtonEventArgs e) => this.DragMove();

/// <summary>
/// 最小化
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void BtnMin_Click(object sender, RoutedEventArgs e) => WindowState = WindowState.Minimized;

/// <summary>
/// 最大化/还原
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void BtnMax_Click(object sender, RoutedEventArgs e) => WindowState = WindowState is WindowState.Normal ? WindowState.Maximized : WindowState.Normal;

/// <summary>
/// 关闭
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void BtnClose_Click(object sender, RoutedEventArgs e) => Application.Current.Shutdown();

布局实现

首先我们需要在 MainWindow 也就是我们的主窗口中的 Window.Resources 中实现 WindowChrome 的基本样式:

WindowChrome.ResizeBorderThickness 设置不可见边框宽度

WindowChrome.CaptionHeight> 设置属于标题栏的范围&mdash;&mdash;高度

WindowChrome.UseAeroCaptionButtons 是否启用默认系统按钮功能&mdash;&mdash;三大金刚键

WindowChrome.NonClientFrameEdges 设置客户区域,使用 bottom 可以实现加载时空白窗口而不显示默认窗口,提升用户体验

<Window
   x:Class="SignalRClient.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:local="clr-namespace:SignalRClient"
   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
   Title=""
   Width="880"
   Height="620"
   MinWidth="700"
   MinHeight="500"
   Style="{StaticResource mainWindow}"
   WindowChrome.WindowChrome="{DynamicResource WindowChromeKey}"
   WindowStartupLocation="CenterScreen"
   mc:Ignorable="d">

<Window.Resources>
       <WindowChrome x:Key="WindowChromeKey">
           <WindowChrome.ResizeBorderThickness>
               <Thickness>5</Thickness>
           </WindowChrome.ResizeBorderThickness>
           <WindowChrome.CaptionHeight>60</WindowChrome.CaptionHeight>
           <WindowChrome.UseAeroCaptionButtons>false</WindowChrome.UseAeroCaptionButtons>
           <WindowChrome.NonClientFrameEdges>bottom</WindowChrome.NonClientFrameEdges>
       </WindowChrome>
   </Window.Resources>
</Window>

重写窗口,实现最大化窗口下,标题栏及客户区域偏移问题的修正。

通过代码获取当前窗口的工作区域,及任务栏以外的其他区域

System.Windows.SystemParameters.WorkArea.Width 获取工作区域的宽

System.Windows.SystemParameters.WorkArea.Height 获取工作区域的高

为什么要使用 ValueConverter 主要是因为 WorkArea 返回的类型无法直接 binding xaml

<ValueConverters:WorkAreaWidth x:Key="workAreaWidth" />
<ValueConverters:WorkAreaHeight x:Key="workAreaHeight" />

<Style x:Key="mainWindow" TargetType="{x:Type Window}">
   <Setter Property="Template">
       <Setter.Value>
           <ControlTemplate TargetType="Window">

<ContentControl x:Name="window" Content="{TemplateBinding Content}" />

<ControlTemplate.Triggers>
                   <Trigger Property="WindowState" Value="Maximized">
                       <Setter TargetName="window" Property="MaxHeight" Value="{Binding Converter={StaticResource workAreaHeight}}" />
                       <Setter TargetName="window" Property="MaxWidth" Value="{Binding Converter={StaticResource workAreaWidth}}" />
                   </Trigger>
               </ControlTemplate.Triggers>
           </ControlTemplate>
       </Setter.Value>
   </Setter>
</Style>
using System;
using System.Globalization;
using System.Windows.Data;

namespace SignalRClient.ValueConverters
{
   internal class WorkAreaWidth : IValueConverter
   {
       public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
       {
           return System.Windows.SystemParameters.WorkArea.Width;
       }

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
       {
           throw new NotImplementedException();
       }
   }
}
using System;
using System.Globalization;
using System.Windows.Data;

namespace SignalRClient.ValueConverters
{
   internal class WorkAreaHeight : IValueConverter
   {
       public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
       {
           return System.Windows.SystemParameters.WorkArea.Height;
       }

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
       {
           throw new NotImplementedException();
       }
   }
}

来源:https://blog.csdn.net/qq_43562262/article/details/129059262

标签:WPF,WindowChrome,自定义,窗口
0
投稿

猜你喜欢

  • Java Swing实现窗体添加背景图片的2种方法详解

    2021-10-26 19:01:18
  • Java事件处理机制和适配器全面解析

    2021-10-23 04:19:32
  • 深入理解Java中的接口

    2023-11-08 23:52:43
  • java LRU(Least Recently Used )详解及实例代码

    2022-10-08 10:42:43
  • Java加载资源文件时的路径问题的解决办法

    2023-05-09 23:22:40
  • Mybatis整合达梦数据库的完整步骤记录

    2023-11-23 07:15:37
  • java中拼接字符串的5种方法效率对比

    2022-01-08 05:46:18
  • C#实现文件压缩与解压的方法示例【ZIP格式】

    2021-12-31 23:25:20
  • Android实现图片文字轮播特效

    2021-07-25 18:44:11
  • JSON序列化Redis读取出错问题解决方案

    2022-10-13 18:57:50
  • 细品Java8中hashCode方法的使用

    2023-10-04 14:01:19
  • 基于json解析神器 jsonpath的使用说明

    2022-06-14 08:57:18
  • Visual C#类的定义及实现方法实例解析

    2023-06-04 18:10:37
  • java中的interface接口实例详解

    2023-10-12 22:03:10
  • SpringBoot中的Thymeleaf用法

    2023-10-30 17:30:39
  • swagger如何返回map字段注释

    2023-02-22 08:56:27
  • JavaWeb动态导出Excel可弹出下载

    2021-11-21 11:12:12
  • Mybatis源码解析之事务管理

    2023-01-14 10:59:34
  • Android中通知栏跳动问题解决方法

    2023-05-31 20:16:55
  • springboot 按月分表的实现方式

    2023-11-25 00:03:47
  • asp之家 软件编程 m.aspxhome.com