上面blog讲了自定义window的样式,可以很容易个构建具有自定义样式的窗体。然而,如果希望整个应用程序使用的我们自定义的窗口标准,就必须以手动的方式重新设置窗口。这是很麻烦的体力劳动。对于这种情况有个更好的解决方法是将标记改编成一个可以用于任何窗口的控件模板(ControlTemplate),有关详细介绍,请看相关文档。
直接贴出代码进行分析:

1 <!-- 应该在此定义应用程序级的资源。--> 2 <Style x:Key="btnTitleMaxMin" TargetType="Button"> 3 <Setter Property="Width" Value="30"></Setter> 4 <Setter Property="Height" Value="30"></Setter> 5 <Setter Property="Cursor" Value="Hand"></Setter> 6 <Setter Property="Margin" Value="1,0,1,0"></Setter> 7 <Setter Property="Foreground" Value="DarkRed"></Setter> 8 <Setter Property="Template"> 9 <Setter.Value> 10 <ControlTemplate TargetType="Button"> 11 12 <Grid> 13 <Grid.ColumnDefinitions> 14 <ColumnDefinition x:Name="columnDefinition1" Width="0.982*"/> 15 <ColumnDefinition x:Name="columnDefinition" Width="0.018*"/> 16 </Grid.ColumnDefinitions> 17 <Border x:Name="rectangle" Background="Transparent" BorderThickness="0" CornerRadius="0" Grid.ColumnSpan="2"></Border> 18 <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/> 19 </Grid> 20 <ControlTemplate.Triggers> 21 <Trigger Property="IsMouseOver" Value="True"> 22 <Setter Property="Background" TargetName="rectangle" Value="RoyalBlue"></Setter> 23 <Setter Property="Foreground" Value="white"></Setter> 24 </Trigger> 25 <Trigger Property="IsPressed" Value="True"> 26 <Setter Property="Background" Value="Transparent"></Setter> 27 </Trigger> 28 </ControlTemplate.Triggers> 29 </ControlTemplate> 30 </Setter.Value> 31 </Setter> 32 </Style> 33 <Style x:Key="btnTitleClose" TargetType="Button"> 34 <Setter Property="Width" Value="35"></Setter> 35 <Setter Property="Height" Value="35"></Setter> 36 <Setter Property="Cursor" Value="Hand"></Setter> 37 <Setter Property="Margin" Value="1,0,1,0"></Setter> 38 <Setter Property="Foreground" Value="DarkRed"></Setter> 39 <Setter Property="Template"> 40 <Setter.Value> 41 <ControlTemplate TargetType="Button"> 42 43 <Grid> 44 <Grid.ColumnDefinitions> 45 <ColumnDefinition x:Name="columnDefinition1" Width="0.982*"/> 46 <ColumnDefinition x:Name="columnDefinition" Width="0.018*"/> 47 </Grid.ColumnDefinitions> 48 <Border x:Name="rectangle" Background="Transparent" CornerRadius="0,4,0,0" Grid.ColumnSpan="2"></Border> 49 <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/> 50 </Grid> 51 <ControlTemplate.Triggers> 52 <Trigger Property="IsMouseOver" Value="True"> 53 <Setter Property="Background" TargetName="rectangle" Value="Firebrick"></Setter> 54 <Setter Property="Foreground" Value="white"></Setter> 55 </Trigger> 56 <Trigger Property="IsPressed" Value="True"> 57 <Setter Property="Background" Value="Transparent"></Setter> 58 </Trigger> 59 60 </ControlTemplate.Triggers> 61 </ControlTemplate> 62 </Setter.Value> 63 </Setter> 64 </Style> 65 66 <!--自定义模板--> 67 <ControlTemplate x:Key="CustomWindowTemplate" TargetType="Window"> 68 <Border BorderBrush="#FF0DAD5F" BorderThickness="3" CornerRadius="4"> 69 <Grid > 70 <Grid.RowDefinitions> 71 <RowDefinition Height="30"></RowDefinition> 72 <RowDefinition></RowDefinition> 73 <RowDefinition Height="5"></RowDefinition> 74 </Grid.RowDefinitions> 75 <Border Background="#FF0DAD5F" BorderBrush="Transparent" MouseDown="Grid_MouseDown" CornerRadius="1,1,0,0"> 76 <Grid Name="Title" Margin="0"> 77 <TextBlock HorizontalAlignment="Left" Margin="10,0,0,0" Text="{TemplateBinding Title}" VerticalAlignment="Center"></TextBlock> 78 <Button ToolTip="最小化" Content="0" FontFamily="Webdings" Name="btnMin" Click="btnMin_Click" HorizontalAlignment="Right" Foreground="White" Margin="0,-9,37,0" Height="26" Width="26" Style="{DynamicResource btnTitleMaxMin}" VerticalAlignment="Center" /> 79 <Button ToolTip="最大化" Content="1" FontFamily="Webdings" Name="btnMaxOrMin" Click="btnMaxOrMin_Click" HorizontalAlignment="Right" Foreground="White" Margin="0,-9,17,0" Height="26" Width="26" Style="{DynamicResource btnTitleMaxMin}" VerticalAlignment="Center" /> 80 <Button ToolTip="关闭" Content="r" FontFamily="Webdings" Name="PART_CLOSEBTN" HorizontalAlignment="Right" Foreground="White" Margin="0,-9,-3,0" Height="26" Width="26" Style="{DynamicResource btnTitleClose}" VerticalAlignment="Center" Click="Button_Click" /> 81 </Grid> 82 </Border> 83 <Grid Grid.Row="1" Background="White" > 84 <Grid Margin="5,5,5,0"> 85 <AdornerDecorator> 86 <ContentPresenter></ContentPresenter> 87 </AdornerDecorator> 88 </Grid> 89 </Grid> 90 91 <Grid Grid.Row="2" Background="White"> 92 <ResizeGrip Name="WindowResizeGrip" Visibility="Collapsed" IsTabStop="False" HorizontalAlignment="Right" FontWeight="Black" VerticalAlignment="Bottom"> 93 94 </ResizeGrip> 95 <!--<Border Height="5" Width="5" Background="Red" CornerRadius="500,0,0,0" VerticalAlignment="Bottom" HorizontalAlignment="Right" Cursor="SizeNWSE" MouseLeftButtonDown="Border_MouseLeftButtonDown" MouseLeftButtonUp="Border_MouseLeftButtonUp" MouseMove="Border_MouseMove"> 96 97 </Border>--> 98 99 </Grid> 100 </Grid> 101 102 </Border> 103 <ControlTemplate.Triggers> 104 <Trigger Property="ResizeMode" Value="CanResizeWithGrip"> 105 <Setter TargetName="WindowResizeGrip" Property="Visibility" Value="Visible"></Setter> 106 </Trigger> 107 <Trigger Property="WindowState" Value="Maximized"> 108 <Setter TargetName="btnMaxOrMin" Property="Content" Value="2"></Setter> 109 <Setter TargetName="btnMaxOrMin" Property="ToolTip" Value="还原"></Setter> 110 </Trigger> 111 </ControlTemplate.Triggers> 112 </ControlTemplate>
该模板的顶级元素是Border作为窗体的边框。在border对象内部是一个具有三行的grid面板,分别是表示标题栏、内容、和ResizeGrip对象,用户手动改变窗口的尺寸。
下面就来实现窗体的各种行为,最大化、关闭;
上面的模板是在添加在对象级资源里面的,放置在App.Xaml文件 <Application.Resources>里面.就直接在对应的App.Xaml.cs写相应的事件。在写相应事件之前需要解决一个问题,那就是,现在代码是运行在资源对象,而不是运行在窗口对象中,就不能使用this关键字访问当前窗体,我们就用另一种方式来实现:使用FrameworkElement.TemplatedParent属性。
注:上面实现的模板可以建立在资源字典中,并为资源字典创建代码隐藏类,添加相应的事件处理程序。详细请参考相应文档。(推荐:wpf编程宝典-C#2010版)
控件模板到此已经搞定,那面就建立一个简单的样式应用窗口模板,关键一点是该样式需要设置window类的三个关键属性以使窗口透明。
代码如下:
<Style x:Key="CustomWindowChrome" TargetType="Window">
<Setter Property="AllowsTransparency" Value="True"></Setter>
<Setter Property="WindowStyle" Value="None"></Setter>
<Setter Property="Background" Value="Transparent"></Setter>
<Setter Property="Template" Value="{StaticResource CustomWindowTemplate}"></Setter>
</Style>
注:本次实现的改变窗口尺寸使用了Window.ResizeMode属性,设置这个属性为CanResizeWithGrip,在窗体右下角会显示手柄,鼠标移动修改窗口尺寸。
样式已经定义好,直接在窗体中引用,修改为自定义的窗体样式:
Style="{StaticResource CustomWindowChrome}"
ok,一个自定义的简单的窗口就实现了,通过修改控件模板来达到自己需要的窗口效果,以满足不同的应用程序。本窗体中,按钮样式只使用了一种,有兴趣的同学可以修改关闭和最大化使用不同样式的,以及图标,做出更适合现代应用程序,更具有吸引力的窗口,还需多多改进。
还是贴个效果图吧:

最大化效果:
