上面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,一個自定義的簡單的窗口就實現了,通過修改控件模板來達到自己需要的窗口效果,以滿足不同的應用程序。本窗體中,按鈕樣式只使用了一種,有興趣的同學可以修改關閉和最大化使用不同樣式的,以及圖標,做出更適合現代應用程序,更具有吸引力的窗口,還需多多改進。
還是貼個效果圖吧:

最大化效果:
