WPF 自定义窗口(C#)
WPF 自定义窗口(C#)
前言
WPF 自定义窗口 自定义窗口的这个问题,我在很久之前就有遇到,当时的解决办法也是简单粗暴,直接设置WindowStyle=”None” 、ResizeMode=”NoResize” 和 AllowsTransparency=”True” ,然后在里面的窗口里,自行实现窗口事件和阴影效果。
现在回望,很蠢。边缘阴影效果很差,边界线的感觉很low,窗口功能和图标都不能完美现实,最大化,最小化,关比的按钮做的千奇百怪。
最为重要的一点是体验很差,没有办法完美实现窗口的效果,强行实现要花的时间不值当的。
进阶 WindowChrome
我在Google 的过程中,突然看到了 可以使用WindowChrome 来自定义窗口样式。 不仅效果好,性能也高。
参考:WPF 制作高性能的透明背景异形窗口(使用 WindowChrome 而不要使用 AllowsTransparency=True)
WPF 使用 WindowChrome,在自定义窗口标题栏的同时最大程度保留原生窗口样式(类似 UWP/Chrome)
若要自定义窗口,同时保留其标准功能,可以使用WindowChrome类。 WindowChrome类窗口框架的功能分离开来视觉对象,并允许您控制的客户端和应用程序窗口的非工作区之间的边界。
只需要配置,即可。我尝试了一下,效果害可以,但是带来了新的问题。
<WindowChrome.WindowChrome>
<WindowChrome GlassFrameThickness="0 64 0 0" NonClientFrameEdges="Left,Bottom,Right" />
</WindowChrome.WindowChrome>
<Window.Template>
<ControlTemplate TargetType="Window">
<Border Padding="0 30 0 0">
<Grid x:Name="RootGrid" Background="{TemplateBinding Background}">
<Border Background="{TemplateBinding Background}"
VerticalAlignment="Top" Height="30" Margin="0 -29 140 0">
<TextBlock Foreground="White" Margin="16 0" VerticalAlignment="Center"
FontSize="12" Text="{TemplateBinding Title}" />
</Border>
<ContentPresenter />
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="WindowState" Value="Maximized">
<Setter TargetName="RootGrid" Property="Margin" Value="6" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Window.Template>
我在进行主题切换的时候,还剩下右上角的三颗按钮的背景色无法定制。这种样子蠢得要死。查了就很久的网页,解决的办法分成两种,一种复杂一些,要copy 100行代码左右,直接修改Win32 Api 。 另一种是 设置WindowChrome 的属性 UseAeroCaptionButtons =“False” 然后自定义工具栏。
说实在的我感觉这两种都很蠢,都需要很高的代码量,才能解决问题,而且复用性极差。复用只能Copy 代码,还需要按照需求修改 。
于是我又参考了WPF 应用完全模拟 UWP 的标题栏按钮 ,感觉呢,有可能是我很蠢,我直接调用失败了,有些参数,参考里没有给,
写完跑不了。
Segoe MDL2 Assets
这是一个字体图标库,设置字体为里面的参数,就可以使用,就是上面缺失的那个部分。
在Github 里面找到的…..,重新设定参数。 使用方式如下。
<TextBlock Text="" FontFamily="Segoe MDL2 Assets" FontSize="15" Foreground="{DynamicResource WindowTitleBrush}"/>
结束
通过 Ctrl +C ,Ctrl +V ,完美的实现了自定义窗口的效果,并且代码的每个部分都可以单独拆分使用,通过拆解这些代码,就可以完美模仿各种软件上的窗口。比如QQ 的没有最大化的窗口,微信的前置置顶,chrome 的搜索和标签,以及凶残的Office。
本代码模仿 Visual Studio 2019。
最后的完整的参数如下
Xaml
<WindowChrome.WindowChrome>
<WindowChrome GlassFrameThickness="1 64 1 1" NonClientFrameEdges="Right" UseAeroCaptionButtons="False" />
</WindowChrome.WindowChrome>
<Window.Template>
<ControlTemplate TargetType="Window">
<Border Padding="0 30 0 0" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" >
<Grid x:Name="RootGrid" Background="{TemplateBinding Background}">
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Grid Background="{TemplateBinding BorderBrush}" VerticalAlignment="Top" Height="30" Margin="0 -29 0 0" d:LayoutOverrides="LeftMargin, RightMargin, TopMargin, BottomMargin">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="135" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal">
<Image Source="{TemplateBinding Icon}" Height="{x:Static SystemParameters.SmallIconHeight}" Width="{x:Static SystemParameters.SmallIconWidth}" WindowChrome.IsHitTestVisibleInChrome="True" >
</Image>
<ContentControl Foreground="{DynamicResource WindowTitleBrush}" FontSize="{DynamicResource {x:Static SystemFonts.CaptionFontSize}}" Content="{TemplateBinding Title}" VerticalAlignment="Center" Margin="2,0,0,0"/>
</StackPanel>
<StackPanel x:Name="WindowCommandButtonsPanel" Grid.Column="1" HorizontalAlignment="Center" Orientation="Horizontal" WindowChrome.IsHitTestVisibleInChrome="True" Margin="0,0,-1,0">
<Button x:Name="MinimizeButton" Style="{DynamicResource MinimizeButtonStyle}" Width="45" Click="SystemCommands_Click" />
<Grid Margin="1,0,1,0">
<Button x:Name="MaximizeButton" Style="{DynamicResource MaximizeButtonStyle}" Width="45" Click="SystemCommands_Click" />
<Button x:Name="RestoreButton" Style ="{DynamicResource RestoreButtonStyle}" Width="45" Click="SystemCommands_Click" Visibility="Hidden" />
</Grid>
<Button x:Name="CloseButton" Style="{DynamicResource CloseButtonStyle}" Width="45" Click="SystemCommands_Click" />
</StackPanel>
</Grid>
<ContentPresenter Content="{TemplateBinding Content}" Grid.Column="0" Grid.ColumnSpan="1" d:LayoutOverrides="LeftMargin, RightMargin, TopMargin, BottomMargin" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="WindowState" Value="Maximized">
<Setter TargetName="RootGrid" Property="Margin" Value="6" />
<Setter TargetName="MaximizeButton" Property="Visibility" Value="Hidden"/>
<Setter TargetName="RestoreButton" Property="Visibility" Value="Visible"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="ResizeMode" Value="CanResizeWithGrip" />
<Condition Property="WindowState" Value="Normal" />
</MultiTrigger.Conditions>
<Setter TargetName="MaximizeButton" Property="Visibility" Value="Visible"/>
<Setter TargetName="RestoreButton" Property="Visibility" Value="Hidden"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Window.Template>
Xaml.cs
private void SystemCommands_Click(object sender, RoutedEventArgs e)
{
Button button = sender as Button;
switch (button.Name)
{
case "CloseButton":
Close();
break;
case "MinimizeButton":
WindowState = WindowState.Minimized;
break;
case "MaximizeButton":
WindowState = WindowState.Maximized;
break;
case "RestoreButton":
WindowState = WindowState.Normal;
break;
}
}
resourceDictionary
<SolidColorBrush x:Key="WindowBackgroundBrush" Color="White" />
<SolidColorBrush x:Key="WindowTitleBrush" Color="Black" />
<SolidColorBrush x:Key="SubMenuBackgroundBrush" Color="Red"/>
<SolidColorBrush x:Key="StatusBarBackgroundBrush" Color="#007ACC"/>
<Style x:Key="CaptionButtonStyleDefault" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid x:Name="LayoutRoot" Background="Transparent" Width="46" Height="30">
<TextBlock x:Name="txt" Text="{TemplateBinding Content}" FontFamily="Segoe MDL2 Assets" FontSize="10"
Foreground="#868688" HorizontalAlignment="Center" VerticalAlignment="Center"
RenderOptions.ClearTypeHint="Auto" TextOptions.TextRenderingMode="Aliased" TextOptions.TextFormattingMode="Display"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="LayoutRoot" Property="Background" Value="#E5E5E5"/>
<Setter TargetName="txt" Property="Foreground" Value="#000000"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="CaptionButtonStyleClose" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid x:Name="LayoutRoot" Background="Transparent" Width="46" Height="30">
<TextBlock x:Name="txt" Text="{TemplateBinding Content}" FontFamily="Segoe MDL2 Assets" FontSize="10"
Foreground="#868688" HorizontalAlignment="Center" VerticalAlignment="Center"
RenderOptions.ClearTypeHint="Auto" TextOptions.TextRenderingMode="Aliased" TextOptions.TextFormattingMode="Display"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="LayoutRoot" Property="Background" Value="#E81123"/>
<Setter TargetName="txt" Property="Foreground" Value="#FFFFFF"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="MinimizeButtonStyle" TargetType="Button" BasedOn="{StaticResource CaptionButtonStyleDefault}">
<Setter Property="Content" Value=""/>
</Style>
<Style x:Key="MaximizeButtonStyle" TargetType="Button" BasedOn="{StaticResource CaptionButtonStyleDefault}">
<Setter Property="Content" Value=""/>
</Style>
<Style x:Key="RestoreButtonStyle" TargetType="Button" BasedOn="{StaticResource CaptionButtonStyleDefault}">
<Setter Property="Content" Value=""/>
</Style>
<Style x:Key="CloseButtonStyle" TargetType="Button" BasedOn="{StaticResource CaptionButtonStyleClose}">
<Setter Property="Content" Value=""/>
</Style>