.Net預設的表單樣式只有四種:None、SingleBorderWindow、ThreeDBorderWindow、ToolWindow,都比較「醜」。而很多時候,我們希望自定義表單,比如,無邊框,有陰影,或者有模糊效果等。
在WPF中,要實現自定義表單比較簡單,主要有兩種方法:
1)使用WindowChrome;
2)使用WindowStyle = 「None」。
WindowChrome,可以翻譯為:表單裝飾條,官方檔案中的定義是:表示一個物件,它描述視窗非工作區區域的自定義。(官方連結:WindowChrome 類 (System.Windows.Shell) | Microsoft Learn)
在官方的解釋中,視窗由兩部分構成:客戶區域,非客戶區域。
圖中,Client Area表示客戶區域;其他的部分,統稱為非客戶區域。
那麼WindowChrome的作用是,將客戶區域擴充套件至整個表單(遮住了非客戶區),同時提供部分標準表單的功能。如下所示:
<Window x:Class="ControlTest.WindowNone"
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:ControlTest"
mc:Ignorable="d"
Title="WindowNone" Height="450" Width="800">
<!-- WindowChrome將客戶區域擴充套件至整個表單,並遮住標題列、按鈕等-->
<WindowChrome.WindowChrome>
<WindowChrome />
</WindowChrome.WindowChrome>
<Grid>
<TabControl>
<TabItem Header="專案"/>
<TabItem Header="程式碼"/>
</TabControl>
</Grid>
</Window>
備註:這裡的邊框,是TabControl的邊框,不是表單的邊框。
用上WindowChrome後,會驚奇的發現:在原標題列的位置,可以用滑鼠拖動了;在表單的四周,可以調整表單的大小了!Amazing!
但同時,又出現了一個新的問題:表單中的所以內容,都不能互動(滑鼠點選,使用者輸入)了。
這是為什麼呢?可以這樣理解。WindowChrome就像一個圖層,它將表單整個覆蓋住了。因此表單上的內容,自然就操作不了。那要如何才能點選呢?
這需要給互動控制元件,新增WindowChrome的附件屬性:IsHitTestVisibleInChrome。如下所示。
<Grid>
<!-- 使用WindowChrome的附件屬性 -->
<TabControl WindowChrome.IsHitTestVisibleInChrome="True">
<TabItem Header="專案"/>
<TabItem Header="程式碼"/>
</TabControl>
</Grid>
如果你以為這樣就萬事大吉了,那隻能說太天真了,微軟的東西,哪有那麼簡單的呢??哈哈~
如果真的按照這個程式碼,你會發現,又不能使用滑鼠拖動表單了。這是為什麼呢?明明之前都可以,為何為控制元件新增了一個附加屬性後,就不行了呢?
問題肯定出在WindowChrome上。那麼我們再來看看WindowChrome:
圖中有顏色的區域,實際上均為透明的,看不見的。此處附上顏色則是為了方便解釋。
這個圖就是WindowChrome的模型。其中Caption區域,表示標題列,就是它,允許表單被滑鼠拖動。GlassFrameThickness就是Aero表單的透明邊框(Aero主體只在部分作業系統中支援)。ResizeBorderThickness就是調整表單大小的邊框的粗細,它提供了使用滑鼠調整表單大小的功能。而CornerRadius,則將表單變成了圓角,它只有在GlassFrameThickness = 0 或者未啟用Aero主體的視窗中才有效。。
再回到上面的問題,為什麼新增了附加屬性,就不能用滑鼠拖動表單了呢?
原因在於,TabControl進入了Caption區域。因為設定了附加屬性(IsHitTestVisibleInChrome),表示滑鼠可以「擊穿」WindowChrome,那麼自然就無法「點選」到Caption區域,自然就無法拖動表單了。
那麼如果解決這個問題呢?以及如何新增按鈕呢?答案是手動新增標題列。哈哈~ 如下程式碼所示:
Xaml程式碼: <Window x:Class="ControlTest.WindowNone" 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:ControlTest" mc:Ignorable="d" Title="WindowNone" Height="450" Width="800"> <!-- WindowChrome將客戶區域擴充套件至整個表單,並遮住標題列、按鈕等 --> <WindowChrome.WindowChrome>
<!-- 設定了標題列的高度 = 30,圓角 = 20 --> <WindowChrome CaptionHeight="30" CornerRadius="20" GlassFrameThickness="0"/> </WindowChrome.WindowChrome> <Border BorderThickness="1"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <Border Height="30" Background="YellowGreen"> <Grid> <Grid.Resources> <Style TargetType="Button"> <Setter Property="Width" Value="30"/> <Setter Property="Background" Value="Transparent"/> <Setter Property="BorderThickness" Value="0"/> </Style> </Grid.Resources> <StackPanel Orientation="Horizontal" WindowChrome.IsHitTestVisibleInChrome="True"> <Image /> <TextBlock VerticalAlignment="Center" Margin="3,0" Text="{Binding Title, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"/> </StackPanel> <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" WindowChrome.IsHitTestVisibleInChrome="True"> <Button Content="_" Click="Btn_Min"/> <Button Content="Max" Click="Btn_Max"/> <Button Content="X" Click="Btn_Close"/> </StackPanel> </Grid> </Border> <!-- 使用WindowChrome的附件屬性 --> <TabControl Grid.Row="1" WindowChrome.IsHitTestVisibleInChrome="True"> <TabItem Header="專案"/> <TabItem Header="程式碼"/> </TabControl> </Grid> </Border> </Window> C# 程式碼: public partial class WindowNone : Window { public WindowNone() { InitializeComponent(); }
// 最小化 private void Btn_Min(object sender, RoutedEventArgs e) { this.WindowState = WindowState.Minimized; }
// 最大化、還原 private void Btn_Max(object sender, RoutedEventArgs e) { if(this.WindowState == WindowState.Normal) { this.WindowState = WindowState.Maximized; } else { this.WindowState = WindowState.Normal; } }
// 關閉表單 private void Btn_Close(object sender, RoutedEventArgs e) { this.Close(); } }
手動新增了標題列之後,在標題列上,你就可以放上任何你放的東西。。。。
將表單的WindowStyle屬性設定為None後,表單呈現這樣:
<Window x:Class="ControlTest.NoneWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" Title="NoneWindow" Height="450" Width="800" WindowStyle="None"> <Grid> <TabControl> <TabItem Header="專案"/> <TabItem Header="程式碼"/> </TabControl> </Grid> </Window>
這裡,你會發現,表單可以通過滑鼠調整大小,但是不能用滑鼠拖動。那解決的辦法是什麼呢?同樣是手動設定一個標題列:
Xaml 程式碼: <Window x:Class="ControlTest.NoneWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" Title="NoneWindow" Height="450" Width="800" WindowStyle="None" BorderThickness="0" BorderBrush="Transparent"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <Border Height="30" Background="YellowGreen" MouseDown="TitleMove"> <Grid> <Grid.Resources> <Style TargetType="Button"> <Setter Property="Width" Value="30"/> <Setter Property="Background" Value="Transparent"/> <Setter Property="BorderThickness" Value="0"/> </Style> </Grid.Resources> <StackPanel Orientation="Horizontal" WindowChrome.IsHitTestVisibleInChrome="True"> <Image /> <TextBlock VerticalAlignment="Center" Margin="3,0" Text="{Binding Title, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"/> </StackPanel> <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" WindowChrome.IsHitTestVisibleInChrome="True"> <Button Content="_" Click="Btn_Min"/> <Button Content="Max" Click="Btn_Max"/> <Button Content="X" Click="Btn_Close"/> </StackPanel> </Grid> </Border> <TabControl Grid.Row="1" Margin="10"> <TabItem Header="專案"/> <TabItem Header="程式碼"/> </TabControl> </Grid> </Window> C# 程式碼: public partial class NoneWindow : Window { public NoneWindow() { InitializeComponent(); } // 表單移動 private void TitleMove(object sender, MouseButtonEventArgs e) { if (e.ChangedButton != MouseButton.Left) return; // 非左鍵點選,退出 if (e.ClickCount == 1) { this.DragMove(); // 拖動表單 } else { WindowMax(); // 雙擊時,最大化或者還原表單 } } // 最小化 private void Btn_Min(object sender, RoutedEventArgs e) { this.WindowState = WindowState.Minimized; } // 關閉表單 private void Btn_Close(object sender, RoutedEventArgs e) { this.Close(); } // 最大化、還原 private void Btn_Max(object sender, RoutedEventArgs e) { WindowMax(); } private void WindowMax() { if (this.WindowState == WindowState.Normal) { this.WindowState = WindowState.Maximized; } else { this.WindowState = WindowState.Normal; } } }
這種方式下,會發現在表單的「標題列」上面,還有一點留白無法去除,同樣表單的邊框也是無法去除的。
如果解決?且聽下回分解。