要实现以下目标:
1、窗口标题栏颜色可定义。
2、标题栏可添加控件。
3、为引用方便,只使用XAML。
使用WindowChrome是方便的办法,但遇到如下问题:
1、窗口最大化后,窗口边缘超出屏幕。
2、自定义的最小化、最大化、关闭按钮功能如何用XAML实现。
3、用鼠标拉伸改变窗口大小时,会出现闪烁。
经过参考,并想一些小技巧,终于解决。
1、解决最大化后边缘超出屏幕
设: a = SystemParameters.MaximizedPrimaryScreenWidth
b=SystemParameters.PrimaryScreenWidth
超出部分尺寸:h = (a-b)/2
可在最大化时四周增加h单位Margin,使显示内容不超出屏幕。
同时最大化时标题栏显示区域高度减少h单位,使得与WindowChrome定义的CaptionHeight对齐。
由于涉及到减法运算,XAML没有加减功能,用Grid自动布局的特性,设计一个运算器.
同理可求最大化时标题栏减少后的高度
2、用纯XAML实现窗口右上角按钮功能
需用到Microsoft.Xaml.Behaviors.Wpf扩展包,先用NuGet下载安装,
再把其命名空间引入: xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
这使按钮可直接调用Window方法。
如实现关闭窗口:
<b:Interaction.Triggers>
<b:EventTrigger EventName="Click">
<b:CallMethodAction TargetObject="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" MethodName="Close"/>
</b:EventTrigger>
</b:Interaction.Triggers>
3、消除拉伸改变窗口尺寸时白色闪烁
只需设定WindowChrome属性 NonClientFrameEdges="Right"
未尽事宜全在代码中
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
>
<!--通过下面3个参数调整标题栏高度与resize区域宽度-->
<!--CaptionAreaHeight 为窗口正常状态下标题栏的总高度,包括拖动窗口的区域与改变大小区域-->
<!-- CaptionAreaHeight = CaptionHeight + ResizeBorderThickness.top -->
<sys:Double x:Key="CaptionAreaHeight">36</sys:Double>
<sys:Double x:Key="CaptionHeight">30</sys:Double>
<Thickness x:Key="ResizeBorderThickness">10 6 10 10</Thickness>
<!--标题栏背景色与前景色-->
<Brush x:Key="CaptionBackground">#202020</Brush>
<Brush x:Key="CaptionForeground">#d6d6d6</Brush>
<!--MouseOver按钮背景色-->
<Brush x:Key="MouseOverButtonColor">#2d2d2d</Brush>
<!--标题栏关闭按钮-->
<Style x:Key="CloseButton" TargetType="Button">
<Setter Property="Width" Value="50"/>
<!--WindowChrome.IsHitTestVisibleInChrome=True 让按钮在自定义的标题栏里能被点按-->
<Setter Property="WindowChrome.IsHitTestVisibleInChrome" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button" >
<Border x:Name="border" CornerRadius="0" Background="Transparent">
<ContentPresenter Margin="0 1 1 0"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="Background" Value="#c42b1c"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="border" Property="Opacity" Value="0.8"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!--标题栏按钮-->
<Style x:Key="CaptionButton" TargetType="Button">
<Setter Property="Width" Value="50"/>
<Setter Property="WindowChrome.IsHitTestVisibleInChrome" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button" >
<Border x:Name="border" CornerRadius="0" Background="Transparent">
<ContentPresenter Margin="0 1 1 0"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="Background" Value="{StaticResource MouseOverButtonColor}"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="border" Property="Opacity" Value="0.8"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!--窗口-->
<Style x:Key="ChromeWindow" TargetType="Window">
<!--NonClientFrameEdges="Right"避免拉伸时出现闪烁-->
<Setter Property="WindowChrome.WindowChrome">
<Setter.Value>
<WindowChrome
NonClientFrameEdges="Right"
CaptionHeight="{StaticResource CaptionHeight}"
ResizeBorderThickness="{StaticResource ResizeBorderThickness}"
UseAeroCaptionButtons="False"
/>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Window">
<Grid Background="{TemplateBinding Background}" >
<!--通过元素自动分布,计算最大化后超出屏幕的尺寸-->
<!--计算公式: (SystemParameters.MaximizedPrimaryScreenWidth - SystemParameters.PrimaryScreenWidth)/2 -->
<Grid Height="0" Width="{x:Static SystemParameters.MaximizedPrimaryScreenWidth}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border x:Name="outOfScreenPart" Grid.Column="0" Background="Yellow"/>
<Border Grid.Column="1" Background="Red" Width="{x:Static SystemParameters.PrimaryScreenWidth}"/>
<Border Grid.Column="2" Background="Yellow"/>
</Grid>
<!--计算最大化后标题栏显示的高度-->
<!--计算公式:CaptionAreaHeight - outOfScreenPart.ActualWidth -->
<Grid Height="0" Width="{StaticResource CaptionAreaHeight}" Background="Green">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0" Background="Red" Width="{Binding ElementName=outOfScreenPart, Path=ActualWidth}"/>
<Border x:Name="maximizedCaptionPart" Grid.Column="1" Background="Yellow"/>
</Grid>
<Grid x:Name="winGrid">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--标题栏区域-->
<Grid Background="{StaticResource CaptionBackground}" x:Name="captionGrid" Height="{StaticResource CaptionAreaHeight}">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="10,0">
<!--标题绑定窗口Title-->
<TextBlock Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=Title}" Foreground="{StaticResource CaptionForeground}"/>
</StackPanel>
<!--右侧按钮-->
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<!--最小化按钮-->
<Button Style="{StaticResource CaptionButton}">
<Path Data="M 0 0 L 9 0" Stroke="{StaticResource CaptionForeground}" StrokeThickness="1"/>
<b:Interaction.Triggers>
<b:EventTrigger EventName="Click">
<b:ChangePropertyAction TargetObject="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" PropertyName="WindowState" Value="1"/>
</b:EventTrigger>
</b:Interaction.Triggers>
</Button>
<!--最大化按钮-->
<Button Style="{StaticResource CaptionButton}" Name="maxbt">
<Path Data="M 0 0 L 9 0 L 9 9 L 0 9 Z" Stroke="{StaticResource CaptionForeground}" StrokeThickness="1"/>
<b:Interaction.Triggers>
<b:EventTrigger EventName="Click">
<b:ChangePropertyAction TargetObject="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" PropertyName="WindowState" Value="2"/>
</b:EventTrigger>
</b:Interaction.Triggers>
</Button>
<!--正常化按钮-->
<Button Style="{StaticResource CaptionButton}" Name="normalbt">
<Path Data="M 2 2 L 2 0 L 9 0 L 9 7 L 7 7 M 0 2 L 7 2 L 7 9 L 0 9 Z" Stroke="{StaticResource CaptionForeground}" StrokeThickness="1"/>
<b:Interaction.Triggers>
<b:EventTrigger EventName="Click">
<b:ChangePropertyAction TargetObject="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" PropertyName="WindowState" Value="0"/>
</b:EventTrigger>
</b:Interaction.Triggers>
</Button>
<!--关闭按钮-->
<Button Style="{StaticResource CloseButton}">
<Path Data="M 0 0 L 9 9 M 9 0 L 0 9" Stroke="{StaticResource CaptionForeground}" StrokeThickness="1"/>
<b:Interaction.Triggers>
<b:EventTrigger EventName="Click">
<b:CallMethodAction TargetObject="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" MethodName="Close"/>
</b:EventTrigger>
</b:Interaction.Triggers>
</Button>
</StackPanel>
</Grid>
<!--窗口工作区-->
<ContentPresenter Grid.Row="1" x:Name="win_content"></ContentPresenter>
</Grid>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="WindowState" Value="Maximized">
<!--最大化后避免内容到屏幕外-->
<Setter TargetName="winGrid" Property="Margin" Value="{Binding ElementName=outOfScreenPart, Path=ActualWidth}"/>
<!--最大化后,windowChrome标题栏一部分会到屏幕外,为了区域对齐,相应缩小可见标题栏显示区域高度-->
<Setter TargetName="captionGrid" Property="Height" Value="{Binding ElementName=maximizedCaptionPart, Path=ActualWidth}"/>
<!--最大化后隐藏最大化按钮-->
<Setter TargetName="maxbt" Property="Width" Value="0"/>
</Trigger>
<Trigger Property="WindowState" Value="Normal">
<!--正常大小后隐藏正常化按钮-->
<Setter TargetName="normalbt" Property="Width" Value="0"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="WindowState" Value="Maximized">
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
窗口直接应用Style即可
<Window x:Class="TouchEditor4_1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TouchEditor4_1"
Title="MainWindow" Height="450" Width="800" Background="Blue" Style="{StaticResource ChromeWindow}">
<Grid>
</Grid>
</Window>