原文:[原译]一步步教你制作WPF圆形玻璃按钮

图1

1.介绍

从我开始使用vista的时候,我就非常喜欢它的圆形玻璃按钮。WPF最好的一个方面就是允许自定义任何控件的样式。用了一段时间的Microsoft Expression Blend后。我做出了这个样式。我觉得做的还行。因为。我决定分享。如我所说。我使用Microsoft Expression Blend来做。但是。我也是用XAML编辑器--Kaxaml

2.概述

玻璃按钮样式包含了三层。组织了玻璃效果(Glass Effect)和一个ContentPresenter  来存储按钮的内容。所有的这些层都在一个最外层的Grid里。当鼠标放到按钮上,按下去的时候也定义了一些触发器(Triggers),来增加一些交互。

我把这个样式做成了资源文件。但是这个Key可以删除,来使得所有的按钮都是这个效果。

好我们来看一下这些层次。这些被广泛应用在微软产品中的按钮。

3.按钮层次

3.1背景层

第一层是一个椭圆。其实是一个canvas,一会在上面画反射和折射层,填充的颜色和按钮的背景(Background)关联。

下面是Blend中的截图

图2

<!-- Background Layer -->

<Ellipse Fill="{TemplateBinding Background}"/>

3.1.1折射层

第二层模拟了光从上到下的折射。被放在反射层之前是因为,要达到反光玻璃的效果,反射层必须在按钮的中间某处有一个硬边缘。这一层实际上是另一个椭圆。但是这次。我们使用一个径向渐变(白色-透明)的填充。来模拟光的折射。渐变开始于第一层底部的中央。结束于上面的中间。然而。为了降低折射光的强度。渐变还是开始于椭圆的底部再下一点为好。可以从图上和代码里清晰的看到。

<!-- Refraction Layer -->
<Ellipse x:Name="RefractionLayer">
<Ellipse.Fill>
<RadialGradientBrush GradientOrigin="0.496,1.052">
<RadialGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform CenterX="0.5"
CenterY="0.5" ScaleX="1.5" ScaleY="1.5"/>
<TranslateTransform X="0.02" Y="0.3"/>
</TransformGroup>
</RadialGradientBrush.RelativeTransform>
<GradientStop Offset="" Color="#00000000"/>
<GradientStop Offset="0.4" Color="#FFFFFFFF"/>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>

3.1.2反射层

第三层是光的反射层。是最难的部分。问题是反射效果不能使用任何标准的形状来画。因此。使用路径(Path)来画反射区域。当时。手工画也是可以的。但老实说。手工画图实在没什么可享受的(除非你是一个艺术家,或者有一个数位板),无论如何。我现在MS Blend中华好一个椭圆并转换成一个路径,然后我使用贝塞尔曲线点调整得到平滑的路径,你可以添加渐变到一个复杂的Path对象上。就像你对其他与定义的图形,比如椭圆,矩形所做的一样。为了得到光泽反射。我额每年需要一个透明-白色的径向渐变填充,从路径的底部开始(也就是按钮的中间某处),结束在顶部。我想如果我是一个艺术家。我会让渐变更准一点。可是我不是。因此。就这样。因为我们要把我们的按钮放在一个Grid里。所有我们设置VerticalAlignment="Top" 这样反射区域在按钮的中间的结束了。

图三

<!-- Reflection Layer -->
<Path x:Name="ReflectionLayer" VerticalAlignment="Top" Stretch="Fill">
<Path.RenderTransform>
<ScaleTransform ScaleY="0.5" />
</Path.RenderTransform>
<Path.Data>
<PathGeometry>
<PathFigure IsClosed="True" StartPoint="98.999,45.499">
<BezierSegment Point1="98.999,54.170" Point2="89.046,52.258"
Point3="85.502,51.029"/>
<BezierSegment IsSmoothJoin="True" Point1="75.860,47.685"
Point2="69.111,45.196" Point3="50.167,45.196"/>
<BezierSegment Point1="30.805,45.196" Point2="20.173,47.741"
Point3="10.665,51.363"/>
<BezierSegment IsSmoothJoin="True" Point1="7.469,52.580"
Point2="1.000,53.252" Point3="1.000,44.999"/>
<BezierSegment Point1="1.000,39.510" Point2="0.884,39.227"
Point3="2.519,34.286"/>
<BezierSegment IsSmoothJoin="True" Point1="9.106,14.370"
Point2="27.875,0" Point3="50,0"/>
<BezierSegment Point1="72.198,0" Point2="91.018,14.466"
Point3="97.546,34.485"/>
<BezierSegment IsSmoothJoin="True" Point1="99.139,39.369"
Point2="98.999,40.084" Point3="98.999,45.499"/>
</PathFigure>
</PathGeometry>
</Path.Data>
<Path.Fill>
<RadialGradientBrush GradientOrigin="0.498,0.526">
<RadialGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform CenterX="0.5"
CenterY="0.5" ScaleX="" ScaleY="1.997"/>
<TranslateTransform X="" Y="0.5"/>
</TransformGroup>
</RadialGradientBrush.RelativeTransform>
<GradientStop Offset="" Color="#FFFFFFFF"/>
<GradientStop Offset="0.85" Color="#92FFFFFF"/>
<GradientStop Offset="" Color="#00000000"/>
</RadialGradientBrush>
</Path.Fill>
</Path>

最后。我添加一个ContentPresenter  到按钮中间。经验告诉我,内容区域再向下一个像素会使得按钮看起来更漂亮。因此,在这里我用了margin属性(注意。因为内容区域在Grid的中间(Center)。所以2个像素的top实际上是向下移动了一个像素 )

好了。最后在Blend中看起来大概是这样

图4

4.添加一些交互性

4.1鼠标悬停效果

为了有鼠标悬停效果,我们需要增加光源的亮度。因此。我们为IsMouseOver 事件定义一个触发器,复制并且粘贴反射和折射层的渐变设置代码。对于折射层。我仅仅移动了渐变的起点向上了一点。在反射层中。我改变了渐变停止点。使不透明的白色多一点。

<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="RefractionLayer" Property="Fill">
<Setter.Value>
<RadialGradientBrush GradientOrigin="0.496,1.052">
<RadialGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform CenterX="0.5" CenterY="0.5"
ScaleX="1.5" ScaleY="1.5"/>
<TranslateTransform X="0.02" Y="0.3"/>
</TransformGroup>
</RadialGradientBrush.RelativeTransform>
<GradientStop Offset="" Color="#00000000"/>
<GradientStop Offset="0.45" Color="#FFFFFFFF"/>
</RadialGradientBrush>
</Setter.Value>
</Setter>
<Setter TargetName="ReflectionLayer" Property="Fill">
<Setter.Value>
<RadialGradientBrush GradientOrigin="0.498,0.526">
<RadialGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform CenterX="0.5" CenterY="0.5"
ScaleX="" ScaleY="1.997"/>
<TranslateTransform X="" Y="0.5"/>
</TransformGroup>
</RadialGradientBrush.RelativeTransform>
<GradientStop Offset="" Color="#FFFFFFFF"/>
<GradientStop Offset="0.85" Color="#BBFFFFFF"/>
<GradientStop Offset="" Color="#00000000"/>
</RadialGradientBrush>
</Setter.Value>
</Setter>
</Trigger>

4.2鼠标点击效果

对于IsPressed  事件,需要降低光。因此。反向操作即可。折射层中光源下一点。反射层中渐变停止点更加透明一些。

<Trigger Property="IsPressed" Value="True">
<Setter TargetName="RefractionLayer" Property="Fill">
<Setter.Value>
<RadialGradientBrush GradientOrigin="0.496,1.052">
<RadialGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform CenterX="0.5" CenterY="0.5"
ScaleX="1.5" ScaleY="1.5"/>
<TranslateTransform X="0.02" Y="0.3"/>
</TransformGroup>
</RadialGradientBrush.RelativeTransform>
<GradientStop Offset="" Color="#00000000"/>
<GradientStop Offset="0.3" Color="#FFFFFFFF"/>
</RadialGradientBrush>
</Setter.Value>
</Setter>
<Setter TargetName="ReflectionLayer" Property="Fill">
<Setter.Value>
<RadialGradientBrush GradientOrigin="0.498,0.526">
<RadialGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform CenterX="0.5" CenterY="0.5"
ScaleX="" ScaleY="1.997"/>
<TranslateTransform X="" Y="0.5"/>
</TransformGroup>
</RadialGradientBrush.RelativeTransform>
<GradientStop Offset="" Color="#CCFFFFFF"/>
<GradientStop Offset="0.85" Color="#66FFFFFF"/>
<GradientStop Offset="" Color="#00000000"/>
</RadialGradientBrush>
</Setter.Value>
</Setter>
</Trigger> 

再说一次。渐变停止点的值靠经验选的。我也不能给出精确的值。

5.使用代码

为了使用这个样式。把定义在GlassButton.xaml 里的样式资源文件并不到你的窗体/页里。然后设置按钮的样式为{StaticResource GlassButton}. 为了设置按钮的颜色。使用Background属性即可。

<Window x:Class="GlassButton.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Glass Buttons" Height="" Width=""> <Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources\GlassButton.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources> <Grid>
<Button Style="{StaticResource GlassButton}" Width=""
Height="" Background="#FF660707" Margin=""/>
</Grid>
</Window>

6.Demo下载

Demo与源代码下载

7.许可

本文包括源代码和文件在CPOL下授权。

[原译]一步步教你制作WPF圆形玻璃按钮的更多相关文章

  1. 在WPF中制作正圆形公章

    原文:在WPF中制作正圆形公章 之前,我利用C#与GDI+程序制作过正圆形公章(利用C#制作公章 ,C#制作公章[续])并将它集成到一个小软件中(个性印章及公章的画法及实现),今天我们来探讨一下WPF ...

  2. 一步步教你轻松学支持向量机SVM算法之理论篇1

    一步步教你轻松学支持向量机SVM算法之理论篇1 (白宁超 2018年10月22日10:03:35) 摘要:支持向量机即SVM(Support Vector Machine) ,是一种监督学习算法,属于 ...

  3. WPF圆形环绕的Loading动画

    原文:WPF圆形环绕的Loading动画 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/yangyisen0713/article/details/ ...

  4. 一步步教你搭建VS环境下用C#写WebDriver脚本

    一步步教你搭建VS环境下用C#写WebDriver脚本http://www.automationqa.com/forum.php?mod=viewthread&tid=3529&fro ...

  5. 我写了个教程《一步步教你把ubuntu安装到U盘》

    一步步教你把ubuntu安装到U盘 作者 Val 2452013147@qq.com 原因: 由于某些原因(学生党),需要把ubuntu安装到U盘到处走,百度了一下,教程都不是很好,要么很复杂,要么不 ...

  6. 一步步教你读懂NET中IL(附带图)

    一步步教你读懂NET中IL(附带图) 接触NET也有1年左右的时间了,NET的内部实现对我产生了很大的吸引力,在msdn上找到一篇关于NET的IL代码的图解说明,写的挺不错的.个人觉得:能对这些底部的 ...

  7. 一步步教你轻松学奇异值分解SVD降维算法

    一步步教你轻松学奇异值分解SVD降维算法 (白宁超 2018年10月24日09:04:56 ) 摘要:奇异值分解(singular value decomposition)是线性代数中一种重要的矩阵分 ...

  8. 一步步教你轻松学支持向量机SVM算法之案例篇2

    一步步教你轻松学支持向量机SVM算法之案例篇2 (白宁超 2018年10月22日10:09:07) 摘要:支持向量机即SVM(Support Vector Machine) ,是一种监督学习算法,属于 ...

  9. 一步步教你轻松学主成分分析PCA降维算法

    一步步教你轻松学主成分分析PCA降维算法 (白宁超 2018年10月22日10:14:18) 摘要:主成分分析(英语:Principal components analysis,PCA)是一种分析.简 ...

随机推荐

  1. php实现 密码验证合格程序(复杂问题分类,超简单的)(分类+规范编码)

    php实现 密码验证合格程序(复杂问题分类,超简单的)(分类+规范编码) 一.总结 一句话总结:复杂问题分类,超简单的.分类+规范编码. 1.写的时候判断  不能有相同长度超2的子串重复  的时候,子 ...

  2. php面试题12(多态web服务器共享session的方法:将session存到数据库)($val=&$data[$key];)

    php面试题12(多态web服务器共享session的方法:将session存到数据库)($val=&$data[$key];) 一.总结 1.多态web服务器共享session的方法: ...

  3. MethodInterceptor拦截器

    http://blog.csdn.net/heirenheiren/article/details/39030767

  4. js 进阶 10 js选择器大全

    js 进阶 10 js选择器大全 一.总结 一句话总结:和css选择器很像 二.JQuery选择器 原生javaScript中,只能使用getELementById().getElementByNam ...

  5. jQuery+ localStorage 实现一个简易的计时器

    原型 图片发自简书App 需求1.关闭浏览器时时间继续运行2.刷新时保持当前状态3.结束时间保存在客户端 <div class="wrapper"> <div c ...

  6. MySQL数据库备份详解

    原文:MySQL数据库备份详解 对于任何数据库来说,备份都是非常重要的 数据库复制不能取代备份的作用 比如我们由于误操作,在主数据库上删除了一些数据,由于主从复制的时间很短,在发现时,从数据库上的数据 ...

  7. Oracle停止一个JOB

    Oracle如何停止一个JOB 相关表.视图 dba_jobs all_jobs user_jobs 包含登录用户所有的JOB信息 dba_jobs_running 包含正在运行job相关信息 注意 ...

  8. Visual Studio 2017 and Apache Cordova mobile apps | Andrés Zsögön

    原文:Visual Studio 2017 and Apache Cordova mobile apps | Andrés Zsögön 以下是使用Microsoft Visual Studio 20 ...

  9. Codeforces #264 (Div. 2) D. Gargari and Permutations

    Gargari got bored to play with the bishops and now, after solving the problem about them, he is tryi ...

  10. 数据科学(data science)概览

    0. 硬件平台设计 一种分层的体系结构: 自下到上依次是: 硬件层 分布式系统层 分布式管理层 分布式处理层 应用层: 1. 总论