流畅设计 Fluent Design System 中的光照效果 RevealBrush,WPF 也能模拟实现啦!

简介: 文:流畅设计 Fluent Design System 中的光照效果 RevealBrush,WPF 也能模拟实现啦! 版权声明:本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

文:流畅设计 Fluent Design System 中的光照效果 RevealBrush,WPF 也能模拟实现啦!

版权声明:本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名吕毅(包含链接:http://blog.csdn.net/wpwalter/),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系(walter.lv@qq.com)。 https://blog.csdn.net/WPwalter/article/details/79827611

UWP 才能使用的流畅设计效果好惊艳,写新的 UWP 程序可以做出更漂亮的 UI 啦!然而古老的 WPF 项目也想解解馋怎么办?

于是我动手实现了一个!


 

迫不及待看效果

 

 
▲ 是不是很像 UWP 中的 RevealBorderBrush

不止是效果像,连 XAML 写法也像:

<Border BorderThickness="1" Margin="50,34,526,348">
    <Border.BorderBrush>
        <demo:RevealBorderBrush />
    </Border.BorderBrush>
</Border>
<Border BorderThickness="1" Margin="50,76,526,306">
    <Border.BorderBrush>
        <demo:RevealBorderBrush Color="White" FallbackColor="Gray" />
    </Border.BorderBrush>
</Border>

▲ 模拟得很像的 RevealBorderBrush 的 XAML 写法

当然,窗口背景那张图是直接用的高斯模糊效果,并不是亚克力 Acrylic 效果。鉴于那张被模糊得看不清的图是我自己画的,所以我一定要单独放出来给大家看��!

我自己画的图,不忍直视,只好模糊掉作为背景了
▲ 我自己画的图,不忍直视,只好模糊掉作为背景了

话不多说看源码

UWP 里的 CompositionBrush 是用一个 ShaderEffect 做出所有控件的所有效果的。正如 叛逆者如何评价微软在 Build 2017 上提出的 Fluent Design System? - 知乎 一文中说的,只需要极少的计算量就能完成。

不过 Win32 窗口并没有得到眷恋,所以我只好自己实现。但限于只能使用 WPF 内建机制,故性能上当然不能比了。但在小型项目的局部用用还是非常不错的——尤其是个人项目!不过话说现在个人项目谁还用 WPF 呢 (逃

思路是画一个径向渐变,即 RadialGradientBrush,然后当鼠标在窗口内移动时,改变径向渐变的渐变中心为鼠标所在点。

以下是全部源码。不要在意基类啦!WPF 不让我们实现自己的 Brush,所以只好用 MarkupExtension 绕道实现了。

using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;

namespace Walterlv.Demo
{
    /// <summary>
    /// Paints a control border with a reveal effect using composition brush and light effects.
    /// </summary>
    public class RevealBorderBrushExtension : MarkupExtension
    {
        /// <summary>
        /// The color to use for rendering in case the <see cref="MarkupExtension"/> can't work correctly.
        /// </summary>
        public Color FallbackColor { get; set; } = Colors.White;

        /// <summary>
        /// Gets or sets a value that specifies the base background color for the brush.
        /// </summary>
        public Color Color { get; set; } = Colors.White;

        public Transform Transform { get; set; } = Transform.Identity;

        public Transform RelativeTransform { get; set; } = Transform.Identity;

        public double Opacity { get; set; } = 1.0;

        public double Radius { get; set; } = 100.0;

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            // 如果没有服务,则直接返回。
            if (!(serviceProvider.GetService(typeof(IProvideValueTarget)) is IProvideValueTarget service)) return null;
            // MarkupExtension 在样式模板中,返回 this 以延迟提供值。
            if (service.TargetObject.ToString().EndsWith("SharedDp")) return this;
            if (!(service.TargetObject is FrameworkElement element)) return this;
            if (DesignerProperties.GetIsInDesignMode(element)) return new SolidColorBrush(FallbackColor);

            var window = Window.GetWindow(element);
            if (window == null) return this;
            var brush = CreateBrush(window, element);
            return brush;
        }

        private Brush CreateBrush(Window window, FrameworkElement element)
        {
            var brush = new RadialGradientBrush(Colors.White, Colors.Transparent)
            {
                MappingMode = BrushMappingMode.Absolute,
                RadiusX = Radius,
                RadiusY = Radius,
                Opacity = Opacity,
                Transform = Transform,
                RelativeTransform = RelativeTransform,
            };
            window.MouseMove += OnMouseMove;
            window.Closed += OnClosed;
            return brush;

            void OnMouseMove(object sender, MouseEventArgs e)
            {
                var position = e.GetPosition(element);
                brush.GradientOrigin = position;
                brush.Center = position;
            }

            void OnClosed(object o, EventArgs eventArgs)
            {
                window.MouseMove -= OnMouseMove;
                window.Closed -= OnClosed;
            }
        }
    }
}

参考资料

目录
相关文章
|
7天前
|
C# 开发者 Windows
基于Material Design风格开源、易用、强大的WPF UI控件库
基于Material Design风格开源、易用、强大的WPF UI控件库
|
C# 前端开发
WPF - 图形设计器(Diagram Designer)
原文:WPF - 图形设计器(Diagram Designer)   OpenExpressApp计划中包括建模工具,计划是采用MetaEdit+模型来作为元模型,使用codeproject的《WPF Diagram Designer》一系列文章来做为设计器实现参考,本篇介绍一下codeprojcet的这四个文章,推荐给对图形设计器感兴趣的人去看看,通过WPF的模板功能和其他功能可以很方便的设计出图形编辑器。
3342 0
|
C#
WPF 界面实现多语言支持 中英文切换 动态加载资源字典
原文:WPF 界面实现多语言支持 中英文切换 动态加载资源字典 1、使用资源字典,首先新建两个字典文件en-us.xaml、zh-cn.xaml。定义中英文的字符串在这里面【注意:添加xmlns:s="clr-namespace:System;assembly=mscorlib】 zh-cn.
2855 0
|
C# 数据可视化 开发工具
WPF实现选项卡效果(1)——使用AvalonDock
原文:WPF实现选项卡效果(1)——使用AvalonDock 简介   公司最近一个项目,软件采用WPF开发,需要实现类似于VS的选项卡(或者是浏览器的选项卡)效果。
2106 0
|
IDE C# 开发工具
WPF钟表效果实现
中WPF中的RotateTransform实现UI元素的旋转,并模拟钟表的秒针、分针和时针。
1121 0
WPF钟表效果实现
|
IDE 编译器 C#
WPF实现强大的动态公式计算
数据库可以定义表不同列之间的计算公式,进行自动公式计算,但如何实现行上的动态公式计算呢?行由于可以动态扩展,在某些应用场景下将能很好的解决实际问题。本文就探讨一下如何在WPF中实现一种基于行字段的动态公式计算。
989 0
WPF实现强大的动态公式计算
|
网络协议 C# 移动开发
C# WPF上位机实现和下位机TCP通讯
C# WPF上位机实现和下位机TCP通讯下位机使用北京大华程控电源DH1766-1,上位机使用WPF。实现了电压电流实时采集,曲线显示。上午在公司调试成功,手头没有程控电源,使用TCP服务端模拟。昨天写的TCP服务端正好排上用场。
2332 0
|
C#
WPF特效-实现3D足球效果
原文:WPF特效-实现3D足球效果 WPF 实现 3D足球效果,效果图如下:  每个面加载不同贴图。                                                          ...
856 0
|
算法 C# 容器
WPF特效-实现弧形旋转轮播图
原文:WPF特效-实现弧形旋转轮播图        项目遇到,琢磨并实现了循环算法,主要处理循环替换显示问题       (如:12张图组成一个圆弧,但总共有120张图需要呈现,如何在滑动中进行显示块的替换,并毫无卡顿)        处理的自己感觉比较满意,记录一下。
2039 0
|
C#
wpf采用Xps实现文档显示、套打功能
原文:wpf采用Xps实现文档显示、套打功能 近期的一个项目需对数据进行套打,用户要求现场不允许安装office、页面预览显示必须要与文档完全一致,xps文档来对数据进行处理。Wpf的DocumentView 控件可以直接将数据进行显示,xps也是一种开放式的文档,如果我们能够替换里面的标签就最终实现了我们想要的效果。
1730 0