WPF中自定义标题栏时窗体最大化处理之WindowChrome

栏目: ASP.NET · 发布时间: 7年前

内容简介:根据观察,这个溢出宽度应该是不管使用哪种方法,最大化时,系统的标题栏高度都发生了变化,故,需要重新设置模板中定义的标题栏高度。

博客分类: FAQ

注意:

  • 本文方法基础是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.5SystemParameters 添加了许多系统变量的实现)

实现步骤

第一步:基本实现【保留系统基础操作按钮】

  • 添加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。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

复杂网络理论及其应用

复杂网络理论及其应用

汪小帆、李翔、陈关荣 / 清华大学出版社 / 2006 / 45.00元

国内首部复杂网络专著 【图书目录】 第1章 引论 1.1 引言 1.2 复杂网络研究简史 1.3 基本概念 1.4 本书内容简介 参考文献 第2章 网络拓扑基本模型及其性质 2.1 引言 2.2 规则网络 2.3 随机图 2.4 小世界网络模型 2.5 无标度网络模型 ......一起来看看 《复杂网络理论及其应用》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具