WPF實現(xiàn)自定義窗體的示例代碼
.Net默認(rèn)的窗體樣式只有四種:None、SingleBorderWindow、ThreeDBorderWindow、ToolWindow,都比較“丑”。而很多時候,我們希望自定義窗體,比如,無邊框,有陰影,或者有模糊效果等。
在WPF中,要實現(xiàn)自定義窗體比較簡單,主要有兩種方法:
1)使用WindowChrome;
2)使用WindowStyle = “None”。
一、使用WindowChrome
WindowChrome,可以翻譯為:窗體裝飾條,官方文檔中的定義是:表示一個對象,它描述窗口非工作區(qū)區(qū)域的自定義。(官方鏈接:WindowChrome 類 (System.Windows.Shell) | Microsoft Learn)
在官方的解釋中,窗口由兩部分構(gòu)成:客戶區(qū)域,非客戶區(qū)域。
圖中,Client Area表示客戶區(qū)域;其他的部分,統(tǒng)稱為非客戶區(qū)域。
那么WindowChrome的作用是,將客戶區(qū)域擴(kuò)展至整個窗體(遮住了非客戶區(qū)),同時提供部分標(biāo)準(zhǔn)窗體的功能。如下所示:
<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將客戶區(qū)域擴(kuò)展至整個窗體,并遮住標(biāo)題欄、按鈕等--> <WindowChrome.WindowChrome> <WindowChrome /> </WindowChrome.WindowChrome> <Grid> <TabControl> <TabItem Header="項目"/> <TabItem Header="代碼"/> </TabControl> </Grid> </Window>
備注:這里的邊框,是TabControl的邊框,不是窗體的邊框。
用上WindowChrome后,會驚奇的發(fā)現(xiàn):在原標(biāo)題欄的位置,可以用鼠標(biāo)拖動了;在窗體的四周,可以調(diào)整窗體的大小了!Amazing!
但同時,又出現(xiàn)了一個新的問題:窗體中的所以內(nèi)容,都不能交互(鼠標(biāo)點擊,用戶輸入)了。
這是為什么呢?可以這樣理解。WindowChrome就像一個圖層,它將窗體整個覆蓋住了。因此窗體上的內(nèi)容,自然就操作不了。那要如何才能點擊呢?
這需要給交互控件,添加WindowChrome的附件屬性:IsHitTestVisibleInChrome。如下所示。
<Grid> <!-- 使用WindowChrome的附件屬性 --> <TabControl WindowChrome.IsHitTestVisibleInChrome="True"> <TabItem Header="項目"/> <TabItem Header="代碼"/> </TabControl> </Grid>
如果你以為這樣就萬事大吉了,那只能說太天真了,微軟的東西,哪有那么簡單的呢??哈哈~
如果真的按照這個代碼,你會發(fā)現(xiàn),又不能使用鼠標(biāo)拖動窗體了。這是為什么呢?明明之前都可以,為何為控件添加了一個附加屬性后,就不行了呢?
問題肯定出在WindowChrome上。那么我們再來看看WindowChrome:
圖中有顏色的區(qū)域,實際上均為透明的,看不見的。此處附上顏色則是為了方便解釋。
這個圖就是WindowChrome的模型。其中Caption區(qū)域,表示標(biāo)題欄,就是它,允許窗體被鼠標(biāo)拖動。GlassFrameThickness就是Aero窗體的透明邊框(Aero主體只在部分操作系統(tǒng)中支持)。ResizeBorderThickness就是調(diào)整窗體大小的邊框的粗細(xì),它提供了使用鼠標(biāo)調(diào)整窗體大小的功能。而CornerRadius,則將窗體變成了圓角,它只有在GlassFrameThickness = 0 或者未啟用Aero主體的窗口中才有效。。
再回到上面的問題,為什么添加了附加屬性,就不能用鼠標(biāo)拖動窗體了呢?
原因在于,TabControl進(jìn)入了Caption區(qū)域。因為設(shè)置了附加屬性(IsHitTestVisibleInChrome),表示鼠標(biāo)可以“擊穿”WindowChrome,那么自然就無法“點擊”到Caption區(qū)域,自然就無法拖動窗體了。
那么如果解決這個問題呢?以及如何添加按鈕呢?答案是手動添加標(biāo)題欄。哈哈~ 如下代碼所示:
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將客戶區(qū)域擴(kuò)展至整個窗體,并遮住標(biāo)題欄、按鈕等 --> <WindowChrome.WindowChrome> <!-- 設(shè)置了標(biāo)題欄的高度 = 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; } } // 關(guān)閉窗體 private void Btn_Close(object sender, RoutedEventArgs e) { this.Close(); } }
手動添加了標(biāo)題欄之后,在標(biāo)題欄上,你就可以放上任何你放的東西。。。。
二、使用WindowStyle = "None"
將窗體的WindowStyle屬性設(shè)置為None后,窗體呈現(xiàn)這樣:
<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>
這里,你會發(fā)現(xiàn),窗體可以通過鼠標(biāo)調(diào)整大小,但是不能用鼠標(biāo)拖動。那解決的辦法是什么呢?同樣是手動設(shè)置一個標(biāo)題欄:
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; } // 關(guān)閉窗體 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; } } }
這種方式下,會發(fā)現(xiàn)在窗體的“標(biāo)題欄”上面,還有一點留白無法去除,同樣窗體的邊框也是無法去除的。
到此這篇關(guān)于WPF實現(xiàn)自定義窗體的示例代碼的文章就介紹到這了,更多相關(guān)WPF自定義窗體內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#?wpf實現(xiàn)任意控件更多調(diào)整大小功能
這篇文章主要為大家詳細(xì)介紹了C#?wpf實現(xiàn)任意控件更多調(diào)整大小功能的相關(guān)知識,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-01-01c#中WinForm使用OpencvSharp4實現(xiàn)簡易抓邊
本文主要介紹了c#中WinForm使用OpencvSharp4實現(xiàn)簡易抓邊,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05C#實現(xiàn)將RTF轉(zhuǎn)為HTML的示例代碼
RTF文檔即富文本格式(Rich?Text?Format)的文檔。我們在處理文件時,遇到需要對文檔格式進(jìn)行轉(zhuǎn)換時,可以將RTF轉(zhuǎn)為其他格式,如轉(zhuǎn)為DOCX/DOC、PDF或者HTML。本文將利用C#實現(xiàn)RTF轉(zhuǎn)HTML,需要的可以參考一下2022-04-04C#使用MailAddress類發(fā)送html格式郵件的實例代碼
這篇文章主要介紹如何使用C#的MailAddress類發(fā)送郵件的方法,大家參考使用吧2013-11-11C#使?XmlReader和XmlWriter操作XML?件
這篇文章介紹了C#使?XmlReader和XmlWriter操作XML?件的方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-06-06