快速创建WPF自定义窗体

使用WindowChrome创建自定义圆角窗体。WindowChrome.NET Framework 4.5之后才被集成。之前创建自定义窗口,都是把原有样式都取消,然后自己写一套控制逻辑来实现,有了WindowChrome多了一个选择,开发效率也更高效,下面就是一个简单基础示例。 本次示例项目采用的是.net 6,开发工具VS2022 内容参考:WPF中自定义标题栏时窗体最大化处理之WindowChrome - 奇葩史 - 博客园 (cnblogs.com)

快速上手

通过一个简单示例,来说明使用WindowChrome自定义窗体的创建流程。对于不理解的部分可以先不用理解,等整体弄完后自己再去查阅微软文档理解。

创建项目

创建一个WPF项,保持它最初始的样式

添加样式

为了方便编写,采用在<Window.Resources>标签内编写样式。最后需要把这里面的样式转移到样式资源字典里面。

基础样式

这里需要注意的是Sytle的TargetType需要指定为local:MainWindow,如果指定为Window则运行出错。等后期转移到资源字典的时候可以指定为Window,主窗体使用Sytle属性引用。

xml 复制代码
<Window.Resources>
	<!-- 自定义窗体样式 -->
	<Style TargetType="local:MainWindow">
		<!-- 设置窗体的WindowChrome -->
		<Setter Property="WindowChrome.WindowChrome">
			<Setter.Value>
				<!-- ResizeBorderThickness:拖拽改变窗体大小的边框厚度;-->
				<!-- CornerRadius:窗体圆角;-->
				<!-- CaptionHeight顶部标题的高度;-->
				<!-- GlassFrameThickness:默认边框的大小,0为不使用默认边框(这样定义的圆角才有效),-1为使用默认边框默认值-->
				<WindowChrome ResizeBorderThickness="4" CornerRadius="10" CaptionHeight="50" GlassFrameThickness="0"/>
			</Setter.Value>
		</Setter>

		<Setter Property="Template">
			<Setter.Value>
				<ControlTemplate TargetType="Window">
					<Grid x:Name="MainWindowArea">
						<Border Background="White"/>
						
					</Grid>

					<!-- 用于处理windowschrom,边框最大化出溢出问题 -->

				</ControlTemplate>
			</Setter.Value>
		</Setter>
	</Style>
</Window.Resources>

点击运行项目,你会得到这样一个带圆角的窗体,由于覆盖了默认控制按钮,而此时有没有编写自定义按钮,因此只能通过VS强行关闭。

标题栏区域样式

这一部分是在控件模板中编写标题栏的布局样式,主要分为3个区域:Icon;Title;ControlButton。

<Grid x:Name="MainWindowArea">标签里面填写如下样式布局。定义了两行,标题栏高度为50,50像素以下的区域用作窗体内容的显示。 需要注意的是Image控件中的图片资源我采用的是图片编译资源的引入,你可以更具实际情况不想用资源的话,可以使用图片路径。 按钮样式是我自定义按钮样式,可以更具你想要的样式自己编写。==示例样式==,我在文章最后会贴出。

xml 复制代码
<Grid x:Name="MainWindowContentGrid">
	<Grid.RowDefinitions>
		<RowDefinition Height="50"/>
		<RowDefinition Height="*"/>
	</Grid.RowDefinitions>

	<Grid x:Name="TitleBar">
		<Grid.ColumnDefinitions>
			<ColumnDefinition Width="Auto"/>
			<ColumnDefinition Width="*"/>
			<ColumnDefinition Width="Auto"/>
		</Grid.ColumnDefinitions>
		<!-- Top  Icon -->
		<Button x:Name="btnIcon"  Command="{Binding MenuCommand}">
			<Button.Style>
				<Style TargetType="Button">
					<!-- 这个属性不设置,在Caption上点击无效,无法触发button -->
					<Setter Property="WindowChrome.IsHitTestVisibleInChrome" Value="True"/>
					<Setter Property="Template">
						<Setter.Value>
							<ControlTemplate TargetType="Button">
								<Border FocusVisualStyle="{x:Null}">
									<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center"/>
								</Border>
							</ControlTemplate>
						</Setter.Value>
					</Setter>
				</Style>
			</Button.Style>
			<Button.Content>
				<!-- 这里采用的为内嵌资源引入,你可以自己改为图片路径 -->
				<Image Source="{StaticResource App_Icon_TitleBar}" Width="32" Height="32" Margin="9" Stretch="UniformToFill"/>
			</Button.Content>
		</Button>
		<!-- Top Title  ViewBox可以自适应内容-->
		<Viewbox Grid.Column="0" Grid.ColumnSpan="3">
			<StackPanel Margin="10">
				<TextBlock TextAlignment="Center" HorizontalAlignment="Center" Text="测试Demo"/>
			</StackPanel>
		</Viewbox>
		<!-- Top ControlBtn -->
		<StackPanel Grid.Column="2" Orientation="Horizontal">
			<Button Style="{StaticResource ControlButtonBase}" Content="---" Command="{Binding MinimizeCommand}"/>
			<Button Style="{StaticResource ControlButtonBase}" Content="▢" Command="{Binding MaximizeCommand}"/>
			<Button Style="{StaticResource CloseButton}" Content="╳" Command="{Binding CloseCommand}"/>
		</StackPanel>
	</Grid>

	<!-- window content show-->
	<Border Grid.Row="1" Padding="0" >
		<ContentPresenter Content="{TemplateBinding Content}"/>
	</Border>
</Grid>

点击运行后会得到一个带有自定义标题的空白窗体

这时候我们在窗体里面添加点内容,在</Window>标签上面添加如下代码

xml 复制代码
<!-- window Content -->
<Grid>
	<Border Background="White" BorderBrush="Red" BorderThickness="4">
		<TextBlock Text="这个是内容区域" FontSize="28" VerticalAlignment="Center" HorizontalAlignment="Center"/>
	</Border>
</Grid>

然后我们就会得到一个拥有内容的窗体。上面的Grid代码会被作为Window.Content填充到 ContentPresenter内渲染显示。

按钮逻辑

按钮点击没有反应,那是没有添加ViewModel中的代码,导致无法执行命令。此部分不属于文章内容不在此详细说明,有多种方法很简单自己实现即可。参考代码见末尾远程仓库。

最大化窗口溢出问题

点击最大化,你会发现窗口红色边框消失,感觉窗口撑破了屏幕,由于计算问题,需要重新定义窗口边缘大小。

有两种方法:

  • 方法1:模板添加最大化触发器,设置最大化时,内部布局Margin设为8
  • 方法2:模板添加最大化触发器,设置最大化时,限制布局最大化的宽高最大值

这里采用方式1

xml 复制代码
<!-- 用于处理windowschrom,边框最大化出溢出问题 -->
<ControlTemplate.Triggers>
	<Trigger Property="WindowState" Value="Maximized">
		<Setter Property="Margin" Value="8" TargetName="MainWindowContentGrid"/>
	</Trigger>
</ControlTemplate.Triggers>

按钮样式

样式前期你可以写在窗体资源里面,但写完后最好移动到资源字典里面。

xml 复制代码
<!-- 控制按钮基础 -->
<Style x:Key="ControlButtonBase" TargetType="Button">
	<Setter Property="WindowChrome.IsHitTestVisibleInChrome" Value="True"/>
	<Setter Property="Background" Value="Transparent"/>
	<Setter Property="Padding" Value="8"/>
	<Setter Property="VerticalAlignment" Value="Stretch"/>
	<Setter Property="Foreground" Value="#686868"/>
	<Setter Property="FontSize" Value="28"/>
	<Setter Property="Width" Value="50"/>
	<Setter Property="Template">
		<Setter.Value>
			<ControlTemplate TargetType="{x:Type Button}">
				<Border Padding="{TemplateBinding Padding}" Background="{TemplateBinding Background}">
					<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Text="{TemplateBinding Content}"/>
				</Border>
			</ControlTemplate>
		</Setter.Value>
	</Setter>

	<Style.Triggers>
		<Trigger Property="IsMouseOver" Value="True">
			<Setter Property="Background" Value="#efefef"/>
		</Trigger>
	</Style.Triggers>
</Style>

<!-- 关闭按钮 -->
<Style x:Key="CloseButton" TargetType="Button" BasedOn="{StaticResource ControlButtonBase}">
	<Style.Triggers>
		<Trigger Property="IsMouseOver" Value="True">
			<Setter Property="Background" Value="#FF4500"/>
		</Trigger>
	</Style.Triggers>
</Style>

结尾

这次只是简单的使用,后续会更新进阶使用,主要介绍里面属性的用法。如果自己感兴趣也可以去查看官方文档,里面解释的很清楚。

参考代码

项目地址:gitee.com/Boting_DD_b...

相关推荐
代码小鑫几秒前
A031-基于SpringBoot的健身房管理系统设计与实现
java·开发语言·数据库·spring boot·后端
Json____5 分钟前
学法减分交管12123模拟练习小程序源码前端和后端和搭建教程
前端·后端·学习·小程序·uni-app·学法减分·驾考题库
monkey_meng26 分钟前
【Rust类型驱动开发 Type Driven Development】
开发语言·后端·rust
落落落sss34 分钟前
MQ集群
java·服务器·开发语言·后端·elasticsearch·adb·ruby
大鲤余1 小时前
Rust,删除cargo安装的可执行文件
开发语言·后端·rust
她说彩礼65万1 小时前
Asp.NET Core Mvc中一个视图怎么设置多个强数据类型
后端·asp.net·mvc
陈随易1 小时前
农村程序员-关于小孩教育的思考
前端·后端·程序员
_江南一点雨1 小时前
SpringBoot 3.3.5 试用CRaC,启动速度提升3到10倍
java·spring boot·后端
转转技术团队2 小时前
空间换时间-将查询数据性能提升100倍的计数系统实践
java·后端·架构
r0ad2 小时前
SpringCloud2023实战之接口服务测试工具SpringBootTest
spring boot·后端·spring cloud