C# wpf 无边框窗口添加阴影效果的实现
作者:CodeOfCC 发布时间:2023-11-05 01:15:09
标签:C#,wpf,窗口,阴影
前言
制作无边框窗口时,系统自带阴影会消失,这时就需要我自己给窗口添加阴影以防止窗口融入背景。添加阴影的方法很简单,直接用effect就可以了,但这里还是有个不容易注意到的细节需要处理,加阴影后窗口最大化可能会有问题。
一、如何实现?
1、去除边框
(1)方法一
使用WindowStyle可以去除窗口边框,AllowsTransparency+Background制造透明窗口为阴影留出透明边距。
注:此方法较影响窗口渲染性能。
<Window WindowStyle="None" AllowsTransparency="True" Background="Transparent" >
(2)方法二
使用WindowChrome也可以实现无边框窗口,.net4.5之后可以使用此组件。WindowChrome通常不会影响渲染性能。
<Window WindowStyle="None" Background="Transparent" ResizeMode="NoResize">
<WindowChrome.WindowChrome>
<WindowChrome GlassFrameThickness="-1" CaptionHeight="0" />
</WindowChrome.WindowChrome
<Grid>
</Grid>
</Window>
2、添加阴影
使用DropShadowEffect 加Margin属性即可。添加阴影特效后,需要设置margin给阴影留出边距,否则是看不到阴影的。通常到这一步就结束了,如果窗口需要最大化则继续往下。
<Window >
<Grid Margin="10" Background="White">
<Grid.Effect>
<DropShadowEffect ShadowDepth="0" BlurRadius="10" Opacity="0.8" Color="#AAAAAA"/>
</Grid.Effect>
</Grid>
</Window>
3、添加触发器
1、 为何添加触发器?
根据上述2个步骤添加完阴影后,如果将窗口最大化就会发现,Margin依然生效,全屏窗口有一个透明外边距,为了解决这问题所以需要添加触发器。
2、 具体实现
在style中使用触发器,绑定窗口状态,当最大化时边距设为0,其他情况设为阴影需要的边距。在这里需要注意的是此时Grid不可以设置Margin属性了只能在触发器中设置,因为赋值优先级的原因,在Grid中设置Margin后触发器的赋值会失效。
<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>
<!--标题栏-->
<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>
<!--关闭按钮-->
<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();
}
}
}
三、效果预览
来源:https://blog.csdn.net/u013113678/article/details/126045002


猜你喜欢
- 本文实例讲述了C#使用foreach语句遍历队列(Queue)的方法。分享给大家供大家参考。具体如下:using System;using
- 循环结构可以实现一个程序模块的重复执行,它对于我们简化程序,更好地组织算法有着重要的意义。C#为我们提供了若干种循环语句,分别适用于不同的情
- 本文实例讲述了java实现的日期时间转换工具类。分享给大家供大家参考,具体如下:最基础的东西,总结一下,下次用的时候就方便一些了。废话不多说
- C#中如何给Excel添加水印我们知道Microsoft Excel并没有内置的功能直接给Excel表添加水印,但是其实我们可以用其他变通的
- JDK集合源码之HashMap解析1.树结构入门1.1 什么是树?树(tree)是一种抽象数据类型(ADT),用来模拟具有树状结构性质的数据
- 1.使用java.util.Properties类的load()方法示例:Java代码InputStream in = lnew Buffe
- Java里一个对象obj被创建时,被放在堆里。当GC运行的时候,发现没有任何引用指向obj,那么就会回收obj对象的堆内存空间。换句话说,一
- 1、什么是 IOC?IOC-Inversion of Control,即控制反转。它不是什么技术,而是一种设计思想。传统的创建对象的方法是直
- C#版本public static Component AddComponent(GameObject go, string assembl
- 一、数据类型与变量的介绍在程序运行的过程中计算机需要记录大量的状态 数据(这里我们统称数据)。那这些数据都存放在哪呢?程序在运行过程中的数据
- 本文实例讲述了C#数据结构之双向链表(DbLinkList)。分享给大家供大家参考,具体如下:这是继上一篇《C#数据结构之单链表(LinkL
- 简单介绍synchronized是Java中的关键字,是一种同步锁。它修饰的对象有以下几种:1. 修饰一个代码块,被修饰的代码块称为同步语句
- 一、前言今天实现一个时钟工具,其实在之前已经完成了一个简单的时钟工具:【Unity3D应用案例系列】时钟、钟表小组件开发。那么,今天的这个小
- 提到java里的注解,和我们平时的注释还是有很大的区别,主要是作为java特性来使用的,跟我们常见的类是同一个使用的层面。关于java注解的
- 先看一下效果图实现思路:变成点的控件不是TextView和EditText而是Imageview。首先写一个RelativeLayout里边
- 本文实例讲述了Java实现的日历功能。分享给大家供大家参考,具体如下:应用名称:Java日历用到的知识:Java GUI编程,日期操作开发环
- textField用于文本输入,它提供了很多属性:const TextField({ ... TextEditi
- 一般学过C#的都知道,Array 一旦定义好,比如四个长度,当需要再往里面添加元素的时候,需要Array.Resize一下才可以。有鉴于此,
- 本文给大家分享Android视频播放器屏幕左侧边随手指上下滑动亮度调节功能的原理实现,具体代码如下所示:import android.app
- 这篇文章主要从以下几个方面来介绍。简单介绍下jersey,springboot,重点介绍如何整合springboot与jersey。什么是j