WPF中自定义标题栏时窗体最大化处理之WindowChrome
注意:
- 本文方法基础是WindowChrome,而WindowChrome在
.NET Framework 4.5
之后才集成发布的。见:WindowChrome Class- 在
.NET Framework 4.0
中使用WindowChrome,需要安装Ribbon来支持WindowChrome- 目前官方文档的内容较为陈旧(但仍有参考价值),其中提到了
SystemParameters2
,这个应该是Ribbon里的东西,4.5
想用可以安装Xceed.Wpf.AvalonDock
库,这里面有现成的Microsoft.Windows.Shell.SystemParameters2
实现——当然,自己不怕麻烦,可以自己实现来获取要用的系统变量。(一般用不着,4.5
中SystemParameters
添加了许多系统变量的实现)
实现步骤
第一步:基本实现【保留系统基础操作按钮】
- 添加Window的Style定义,并设置WindowChrome.WindowChrome属性;
- 设置WindowChrome标题栏:
- CaptionHeight——主要用于拖动有效区;
- GlassFrameThickness——影响标题栏系统按钮显示,0表示不使用系统按钮【后面介绍】,-1表示用的系统默认值,如下示例则表示标题栏高度30;
- 自定义窗体Title
注意:控件模板中的定义:
- 1、最外层Border背景无颜色,否则会覆盖标题栏,看不到系统按钮。
- 2、内部布局定义,使用Grid隔出30的标题栏高度,也可以直接对ContentPresenter设置Margin【主要是为了让顶部显示出标题栏】。
<Style x:Key="WindowStyle1" TargetType="{x:Type Window}">
<Setter Property="WindowChrome.WindowChrome">
<Setter.Value>
<WindowChrome CaptionHeight="30" GlassFrameThickness="0,30,0,0"/>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Window}">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" >
<AdornerDecorator >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ContentPresenter Grid.Row="1"/>
<TextBlock Text="{TemplateBinding Title}" HorizontalAlignment="Left" VerticalAlignment="Center" />
</Grid>
</AdornerDecorator>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
存在的问题: 最大化边框问题 —— 会有部分溢出。
根据观察,这个溢出宽度应该是
8
,此值的来源:(SystemParameters.MaximizedPrimaryScreenWidth - SystemParameters.WorkArea.Width)/2
,高度也可以这样计算。
第二步:优化边界处理
- 方法1:模板添加最大化触发器,设置最大化时,内部布局Margin设为8
- 方法2:模板添加最大化触发器,设置最大化时,限制布局最大化的宽高最大值
不管使用哪种方法,最大化时,系统的标题栏高度都发生了变化,故,需要重新设置模板中定义的标题栏高度。
<ControlTemplate TargetType="{x:Type Window}">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" >
<AdornerDecorator >
<Grid Name="win_content">
<Grid.RowDefinitions>
<RowDefinition Height="30" x:Name="row_title"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ContentPresenter Grid.Row="1"/>
<TextBlock Text="{TemplateBinding Title}" HorizontalAlignment="Left" VerticalAlignment="Center" />
</Grid>
</AdornerDecorator>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="WindowState" Value="Maximized">
<Setter Property="Margin" TargetName="win_content" Value="8"/>
<!--二选一-->
<Setter Property="MaxWidth" TargetName="win_content" Value="{Binding Source={x:Static SystemParameters.WorkArea},Path=Width}" />
<Setter Property="MaxHeight" TargetName="win_content" Value="{Binding Source={x:Static SystemParameters.WorkArea},Path=Height}"/>
<Setter Property="Height" TargetName="row_title" Value="22" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
至此,都是系统标题栏和我们自定义内容组合使用,但这样总有些边边角角要修正,下面就完全自定义标题栏
第三步:完全自定义标题栏【即,不使用系统的操作按钮】
- 初步操作类似第一步,其中将
GlassFrameThickness
设置为0
- 在内容定义部分添加自定义的标题栏,添加操作按钮,并设置按钮属性
WindowChrome.IsHitTestVisibleInChrome="True"
如果不设置
WindowChrome.IsHitTestVisibleInChrome
,则由于我们之前设置CaptionHeight
,则这个区域内,按钮将失效。
但是,也不能将整个标题栏布局设置这个属性,那样会完全覆盖系统标题栏的操作,如拖动效果,即CaptionHeight
设置的那个区域。
<!--样式定义-->
<Style x:Key="WindowStyle2" TargetType="{x:Type Window}">
<Setter Property="WindowChrome.WindowChrome">
<Setter.Value>
<WindowChrome UseAeroCaptionButtons="False" GlassFrameThickness="0" CaptionHeight="30" />
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Window}">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" >
<AdornerDecorator >
<ContentPresenter x:Name="win_content" />
</AdornerDecorator>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="WindowState" Value="Maximized">
<Setter Property="Margin" TargetName="win_content" Value="8"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!--定义标题栏-->
<Grid Background="Red" >
<Grid Height="30" HorizontalAlignment="Stretch" VerticalAlignment="Top" Background="Blue">
<StackPanel Orientation="Horizontal" WindowChrome.IsHitTestVisibleInChrome="True" HorizontalAlignment="Right" >
<Button Name="btn_Min" Content="—" ></Button>
<Button Name="btn_Max" Content="☐" ></Button>
<Button Name="btn_Close" Content="✕" ></Button>
</StackPanel>
</Grid>
</Grid>
//标题栏按钮功能实现
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.btn_Min.Click += Btn_Min_Click;
this.btn_Max.Click += Btn_Max_Click;
this.btn_Close.Click += Btn_Close_Click;
}
private void Btn_Close_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
private void Btn_Max_Click(object sender, RoutedEventArgs e)
{
this.WindowState = WindowState.Maximized == this.WindowState ? WindowState.Normal : WindowState.Maximized;
}
private void Btn_Min_Click(object sender, RoutedEventArgs e)
{
this.WindowState = WindowState.Minimized;
}
}
关联了解:
如果你平时也使用Visual Studio Code【VSCode】,文中的第一步和第三步,在vscode的设置中有对应效果:
- 第一步 —— 将vscode用户设置中Title Bar Style值设为native;
- 第三步 —— 将vscode用户设置中Title Bar Style值设为custom。
相关下载
解:奇葩史
落后要挨打,个人以前一直局限于老旧方式实现窗体处理,没有跟进WPF技术改进,在此,非常感谢@vbfool的提醒。【之前说周末搞出来,自己这几周浪了,没研究。今天趁着别人双11买买买,咱就撸撸代码】
WPF中自定义标题栏时窗体最大化处理之WindowChrome的更多相关文章
- 在WPF中自定义你的绘制(一)
原文:在WPF中自定义你的绘制(一) 在WPF中自定义你的绘制(一) ...
- 在WPF中自定义你的绘制(二)
原文:在WPF中自定义你的绘制(二) 在WPF中自定义你的绘制(二) ...
- WPF中制作无边框窗体
原文:WPF中制作无边框窗体 众所周知,在WinForm中,如果要制作一个无边框窗体,可以将窗体的FormBorderStyle属性设置为None来完成.如果要制作成异形窗体,则需要使用图片或者使用G ...
- 在VS2005中设置WPF中自定义按钮的事件
原文:在VS2005中设置WPF中自定义按钮的事件 上篇讲了如何在Blend中绘制圆角矩形(http://blog.csdn.net/johnsuna/archive/2007/08/13/17407 ...
- WPF中自定义的DataTemplate中的控件,在Window_Loaded事件中加载机制初探
原文:WPF中自定义的DataTemplate中的控件,在Window_Loaded事件中加载机制初探 最近因为项目需要,开始学习如何使用WPF开发桌面程序.使用WPF一段时间之后,感 ...
- 示例:WPF中自定义MessageService应用DialogHost、Snackbar、NotifyIcon显示各种场景提示消息
原文:示例:WPF中自定义MessageService应用DialogHost.Snackbar.NotifyIcon显示各种场景提示消息 一.目的:不同交互场景需要提示不同的消息,不同的消息需要用不 ...
- 示例:WPF中自定义StoryBoarService在代码中封装StoryBoard、Animation用于简化动画编写
原文:示例:WPF中自定义StoryBoarService在代码中封装StoryBoard.Animation用于简化动画编写 一.目的:通过对StoryBoard和Animation的封装来简化动画 ...
- 在WPF中自定义你的绘制(五)
原文:在WPF中自定义你的绘制(五) 在WPF中自定义你的绘制(五) ...
- 在WPF中自定义你的绘制(三)
原文:在WPF中自定义你的绘制(三) 在WPF中自定义你的绘制(三) ...
随机推荐
- 将Maple输出的LaTex导出到txt文件
将Maple输出的LaTex导出到txt文件 1. 生成LATEX Maple可以把它的表达式转换成LATEX, 使用latex命令即可: > latex(x^2+y^2=z^2); {x}^{ ...
- 《连连看》算法c语言演示(自动连连看)
(图片是游戏的示意图,来自互联网,与本文程序无关) 看题目就知道是写给初学者的,没需要的就别看了,自己都觉得怪无聊的. 很多游戏的耐玩性都来自精巧的算法,特别是人工智能的水平.比如前几天看了著名的Al ...
- 带着新人学springboot的应用07(springboot+RabbitMQ 下)
说一两句废话,强烈推荐各位小伙伴空闲时候也可以写写自己的博客!不管水平高低,不管写的怎么样,不要觉得写不好或者水平不够就不写了(咳,我以前就是这样的想法...自我反省!). 但是开始写博客之后,你会发 ...
- 线程安全(上)--彻底搞懂volatile关键字
对于volatile这个关键字,相信很多朋友都听说过,甚至使用过,这个关键字虽然字面上理解起来比较简单,但是要用好起来却不是一件容易的事.这篇文章将从多个方面来讲解volatile,让你对它更加理解. ...
- alibaba / zeus 安装 图解
一.首先需要到https://github.com/alibaba/zeus下载相应的安装文件 二.解压缩导入到eclipse工程
- Docker最全教程——从理论到实战(四)
往期内容链接 https://www.cnblogs.com/codelove/p/10030439.html https://www.cnblogs.com/codelove/p/10036608. ...
- 网络协议抓包分析——TCP传输控制协议(连接建立、释放)
前言 TCP协议为数据提供可靠的端到端的传输,处理数据的顺序和错误恢复,保证数据能够到达其应到达的地方.TCP协议是面向连接的,在两台主机使用TCP协议进行通信之前,会先建立一个TCP连接(三次握手) ...
- C# Task 篇幅一
在https://www.cnblogs.com/loverwangshan/p/10415937.html中我们有讲到委托的异步方法,Thread,ThreadPool,然后今天来讲一下Task, ...
- DSAPI多功能组件编程应用-网络相关(下)
[DSAPI.DLL下载地址] 在本篇,我将重点介绍DSAPI.DLL中Socket编程的使用.众所周知,Socket用起来不难,但是写起来麻烦.我对Socket进行了封装,进行了高度简化.下面我将通 ...
- 理解PHP的垃圾回收机制
什么是垃圾回收机制 使用的是“引用计数”方式进行回收.简单地理解的话,就是每个分配的内存区域都有一个计数器,记录有多少个变量指针指向这片内存.当指向该片内存的指针数量为0,那么该片内存区域就可以被回收 ...