WPF實(shí)現(xiàn)自定義窗體的示例代碼
.Net默認(rèn)的窗體樣式只有四種:None、SingleBorderWindow、ThreeDBorderWindow、ToolWindow,都比較“丑”。而很多時(shí)候,我們希望自定義窗體,比如,無(wú)邊框,有陰影,或者有模糊效果等。
在WPF中,要實(shí)現(xiàn)自定義窗體比較簡(jiǎn)單,主要有兩種方法:
1)使用WindowChrome;
2)使用WindowStyle = “None”。
一、使用WindowChrome
WindowChrome,可以翻譯為:窗體裝飾條,官方文檔中的定義是:表示一個(gè)對(duì)象,它描述窗口非工作區(qū)區(qū)域的自定義。(官方鏈接:WindowChrome 類 (System.Windows.Shell) | Microsoft Learn)
在官方的解釋中,窗口由兩部分構(gòu)成:客戶區(qū)域,非客戶區(qū)域。

圖中,Client Area表示客戶區(qū)域;其他的部分,統(tǒng)稱為非客戶區(qū)域。
那么WindowChrome的作用是,將客戶區(qū)域擴(kuò)展至整個(gè)窗體(遮住了非客戶區(qū)),同時(shí)提供部分標(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ò)展至整個(gè)窗體,并遮住標(biāo)題欄、按鈕等-->
<WindowChrome.WindowChrome>
<WindowChrome />
</WindowChrome.WindowChrome>
<Grid>
<TabControl>
<TabItem Header="項(xiàng)目"/>
<TabItem Header="代碼"/>
</TabControl>
</Grid>
</Window>

備注:這里的邊框,是TabControl的邊框,不是窗體的邊框。
用上WindowChrome后,會(huì)驚奇的發(fā)現(xiàn):在原標(biāo)題欄的位置,可以用鼠標(biāo)拖動(dòng)了;在窗體的四周,可以調(diào)整窗體的大小了!Amazing!
但同時(shí),又出現(xiàn)了一個(gè)新的問(wèn)題:窗體中的所以內(nèi)容,都不能交互(鼠標(biāo)點(diǎn)擊,用戶輸入)了。
這是為什么呢?可以這樣理解。WindowChrome就像一個(gè)圖層,它將窗體整個(gè)覆蓋住了。因此窗體上的內(nèi)容,自然就操作不了。那要如何才能點(diǎn)擊呢?
這需要給交互控件,添加WindowChrome的附件屬性:IsHitTestVisibleInChrome。如下所示。
<Grid>
<!-- 使用WindowChrome的附件屬性 -->
<TabControl WindowChrome.IsHitTestVisibleInChrome="True">
<TabItem Header="項(xiàng)目"/>
<TabItem Header="代碼"/>
</TabControl>
</Grid>如果你以為這樣就萬(wàn)事大吉了,那只能說(shuō)太天真了,微軟的東西,哪有那么簡(jiǎn)單的呢??哈哈~
如果真的按照這個(gè)代碼,你會(huì)發(fā)現(xiàn),又不能使用鼠標(biāo)拖動(dòng)窗體了。這是為什么呢?明明之前都可以,為何為控件添加了一個(gè)附加屬性后,就不行了呢?
問(wèn)題肯定出在WindowChrome上。那么我們?cè)賮?lái)看看WindowChrome:

圖中有顏色的區(qū)域,實(shí)際上均為透明的,看不見的。此處附上顏色則是為了方便解釋。
這個(gè)圖就是WindowChrome的模型。其中Caption區(qū)域,表示標(biāo)題欄,就是它,允許窗體被鼠標(biāo)拖動(dòng)。GlassFrameThickness就是Aero窗體的透明邊框(Aero主體只在部分操作系統(tǒng)中支持)。ResizeBorderThickness就是調(diào)整窗體大小的邊框的粗細(xì),它提供了使用鼠標(biāo)調(diào)整窗體大小的功能。而CornerRadius,則將窗體變成了圓角,它只有在GlassFrameThickness = 0 或者未啟用Aero主體的窗口中才有效。。
再回到上面的問(wèn)題,為什么添加了附加屬性,就不能用鼠標(biāo)拖動(dòng)窗體了呢?
原因在于,TabControl進(jìn)入了Caption區(qū)域。因?yàn)樵O(shè)置了附加屬性(IsHitTestVisibleInChrome),表示鼠標(biāo)可以“擊穿”WindowChrome,那么自然就無(wú)法“點(diǎn)擊”到Caption區(qū)域,自然就無(wú)法拖動(dòng)窗體了。
那么如果解決這個(gè)問(wèn)題呢?以及如何添加按鈕呢?答案是手動(dòng)添加標(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ò)展至整個(gè)窗體,并遮住標(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="項(xiàng)目"/>
<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();
}
}

手動(dòng)添加了標(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="項(xiàng)目"/>
<TabItem Header="代碼"/>
</TabControl>
</Grid>
</Window>
這里,你會(huì)發(fā)現(xiàn),窗體可以通過(guò)鼠標(biāo)調(diào)整大小,但是不能用鼠標(biāo)拖動(dòng)。那解決的辦法是什么呢?同樣是手動(dòng)設(shè)置一個(gè)標(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="項(xiàng)目"/>
<TabItem Header="代碼"/>
</TabControl>
</Grid>
</Window>C# 代碼:
public partial class NoneWindow : Window
{
public NoneWindow()
{
InitializeComponent();
}
// 窗體移動(dòng)
private void TitleMove(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton != MouseButton.Left) return; // 非左鍵點(diǎn)擊,退出
if (e.ClickCount == 1)
{
this.DragMove(); // 拖動(dòng)窗體
}
else
{
WindowMax(); // 雙擊時(shí),最大化或者還原窗體
}
}
// 最小化
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;
}
}
}
這種方式下,會(huì)發(fā)現(xiàn)在窗體的“標(biāo)題欄”上面,還有一點(diǎn)留白無(wú)法去除,同樣窗體的邊框也是無(wú)法去除的。
到此這篇關(guān)于WPF實(shí)現(xiàn)自定義窗體的示例代碼的文章就介紹到這了,更多相關(guān)WPF自定義窗體內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#?wpf實(shí)現(xiàn)任意控件更多調(diào)整大小功能
這篇文章主要為大家詳細(xì)介紹了C#?wpf實(shí)現(xiàn)任意控件更多調(diào)整大小功能的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-01-01
c#中WinForm使用OpencvSharp4實(shí)現(xiàn)簡(jiǎn)易抓邊
本文主要介紹了c#中WinForm使用OpencvSharp4實(shí)現(xiàn)簡(jiǎn)易抓邊,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05
C#實(shí)現(xiàn)將RTF轉(zhuǎn)為HTML的示例代碼
RTF文檔即富文本格式(Rich?Text?Format)的文檔。我們?cè)谔幚砦募r(shí),遇到需要對(duì)文檔格式進(jìn)行轉(zhuǎn)換時(shí),可以將RTF轉(zhuǎn)為其他格式,如轉(zhuǎn)為DOCX/DOC、PDF或者HTML。本文將利用C#實(shí)現(xiàn)RTF轉(zhuǎn)HTML,需要的可以參考一下2022-04-04
C#使用MailAddress類發(fā)送html格式郵件的實(shí)例代碼
這篇文章主要介紹如何使用C#的MailAddress類發(fā)送郵件的方法,大家參考使用吧2013-11-11
C#使?XmlReader和XmlWriter操作XML?件
這篇文章介紹了C#使?XmlReader和XmlWriter操作XML?件的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06

