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

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

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

博客分类: 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。

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

查看所有标签

猜你喜欢:

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

GUI设计禁忌2.0

GUI设计禁忌2.0

Jeff Johnson / 盛海艳 等 / 机械工业出版社 / 2008 / 49.00元

本书描述软件开发人员在设计图形用户界面(GUI)时经常犯的“禁忌”,并提出避免这些错误的基本原则和理论依据。本书将GUI禁忌分为7种类型:GUI控件禁忌、导航禁忌、文字禁忌、图形设计和布局禁忌、交互禁忌、响应性禁忌以及管理禁忌,并分别进行详述。 本书编排独特,条理清晰,针对性极强,是不可多得的GUI设计优秀资源。本书适合软件开发人员、web站点设计人员、开发经理、用户界面设计人员等阅读。一起来看看 《GUI设计禁忌2.0》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

随机密码生成器
随机密码生成器

多种字符组合密码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具