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
0
投稿
猜你喜欢
- 首先,我们需要增加用户对该脚本的执行权限,即 String cmdstring = "chmod a+x test.sh
- 本文实例讲述了C#采用FileSystemWatcher实现监视磁盘文件变更的方法。分享给大家供大家参考。具体实现方法如下:简化需求:有一个
- 对数组使用 foreachC#提供 foreach 语句。 该语句提供一种简单、明了的方法来循环访问数组或任何可枚举集合的元素。 forea
- 前言在开发过程中,会遇到很多的实体需要将查出的数据处理为下拉或者级联下拉的结构,提供给前端进行展示。在数据库查出的结构中,可能是集合<
- 在 Servlet/Jsp 项目中,如果涉及到系统任务,例如在项目启动阶段要做一些数据初始化操作,这些操作有一个共同的特点,只在项目启动时进
- 本文实例讲述了Android编程自定义线程池与用法。分享给大家供大家参考,具体如下:一、概述:1、因为线程池是固定不变的,所以使用了单例模式
- 前言Java项目开发中经常要用到分页功能,现在普遍使用SpringBoot进行快速开发,而数据层主要整合SpringDataJPA和MyBa
- 详解Java中HashSet和TreeSet的区别1. HashSetHashSet有以下特点:不能保证元素的排列顺序,顺序有可能发生变化不
- 一、遇到一个问题1、读取CSV文件package com.guor.demo.charset;import java.io.Buffered
- 谷歌官方推出了一种侧滑菜单的实现方式(抽屉效果),即 DrawerLayout,这个类是在Support Library里的,需要加上and
- 先给出网页地址:https://wall.alphacoders.com/featured.php?lang=Chinese主要步骤:利用J
- mybatis 查询返回Map<String,Object> 类型,平时没太注意怎么用,今天又遇到了总结记录一下,方便以后处理此
- 这篇文章主要介绍了Java方法重载Overload原理及使用解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值
- 插入排序插入排序的代码实现虽然没有冒泡排序和选择排序那么简单粗暴,但它的原理应该是最容易理解的了,因为只要打过扑克牌的人都应该能够秒懂。插入
- 线程线程:对于所有需要等待的操作,例如移动文件,数据库和网络访问都需要一定的时间,此时就可以启动一个新的线程,同时完成其他任务。一个进程的多
- 通过继承Thread类并实现run方法创建一个线程// 定义一个Thread类,相当于一个线程的模板class MyThread01 ext
- 前言众所周知,encache是现在最流行的java开源缓存框架,配置简单,结构清晰,功能强大。通过注解 @Cacheable 可以快速添加方
- 背景#目前我主要负责的一个项目是一个 C/S 架构的客户端开发,前端主要是通过 WPF 相关技术来实现,后端是通过 Python 来实现,前
- AppWidgetProvider 用来在HOME页面显示插件实现步骤:1、为AppWidget提供一个元布局文件AppWigdetProv
- 函数四个方面:函数的定义函数的特点函数的应用函数的重载一、函数的定义及特点1) 什么是函数?函数就是定义在类中的具有特定功能的一段独立小程序