【WPF学习】第四十六章 效果

  WPF提供了可应用于任何元素的可视化效果。效果的目标是提供一种简单的声明式方法,从而改进文本、图像、按钮以及其他控件的外观。不是编写自己的绘图代码,而是使用某个继承自Effect的类(位于System.Windows.Media.Effects名称空间中)以立即获得诸如模糊、辉光以及阴影等效果。

  下表列出了可供使用的的效果类:

表 效果类

  勿将上表列出的Effect类的派生类和位图效果类相混淆,位图效果派生类自BitmapEffect类,该类和Effect类位于相同的名称空间中。尽管位图效果具有类似的编程模型,但他们存在价格严重的局限性:

  •   位图效果不支持像素着色器,像素着色器是创建可重用效果的最强大、最灵活的方式。
  •   位图效果是用非托管的代码实现的,从而需要完全信任的应用程序。所以,在基于浏览器的XBAP应用程序中不能使用位图效果。
  •   位图效果总使用软件进行渲染,不使用显卡资源。这使得它们的速度较慢,当处理大量元素或具有较大可视化表面的元素时尤其如此。

  BitmapEffect类是在WPF的第一个版本中引入的,该版本没有提供Effect类。为了向后兼容,仍保留了位图效果。

  接下里的几节深入分析效果模型,并演示上三个继承自Effect的类:BlurEffect、DropShadowEffect以及ShaderEffect。

一、BlurEffect类

  最简单的WPF效果是BlurEffect类。该类模糊元素的内容,就想通过失焦透镜观察到得效果。通过增加Radiu属性的值(默认值是5)可增加模糊程度。

  为使用任何效果,需要创建适当的效果对象并设置相应元素的Effect属性:

<Button Content="BlurEffect(Radius=2)" Margin="5" Padding="3">
            <Button.Effect>
                <BlurEffect Radius="2"></BlurEffect>
            </Button.Effect>
        </Button>

        <Button Content="Blurred (Radius=5)" Padding="5" Margin="3">
            <Button.Effect>
                <BlurEffect Radius="5"></BlurEffect>
            </Button.Effect>
        </Button>

        <Button Content="Blurred (Radius=20)" Padding="5" Margin="3">
            <Button.Effect>
                <BlurEffect Radius="20"></BlurEffect>
            </Button.Effect>
        </Button>

  下图显示了应用到一组按钮的三个不同程度的模糊效果(Radiu属性值分别为2、5和20)。

二、DropShadowEffect类

  DropShadowEffect类在元素背后添加了轻微的偏移阴影。可使用该类的几个属性,如下表所示:

表 DropShadowEffect类的属性

  下面是实现这些阴影效果的标记:

<TextBlock FontSize="20" Margin="5">
            <TextBlock.Effect>
                <DropShadowEffect></DropShadowEffect>
            </TextBlock.Effect>
            <TextBlock.Text>Basic DropShawEffect</TextBlock.Text>
        </TextBlock>

        <TextBlock FontSize="20" Margin="5">
            <TextBlock.Effect>
                <DropShadowEffect Color="Blue"></DropShadowEffect>
            </TextBlock.Effect>
            <TextBlock.Text>Blue Color DropShawEffect</TextBlock.Text>
        </TextBlock>

        <TextBlock FontSize="20" Foreground="White" Margin="5">
            <TextBlock.Effect>
                <DropShadowEffect  BlurRadius="15"></DropShadowEffect>
            </TextBlock.Effect>
            <TextBlock.Text>Blurred Dropshadow with White text</TextBlock.Text>
        </TextBlock>

        <TextBlock FontSize="20" Foreground="Magenta" Margin="5">
            <TextBlock.Effect>
                <DropShadowEffect   ShadowDepth="0"></DropShadowEffect>
            </TextBlock.Effect>
            <TextBlock.Text>Close dropshadow</TextBlock.Text>
        </TextBlock>

        <TextBlock FontSize="20" Foreground="Magenta" Margin="5">
            <TextBlock.Effect>
                <DropShadowEffect   ShadowDepth="25"></DropShadowEffect>
            </TextBlock.Effect>
            <TextBlock.Text>Distant dropshadow</TextBlock.Text>
        </TextBlock>

  效果图如下所示:

  没有提供用来组合效果的类,这意味着一次只能为一个元素应用一个效果。然而,有时可通过将元素添加到高层的容器中模拟多个效果(例如,为TextBlock元素使用阴影效果,然后将其放入使用模糊效果的StackPanel面板中)。大多数情况下,应避免这种变通方法,因为这种方法会成倍地增加渲染工作量并会降低性能。相反,应当查找能够完成所有内容的单个效果。

三、ShaderEffect类

  ShaderEffect类没有提供就绪的效果。相反,它是一个抽象类,可继承该类以创建自己的自定义像素着色器。通过使用ShaderEffect类(或从该类派生的自定义效果),可实现更多的效果,而不仅局限于模糊和阴影。

  可能与你所期望的相反,实现像素着色器的逻辑不是直接在效果类中使用C#代码编写的。相反,像素着色器使用高级着色语言(High Level Shader Lanaguage,HLSL)编写的,该语言是Mircrosoft DirectX的一部分(使用这种语言的优点是很明显的——因为DirectX和HLSL已经存在许多年了,图形开发人员已经创建了许多可在代码中使用的像素着色器例程)。

  为创建像素着色器,需要编写和编译HLSL代码。要执行编译,可使用WIndows SDK for Windows 8中的fxc.exe命令工具;注意,Windows SDK for Windows 8也支持Windows 7,这从名称中看不出来的。但更简便的选项是使用免费的Shazzam工具。Shazzam提供了用于HLSL文件的编辑器,可使用该工具在示例图像上尝试效果。该工具还提供了几个像素着色器示例,可将它们作为自定义效果的基础。

  尽管制作自己的HLSL文件超出本章范围,但下面将使用一个已有的HLSL文件。一旦将HLSL文件编译成.ps文件,就可以在项目中使用它了。只需要将文件添加到已有的WPF项目中,在Solution Explorer中选择该文件,并将它的Build Action属性设置为Resource。最后必须创建一个继承自ShaderEffect的自定义类并使用该资源。

  例如,如果正在使用自定义像素着色器(已经编译到名为Effect.ps的文件中),可使用以下代码:

public class CustomEffect:ShaderEffect
    {
        public CustomEffect()
        {
            Uri uri = new Uri("Effect.ps", UriKind.Relative);

            PixelShader = new PixelShader();
            PixelShader.UriSource = uri;
        }
    }

  现在可以在任意窗口中使用这个自定义的像素着色器了。首先,通过如下所示的映射使名称空间可用:

xmlns:local="clr-namespace:Drawing"

  现在创建自定义效果类的一个实例,并用它设置元素的Effect属性:

<Image Name="img" Margin="5" Source="harpsichord.jpg">
            <Image.Effect>
                <local:CustomEffect></local:CustomEffect>
            </Image.Effect>
        </Image>

  该示例完整代码如下所示:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Effects;

namespace Drawing
{
    public class CustomEffect:ShaderEffect
    {
        public CustomEffect()
        {
            Uri uri = new Uri("Effect.ps", UriKind.Relative);

            PixelShader = new PixelShader();
            PixelShader.UriSource = uri;
            UpdateShaderValue(InputProperty);
        }

        public static readonly DependencyProperty InputProperty =
            ShaderEffect.RegisterPixelShaderSamplerProperty("Input", typeof(CustomEffect), 0 /* assigned to sampler register S0 */);

        public Brush Input
        {
            get { return (Brush)GetValue(InputProperty); }
            set { SetValue(InputProperty, value); }
        }
    }
}

CustomEffect

<Window x:Class="Drawing.CustomPixelShader"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:Drawing"
        Title="CustomPixelShader" Height="600" Width="305.639">
    <StackPanel>
        <Image Name="img" Margin="5" Source="harpsichord.jpg">
            <Image.Effect>
                <local:CustomEffect></local:CustomEffect>
            </Image.Effect>
        </Image>
        <CheckBox Name="chkEffect" Margin="5" Content="Effect enabled" IsChecked="True" Click="chkEffect_Click"></CheckBox>

    </StackPanel>
</Window>

CustomPixelShader

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace Drawing
{
    /// <summary>
    /// CustomPixelShader.xaml 的交互逻辑
    /// </summary>
    public partial class CustomPixelShader : Window
    {
        public CustomPixelShader()
        {
            InitializeComponent();
        }

        private void chkEffect_Click(object sender, RoutedEventArgs e)
        {
            if (chkEffect.IsChecked != true)
                img.Effect = null;
            else
                img.Effect = new CustomEffect();
        }
    }
}

CustomPixelShader.xaml.cs

  最终效果图如下所示:

                   

  如果使用采用特定输入参数的像素着色器,需要做的工作笔上面的示例要更复杂一点。对与这种情况,需要通过调用RegisterPixelShaderSamplerProperty()静态方法创建相应的依赖性属性。

  灵活的像素着色器就像在诸如Adobe Photoshop这样的图像软件中使用的插件一样强大。它可以执行任何工作,从添加基本的阴影乃至更富有挑战性的效果。如模糊、辉光、水波、浮雕和锐化等。当集合使用动画实时改变着色器的参数时,像素着色器还可以创建赏心悦目的效果。

原文地址:https://www.cnblogs.com/Peter-Luo/p/12343010.html

时间: 2024-08-11 01:24:37

【WPF学习】第四十六章 效果的相关文章

【WPF学习】第二十六章 Application类——应用程序的生命周期

原文:[WPF学习]第二十六章 Application类--应用程序的生命周期 在WPF中,应用程序会经历简单的生命周期.在应用程序启动后,将立即创建应用程序对象,在应用程序运行时触发各种应用程序事件,你可以选择监视其中的某些事件.最后,当释放应用程序对象时,应用程序将结束. 一.创建Application对象 使用Application类的最简单方式是手动创建它.下面的示例演示了最小的程序:在应用程序入口(Main()方法)处创建名为MainWindow的窗口,并启动一个新的应用程序: 在本质

【WPF学习】第十六章 键盘输入

当用户按下键盘上的一个键时,就会发生一系列事件.下表根据他们的发生顺序列出了这些事件: 表 所有元素的键盘事件(按顺序) 键盘处理永远不会像上面看到的这么简单.一些控件可能会挂起这些事件中的某些事件,从而可执行自己更特殊的键盘处理.最明显的例子是TextBox控件,它挂起了TextInput事件.对于一些按键,TextBox控件还挂起了KeyDown事件,如方向键.对于此类情形,通常仍可使用隧道路由事件(PreviewTextInput和PreviewKeyDown事件). TextBox控件还

【WPF学习】第二十九章 元素绑定——将元素绑定到一起

原文:[WPF学习]第二十九章 元素绑定--将元素绑定到一起 数据banding的最简单情形是,源对象时WPF元素而且源属性是依赖性属性.前面章节解释过,依赖项属性具有内置的更改通知支持.因此,当在源对象中改变依赖项属性的值时,会立即更新目标对象中的绑定属性.这正是我们所需要的行为--而且不必为此构建任何额外的基础结构. 为理解如何将一个元素绑定到另一个元素,下面创建一个简单的示例.该示例窗口包含了两个控件:一个Slider控件和一个具有单行文本的TextBlock控件.如果向右拖动滑动条上的滑

“全栈2019”Java多线程第四十六章:判断任意线程是否已持有写锁

难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多线程第四十六章:判断任意线程是否已持有写锁 下一章 "全栈2019"Java多线程第四十七章:判断锁是否为公平锁isFair() 学习小组 加入同步学习小组,共同交流与进步. 方式一:加入编程圈子. 方式二:关注头条号Gorhaf,私信"Java学习小组". 方式三:关

第四十六章

第四十六章1 马应该种田,不应该打仗:你应该工作,不应该总想买买买 天下有道,却走马以粪.天下无道,戎马生于郊. 天下有道的时候,马都在田里耕地,天下无道的时候,马都在战场打仗. 要放低欲望,把资源用在正地方. 各位朋友大家好,清晨起来,我们接着来讲<道德经>,看看老子老先生带给我们什么样人生启发.我在今天起床之前做梦,梦是让人黯然神伤的,我做梦梦见自己给一帮孩子妈妈,带着小朋友讲课,就讲这个“道”,结果妈妈不听,在下面聊天,孩子哭闹,乱作一团,大家说讲点感冒吧,讲“道”有什么用,我说“道”很

【Unity 3D】学习笔记四十六:输入与控制——键盘事件

在游戏中,玩家控制主角移动,按键攻击,选择行走.都需要在程序中监听玩家的输入.unity为开发者提供了input库,来支持键盘事件,鼠标事件以及触摸事件.本文主要回顾键盘事件,以后会逐文复习鼠标以及触摸事件. 键盘事件 一般的PC键盘有104个不同的按键,在程序中通过监听这些按键事件,从而进一步执行逻辑操作.如:射击游戏中,W表示前进,S表示后退,A表示左移,D表示右移. 按下事件 在脚本中,用input.GetKeyDown( )方法将按键值作为参数,监听此按键是否被按下.按下返回true,否

【WPF学习】第十九章 控件类

原文:[WPF学习]第十九章 控件类 WPF窗口充满了各种元素,但这些元素中只有一部分是控件.在WPF领域,控件通常被描述为与用户交互的元素--能接收焦点并接受键盘或鼠标输入的元素.明显的例子包括文本框和按钮.然而,这个区别有时有些模糊.将工具提示视为控件,因为它根据用户鼠标的移动显示或消失.将标签视为控件,因为它支持记忆码(mnemonics,将焦点转移到相关控件快捷键). 所有控件都继承自System.Windows.Control类,该类添加了一小部分基本的基础结构: 设置控件内容对齐方式

【WPF学习】第十五章 WPF事件

前两章学习了WPF事件的工作原理,现在分析一下在代码中可以处理的各类事件.尽管每个元素都提供了许多事件,但最重要的事件通常包括以下5类: 生命周期事件:在元素被初始化.加载或卸载时发生这些事件. 鼠标事件:这些事件是鼠标动作的结果. 键盘事件:这些事件是键盘动作(如按下键盘上的键)的结果. 手写笔事件:这些事件是使用类似钢笔的手写笔的结果.在平板电脑上用手写笔代替鼠标. 多点触控事件:这些事件是一根或多根手指在多点触控屏上触摸的结果.尽在Windows7中支持这些事件. 一.生命周期事件 当首次

javaweb学习总结(四十六)——Filter(过滤器)常见应用

一.统一全站字符编码 通过配置参数charset指明使用何种字符编码,以处理Html Form请求参数的中文问题 1 package me.gacl.web.filter; 2 3 import java.io.IOException; 4 import javax.servlet.Filter; 5 import javax.servlet.FilterChain; 6 import javax.servlet.FilterConfig; 7 import javax.servlet.Serv