C#?wpf?無(wú)邊框窗口添加陰影效果的實(shí)現(xiàn)
前言
制作無(wú)邊框窗口時(shí),系統(tǒng)自帶陰影會(huì)消失,這時(shí)就需要我自己給窗口添加陰影以防止窗口融入背景。添加陰影的方法很簡(jiǎn)單,直接用effect就可以了,但這里還是有個(gè)不容易注意到的細(xì)節(jié)需要處理,加陰影后窗口最大化可能會(huì)有問(wèn)題。
一、如何實(shí)現(xiàn)?
1、去除邊框
(1)方法一
使用WindowStyle可以去除窗口邊框,AllowsTransparency+Background制造透明窗口為陰影留出透明邊距。
注:此方法較影響窗口渲染性能。
<Window WindowStyle="None" AllowsTransparency="True" Background="Transparent" >
(2)方法二
使用WindowChrome也可以實(shí)現(xiàn)無(wú)邊框窗口,.net4.5之后可以使用此組件。WindowChrome通常不會(huì)影響渲染性能。
<Window WindowStyle="None" Background="Transparent" ResizeMode="NoResize">
<WindowChrome.WindowChrome>
<WindowChrome GlassFrameThickness="-1" CaptionHeight="0" />
</WindowChrome.WindowChrome
<Grid>
</Grid>
</Window>2、添加陰影
使用DropShadowEffect 加Margin屬性即可。添加陰影特效后,需要設(shè)置margin給陰影留出邊距,否則是看不到陰影的。通常到這一步就結(jié)束了,如果窗口需要最大化則繼續(xù)往下。
<Window >
<Grid Margin="10" Background="White">
<Grid.Effect>
<DropShadowEffect ShadowDepth="0" BlurRadius="10" Opacity="0.8" Color="#AAAAAA"/>
</Grid.Effect>
</Grid>
</Window>3、添加觸發(fā)器
1、 為何添加觸發(fā)器?
根據(jù)上述2個(gè)步驟添加完陰影后,如果將窗口最大化就會(huì)發(fā)現(xiàn),Margin依然生效,全屏窗口有一個(gè)透明外邊距,為了解決這問(wèn)題所以需要添加觸發(fā)器。

2、 具體實(shí)現(xiàn)
在style中使用觸發(fā)器,綁定窗口狀態(tài),當(dāng)最大化時(shí)邊距設(shè)為0,其他情況設(shè)為陰影需要的邊距。在這里需要注意的是此時(shí)Grid不可以設(shè)置Margin屬性了只能在觸發(fā)器中設(shè)置,因?yàn)橘x值優(yōu)先級(jí)的原因,在Grid中設(shè)置Margin后觸發(fā)器的賦值會(huì)失效。
<Grid Background="#1e1e1e">
<Grid.Style>
<Style TargetType="Grid">
<!--給陰影留出邊距-->
<Style.Triggers>
<DataTrigger Binding="{Binding WindowState, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" Value="Normal">
<Setter Property="Margin" Value="10" />
</DataTrigger>
<DataTrigger Binding="{Binding WindowState, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" Value="Minimized">
<Setter Property="Margin" Value="10" />
</DataTrigger>
<DataTrigger Binding="{Binding WindowState, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" Value="Maximized">
<Setter Property="Margin" Value="0" />
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Style>
</Grid>二、示例代碼
MainWindow.xaml
<Window x:Class="WpfApp8.MainWindow"
? ? ? ? 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:WpfApp8"
? ? ? ? mc:Ignorable="d"
? ? ? ? Title="MainWindow" Height="450" Width="800"
? ? ? ? WindowStyle="None"
? ? ? ? Background="Transparent"
? ? ? ? ResizeMode="NoResize"
? ? ? ? >
? ? <WindowChrome.WindowChrome>
? ? ? ? <WindowChrome GlassFrameThickness="-1" ? CaptionHeight="0" ? />
? ? </WindowChrome.WindowChrome>
? ? <Grid ?Background="white">
? ? ? ? <Grid.Effect>
? ? ? ? ? ? <DropShadowEffect ShadowDepth="0" BlurRadius="10" Opacity="0.8" Color="#AAAAAA"/>
? ? ? ? </Grid.Effect>
? ? ? ? <Grid.Style>
? ? ? ? ? ? <Style TargetType="Grid">
? ? ? ? ? ? ? ? <!--給陰影留出邊距-->
? ? ? ? ? ? ? ? <Style.Triggers>
? ? ? ? ? ? ? ? ? ? <DataTrigger Binding="{Binding WindowState, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" Value="Normal">
? ? ? ? ? ? ? ? ? ? ? ? <Setter Property="Margin" Value="10" />
? ? ? ? ? ? ? ? ? ? </DataTrigger>
? ? ? ? ? ? ? ? ? ? <DataTrigger Binding="{Binding WindowState, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" Value="Minimized">
? ? ? ? ? ? ? ? ? ? ? ? <Setter Property="Margin" Value="10" />
? ? ? ? ? ? ? ? ? ? </DataTrigger>
? ? ? ? ? ? ? ? ? ? <DataTrigger Binding="{Binding WindowState, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" Value="Maximized">
? ? ? ? ? ? ? ? ? ? ? ? <Setter Property="Margin" Value="0" />
? ? ? ? ? ? ? ? ? ? </DataTrigger>
? ? ? ? ? ? ? ? </Style.Triggers>
? ? ? ? ? ? </Style>
? ? ? ? </Grid.Style>
? ? ? ? <!--標(biāo)題欄-->
? ? ? ? <Grid ?VerticalAlignment="Top" ?>
? ? ? ? ? ? <StackPanel Margin="0,0,10,0" HorizontalAlignment="Right" Orientation="Horizontal">
? ? ? ? ? ? ? ? <!--最小化按鈕-->
? ? ? ? ? ? ? ? <Button Width="50" Height="50" Focusable="False" VerticalAlignment="Center" Cursor="Hand" ?Click="Button_Click_1" >
? ? ? ? ? ? ? ? ? ? <Button.Template>
? ? ? ? ? ? ? ? ? ? ? ? <ControlTemplate TargetType="Button">
? ? ? ? ? ? ? ? ? ? ? ? ? ? <Grid x:Name="grd" Background="Transparent">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <Rectangle Width="20" Height="3" Fill="#1e1e1e" ></Rectangle>
? ? ? ? ? ? ? ? ? ? ? ? ? ? </Grid>
? ? ? ? ? ? ? ? ? ? ? ? ? ? <ControlTemplate.Triggers>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <Trigger Property="IsMouseOver" Value="True">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <Setter TargetName="grd" Property="Background" Value="#666666"></Setter>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? </Trigger>
? ? ? ? ? ? ? ? ? ? ? ? ? ? </ControlTemplate.Triggers>
? ? ? ? ? ? ? ? ? ? ? ? </ControlTemplate>
? ? ? ? ? ? ? ? ? ? </Button.Template>
? ? ? ? ? ? ? ? </Button>
? ? ? ? ? ? ? ? <!--最大化按鈕-->
? ? ? ? ? ? ? ? <Button Width="50" Height="50" Focusable="False" VerticalAlignment="Center" Cursor="Hand" ?Visibility="{DynamicResource MaximizeButtonVisibility}" Click="Button_Click">
? ? ? ? ? ? ? ? ? ? <Button.Template>
? ? ? ? ? ? ? ? ? ? ? ? <ControlTemplate>
? ? ? ? ? ? ? ? ? ? ? ? ? ? <Grid x:Name="grd" Background="Transparent">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <Rectangle Width="20" Height="20" Stroke="#1e1e1e" ?StrokeThickness="3"></Rectangle>
? ? ? ? ? ? ? ? ? ? ? ? ? ? </Grid>
? ? ? ? ? ? ? ? ? ? ? ? ? ? <ControlTemplate.Triggers>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <Trigger Property="IsMouseOver" Value="True">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <Setter TargetName="grd" Property="Background" Value="#666666"></Setter>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? </Trigger>
? ? ? ? ? ? ? ? ? ? ? ? ? ? </ControlTemplate.Triggers>
? ? ? ? ? ? ? ? ? ? ? ? </ControlTemplate>
? ? ? ? ? ? ? ? ? ? </Button.Template>
? ? ? ? ? ? ? ? </Button>
? ? ? ? ? ? ? ? <!--關(guān)閉按鈕-->
? ? ? ? ? ? ? ? <Button Width="50" Height="50" ?Focusable="False" ?VerticalAlignment="Center" Cursor="Hand" Click="Button_Click_2">
? ? ? ? ? ? ? ? ? ? <Button.Template>
? ? ? ? ? ? ? ? ? ? ? ? <ControlTemplate>
? ? ? ? ? ? ? ? ? ? ? ? ? ? <Grid x:Name="grd" Background="Transparent">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <Line Width="20" Height="20" X1="0" Y1="0" X2="20" Y2="20" StrokeThickness="3" Stroke="#1e1e1e" ></Line>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <Line Width="20" Height="20" X1="20" Y1="0" X2="0" Y2="20" StrokeThickness="3" Stroke="#1e1e1e" ></Line>
? ? ? ? ? ? ? ? ? ? ? ? ? ? </Grid>
? ? ? ? ? ? ? ? ? ? ? ? ? ? <ControlTemplate.Triggers>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <Trigger Property="IsMouseOver" Value="True">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <Setter TargetName="grd" Property="Background" Value="#666666"></Setter>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? </Trigger>
? ? ? ? ? ? ? ? ? ? ? ? ? ? </ControlTemplate.Triggers>
? ? ? ? ? ? ? ? ? ? ? ? </ControlTemplate>
? ? ? ? ? ? ? ? ? ? </Button.Template>
? ? ? ? ? ? ? ? </Button>
? ? ? ? ? ? </StackPanel>
? ? ? ? </Grid>
? ? </Grid>
</Window>MainWindow.xaml.cs
using System.Windows;
namespace WpfApp8
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
WindowState = WindowState== WindowState.Maximized? WindowState .Normal: WindowState.Maximized;
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
WindowState = WindowState.Minimized;
}
private void Button_Click_2(object sender, RoutedEventArgs e)
{
Close();
}
}
}三、效果預(yù)覽

總結(jié)
以上就是今天要講的內(nèi)容,給窗口添加陰影的方法還是比較簡(jiǎn)單的,只是需要注意窗口最大化的情況。但實(shí)際上窗口陰影對(duì)性能影響還是比較大的,尤其是有渲染視頻的情況下,消耗更多的cpu。所以陰影只適合對(duì)性能要求不高的場(chǎng)景。
相關(guān)文章
C#實(shí)現(xiàn)對(duì)用戶(hù)輸入數(shù)據(jù)進(jìn)行校驗(yàn)的類(lèi)實(shí)例
這篇文章主要介紹了C#實(shí)現(xiàn)對(duì)用戶(hù)輸入數(shù)據(jù)進(jìn)行校驗(yàn)的類(lèi),實(shí)例分析了C#針對(duì)各種用戶(hù)輸入數(shù)據(jù)的常用校驗(yàn)技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-03-03
C#中Thread(線(xiàn)程)和Task(任務(wù))實(shí)例詳解
.NET Framework在System.Threading命名空間中具有與線(xiàn)程相關(guān)的類(lèi),線(xiàn)程是一小組可執(zhí)行指令,這篇文章主要給大家介紹了關(guān)于C#中Thread(線(xiàn)程)和Task(任務(wù))的相關(guān)資料,需要的朋友可以參考下2022-03-03
C#實(shí)現(xiàn)讀寫(xiě)ini配置文件的方法詳解
這篇文章主要為大家詳細(xì)介紹了如何利用C#實(shí)現(xiàn)讀寫(xiě)ini配置文件操作,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C#有一定的幫助,感興趣的小伙伴可以了解一下2022-12-12
詳解C#如何實(shí)現(xiàn)一個(gè)安全的事件訂閱器
事件訂閱器是一個(gè)對(duì)象,它訂閱(或監(jiān)聽(tīng))某個(gè)事件,并在事件發(fā)生時(shí)執(zhí)行相應(yīng)的操作,本文主要介紹了C#實(shí)現(xiàn)一個(gè)安全的事件訂閱器的相關(guān)知識(shí),感興趣的可以了解下2024-01-01
WPF利用CommunityToolkit.Mvvm實(shí)現(xiàn)級(jí)聯(lián)選擇器
這篇文章主要介紹了WPF如何利用CommunityToolkit.Mvvm實(shí)現(xiàn)級(jí)聯(lián)選擇器,文中的示例代碼講解詳細(xì),對(duì)我們的學(xué)習(xí)或工作有一定幫助,需要的小伙伴可以參考一下2023-12-12
C#實(shí)現(xiàn)操作windows系統(tǒng)服務(wù)(service)的方法
這篇文章主要介紹了C#實(shí)現(xiàn)操作windows系統(tǒng)服務(wù)(service)的方法,可實(shí)現(xiàn)系統(tǒng)服務(wù)的啟動(dòng)和停止功能,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-04-04

