WPF窗口阴影和夜间模式的实现

窗口阴影

实现

因项目需要给用户一定提示,设计师建议在鼠标进入时显示窗口阴影,离开时取消窗口阴影。

很自然,都会想到直接在窗口的内容或者自定义窗口的最外层元素上加效果。示例如下:

<Grid>
    <Grid.Effect>
        <DropShadowEffect x:Name="ShadowEffect"
                                                  BlurRadius="15"
                                                  Direction="270"
                                                  Opacity="0"
                                                  ShadowDepth="15"
                                                  Color="Yellow" />
    </Grid.Effect>
</Grid>

很不幸,上述方法不会生效,原因何在?窗口的非工作区(也就是Grid的四周)的渲染是由系统控制。虽然不清楚是绘出来了被遮住了还是根本没绘出来,但是告诉了我们此路不通。

还好我们用的是WPF,可以自己定义模板和样式。于是简单测试了一下就发现了方案。下面就是我使用的样式一个示例(省略了模拟的控制按钮和其他的一些功能)

<Style x:Key="ShadowWindow" TargetType="Window">
    <Setter Property="OverridesDefaultStyle" Value="True" />
    <Setter Property="AllowsTransparency" Value="True" />
    <Setter Property="WindowStyle" Value="None" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Window">
                <Border Padding="15">
                    <Border Name="BdrShadow">
                        <ContentPresenter ContentSource="Content" />
                        <Border.Effect>
                            <DropShadowEffect x:Name="ShadowEffect"
                                              BlurRadius="15"
                                              Direction="270"
                                              Opacity="0"
                                              ShadowDepth="15"
                                              Color="Yellow" />
                        </Border.Effect>
                    </Border>
                </Border>
                <ControlTemplate.Triggers>
                    <EventTrigger RoutedEvent="MouseEnter">
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation Duration="0:0:1"
                                                 Storyboard.TargetName="ShadowEffect"
                                                 Storyboard.TargetProperty="Opacity"
                                                 To="0.5" />
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger>
                    <EventTrigger RoutedEvent="MouseLeave">
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation Duration="0:0:1"
                                                 Storyboard.TargetName="ShadowEffect"
                                                 Storyboard.TargetProperty="Opacity" />
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

需要注意的是必须将OverridesDefaultStyle和AllowsTransparency设为true。根据需要设置相应的属性,比如外层Border的Padding要与阴影的属性保持一致。

不足

  1. 有时鼠标进入和离开时阴影显隐失灵
  2. 效率低下,特别是经常需要更新界面时(所以最后我们放弃这个方案了)
  3. 上述样式存在一个Bug,即在用到界面验证时,会发生验证无法显示的情况。因为验证常用的AdornedElementPlaceholder中包含一个Adorner,在系统默认的Window样式中包含AdornerLayer,所以显示正常。为此我们需要在样式中手动添加一个AdornerLayer。

夜间模式

因项目需要设计了一个夜间模式,而项目的地图是由位图拼接而成的,无法直接修改。所以我在上面放置了一个Border作为遮罩,原理示意如下:

<DockPanel>
    <Slider DockPanel.Dock="Top"
            LargeChange="0.2"
            Maximum="1"
            Minimum="0"
            Orientation="Horizontal"
            TickFrequency="0.1"
            Value="{Binding ElementName=BdrShade,
                            Path=Opacity}" />
    <Grid>
        <Image Source="Lighthouse.jpg" />
        <Border Name="BdrShade"
                Background="Black"
                IsHitTestVisible="False"
                Opacity="0.5" />
    </Grid>
</DockPanel>

原理很简单,就是将要设置夜间模式的控件上层放置一个背景为黑色的Border,通过调整其透明度实现。值得注意的是,必须将Border的IsHitTestVisible设为False(即不参与命中测试), 否则控件不能点击。

查看控件模板或样式

在使用WPF的过程中,我们经常会对控件的外观进行修改,这个时候查看原有的样式或者模板进行参考就很有必要了。这样一能够减少许多工作,只修改需要的部分,二能够避免修改模板或样式后失去某些功能。下面就是我常用的两个方法

查看当前控件使用的模板

可通过手动创建控件,然后使用XamlWriter类将模板保存的方式来查看控件的当前模板。对此感兴趣的可查看《WPF编程宝典——C#2010版》(《Pro WPF in C# 2010》)17.2.2  剖析控件相关部分。

上述方法经过简单修改之后也可用来查看样式或者第三方控件的模板,比如我就利用该方法查看过DevExpress中图表控件的模板。

上述方法的缺点是使用XamlWriter类保存后的XAML代码有些冗余且不直观,因为其总是会使用属性元素语法而不是特性语法。

查看主题使用的模板

WPF中为自带的控件准备了4套主题,分别是Aero、Classic、Luna、Royale。分别对应PresentationFramework.Aero.dll、PresentationFramework.Classic.dll、PresentationFramework.Luna.dll、PresentationFramework.Royale.dll这4个DLL,在需要时,可通过C#反编译工具(如ILSpy、dotPeek)查看其中的BAML资源。如下图:

时间: 2024-10-12 21:12:01

WPF窗口阴影和夜间模式的实现的相关文章

WPF窗口阴影

起因 在以前项目中,需要给用户一定提示.设计师建议在鼠标进入时显示窗口阴影,离开时取消窗口阴影. 尝试1 很自然,都会想到直接在窗口的内容或者自定义窗口的最外层元素上加效果.示例如下: <Grid> <Grid.Effect> <DropShadowEffect x:Name="ShadowEffect" BlurRadius="15" Direction="270" Opacity="0" Sh

ReactJS React+Redux+Router+antDesign通用高效率开发模板,夜间模式为例

工作比较忙,一直没有时间总结下最近学习的一些东西,为了方便前端开发,我使用React+Redux+Router+antDesign总结了一个通用的模板,这个技术栈在前端开发者中是非常常见的. 总的来说,我这个工程十分便捷,对于初学者来说,可能包含到以下的一些知识点: 一.React-Router的使用 Router是为了方便管理组件的路径,它使用比较简单,一般定义如下就行,需要注意的是,react-router的版本有1.0-3.0,各个版本对应的API大致相似,但也有不同,我使用的是2.X的,

夜间模式的实现

前天在做项目的时候, 遇到一个问题(夜间模式的实现),通常我们在设置夜间模式的时候,简单的做法是使用通知的设计模式,改变各个页面的背景色,然后设置一下透明的效果,可是一个真正的项目,并不能马虎,需要页面效果美观精致.本文参考了github上一个老外写的实现方案,方案参考 经过自己的理解整合,制作出了自己的页面模式的实现. Xcode中floder 与 group 的区别 在这里我先要说明一下:在Xcode中蓝色和黄色文件夹的区别,因为本文就是使用到了蓝色的文件夹,通常蓝色文件夹在IOS中被称为f

DKNightVersion的基本使用(夜间模式)

DKNightVersion下载地址: https://github.com/Draveness/DKNightVersion 基本原理就是利用一个单例对象来存储颜色, 然后通过runtime中的objc_setAssociatedObject和objc_getAssociatedObject来完成两个对象间传递要保存的颜色(纯属个人看法) 下面是gif效果图: 下面是代码部分: import UIKit class ViewController: UIViewController { @IBO

Android 夜间模式的实现

package com.loaderman.daynightdemo; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatDelegate; import android.support.v7.widget.Toolbar; import android.view.View; public class MainActiv

iOS - 夜间模式KTJNightVersion

KTJNightVersion:快速部署夜间模式. 当使用DKNightVersion进行部署夜间模式时候发现了一些问题,由于项目比较急,于是按照DKNightVersion的思路重新进行了实现,并加强了部分功能.先已完成测试,由于开发与测试较急,所以存在一些隐蔽的BUG也是在所难免,烦请各位指正.(github.博客园) KTJNightVersion整体设计: 1.模式切换使用通知方式进行广播,监听该广播的为每一个ViewController,该ViewController分别在 viewW

Android应用开发中的夜间模式实现(一)

前言 在应用开发中会经常遇到要求实现夜间模式或者主题切换具体例子如下,我会先讲解第一种方法. 夜间模式 知乎 网易新闻 沪江开心词场 Pocket 主题切换 腾讯QQ 新浪微博 我今天主要是详述第一种的实现方式: 首先,应用的Application要继承自定义的Theme 1 2 3 4 5 6 <application android:allowBackup="true" android:icon="@drawable/ic_launcher" androi

在 WPF 程序中使用 MVVM 模式

MVVM 模式是一个很久之前的技术了,最近因为一个项目的原因,需要使用 WPF 技术,所以,重新翻出来从前的一段程序,重温一下当年的技术. MVVM 模式 MVVM 实际上涉及三个部分,Model, View 和 ViewModel ,三者的关系如下图所示. 在三部分的关系中,视图显示的内容和操作完全依赖于 ViewModel. Model 是应用程序的核心,代表着最大.最重要的业务资产,因为它记录了所有复杂的业务实体.它们之间的关系以及它们的功能. Model 之上是 ViewModel.Vi

【android】夜间模式简单实现

关于阅读类的app,有个夜间模式真是太重要了. 那么有两种方式可以实现夜间模式 1:修改theme,重启activity 优点:正儿八经的夜间模式,配色看着舒服 缺点:图片刺眼.闪屏 2:使用一个带黑色带透明度的View,盖在现有的activity上,效果类似你带上墨镜,看着太阳不刺眼. 优点:不用重启activity,不闪屏:加上透明度过渡动画,模式之间切换非常舒服,解决了1中,白底图片依旧刺眼的问题.: 缺点:配色没变化,就算带上墨镜,白天依旧是白天. 因此,本方案整合了两种解决方案.在夜间