LinearGradientBrush 其实变化多端,远比这两个例子所能展示的更多。渐变的颜色不限定两个,可以有更多。想运用这样的特性,需要使用到 GradientBrush 定义的 GradientStops 属性。 GradientStops 属性是 GradientStopCollection 类型,它是 GradientStop 对
LinearGradientBrush 其实变化多端,远比这两个例子所能展示的更多。渐变的颜色不限定两个,可以有更多。想运用这样的特性,需要使用到 GradientBrush 定义的 GradientStops 属性。
GradientStops 属性是 GradientStopCollection 类型,它是 GradientStop 对象的集合。 GradientStop 具有 Color 和 Offset 属性,它们分别表示颜色和渐变的范围。
Offset 属性的值正常是在 0 至 1 之间,其意义是 StartPoint 和 EndPoint 的相对距离。
下面的程序创建一个水平 LinearGradientBrush ,且针对彩虹的 7 种颜色设定数个 GradientStop 对象。它们依次从左到右,每个 GradientStop 是 1/6 个窗口宽。
//*********************************************************
//AdjustTheGradient.cs 2010 31th July by mouyong
//*********************************************************
using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
namespace part1.ch02
{
class FollowTheRainbow:Window
{
[STAThread]
public static void Main()
{
Application app = new Application();
app.Run(new FollowTheRainbow());
}
public FollowTheRainbow()
{
Title = " 模拟彩虹 ";
LinearGradientBrush brush = new LinearGradientBrush();
brush.StartPoint = new Point(0,0);
brush.EndPoint = new Point(1,0);
Background = brush;
// 采用 Rey G.Biv 彩虹助记符
brush.GradientStops.Add(new GradientStop(Colors.Red,0));
brush.GradientStops.Add(new GradientStop(Colors.Orange,.17));
brush.GradientStops.Add(new GradientStop(Colors.Yellow,.33));
brush.GradientStops.Add(new GradientStop(Colors.Green,.5));
brush.GradientStops.Add(new GradientStop(Colors.Blue,.67));
brush.GradientStops.Add(new GradientStop(Colors.Indigo,.84));
brush.GradientStops.Add(new GradientStop(Colors.Violet,1));
}
}
}
( 默然说话:我上网查了一下,在维基下面找到一篇关于 Rey G.Biv 彩虹助记系统的英文文章,英文好的同学可以到 http://en.wikipedia.org/wiki/ROYGBIV 了解一下,大概意思是说,在艺术中所使用颜色的种类是如何被确定下来的,而 Rey G.Biv 这个人发明了帮助大家记住这几颜色的符号,它就是上面代码提到的 Rey G.Biv 彩虹助记符。换个说法, Rey G.BIV 这个人看到大家为了究竟画画用到的最基本颜色的名称而在吵来吵去,心里很纠结,于是他就召开了会议,定下来,最基本七种颜色的名称分别是 Red,Orange,Yellow,Green,Blue,Indigo,Violet 。你要是用了别的名称,那就抓起来打屁屁!这就是 Rey G.BIV 助记符! )
接着,我们做一点小小的变化,换个画笔。从 LinearGradientBrush 变到 RadiaGradientBrush ,这个类不需要指定 StartPoint 和 EndPoint 属性,就得到了下面的程序。
//*********************************************************
//CircleTheRainbow.cs 2010 31th July by mouyong
//*********************************************************
using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
namespace part1.ch02
{
class CircleTheRainbow:Window
{
[STAThread]
public static void Main()
{
Application app = new Application();
app.Run(new CircleTheRainbow());
}
public CircleTheRainbow()
{
Title = " 模拟彩虹 ";
RadialGradientBrush brush = new RadialGradientBrush();
Background = brush;
// 采用 Rey G.Biv 彩虹助记符
brush.GradientStops.Add(new GradientStop(Colors.Red, 0));
brush.GradientStops.Add(new GradientStop(Colors.Orange, .17));
brush.GradientStops.Add(new GradientStop(Colors.Yellow, .33));
brush.GradientStops.Add(new GradientStop(Colors.Green, .5));
brush.GradientStops.Add(new GradientStop(Colors.Blue, .67));
brush.GradientStops.Add(new GradientStop(Colors.Indigo, .84));
brush.GradientStops.Add(new GradientStop(Colors.Violet, 1));
}
}
}
上面这个程序的画刷不是从左刷到右,而是从客户区的中心点以红色开始,然后遍历这些颜色,一直到紫色。
很明显, RadialGradientBrush 是按一个椭圆来进行渐变的,它有三个属性来定义这个椭圆: Cente 是椭圆的中心, RadiusX 和 RadiusY 是椭圆的水平和垂直轴半径。
椭圆的圆周受到 Center 、 RadiusX 、 RadiusY 属性的影响,而圆周的颜色就是 Offset 为 1 的颜色。
GradientOrigin 属性可以设置颜色渐变的开始点,它的颜色就是 Offset 为 0 时的颜色,你可以通过 GradientOrigin 来设置渐变的原点。
渐变发生在 GradientOrigin 到圆周之间。如果 GradientOrigin 离圆周近,则颜色渐变就会比较剧烈,反之则比较平和,想感受一下这种影响,可以在 CircleTheRainbow 中插入下面的代码:
brush.GradientOrigin = new Point(0.75, 0.75);
你可能想要体验一下 Center 和 GradientOrigin 属性的变化所造成的视觉效果,那么 ClickTheGradientCenter 程序能满足你的要求。此程序使用 RadialGradientBrush 带两个参数的构造函数,定义 GradientOrigin 和椭圆圆周的颜色,然后,设定 RadiusX 和 RadiusY 的值为 0.1 ,且 SpreadMethod 为 Repeat ,所以画刷显示的是一系列的同心渐变圆圈。
//*********************************************************
//ClickTheGradientCenter.cs 2010 1st Auguest by mouyong
//*********************************************************
using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
namespace part1.ch02
{
class ClickTheGradientCenter:Window
{
RadialGradientBrush brush;
[STAThread]
public static void Main()
{
Application app = new Application();
app.Run(new ClickTheGradientCenter());
}
public ClickTheGradientCenter()
{
Title = " 点击改变中心 ";
brush = new RadialGradientBrush(Colors.White,Colors.Red);
brush.RadiusX = brush.RadiusY = 0.1;
brush.SpreadMethod = GradientSpreadMethod.Repeat;
Background = brush;
}
protected override void OnMouseDown(MouseButtonEventArgs e)
{
base.OnMouseDown(e);
double width = ActualWidth - 2 * SystemParameters.ResizeFrameVerticalBorderWidth;
double height = ActualHeight - 2 * SystemParameters.ResizeFrameHorizontalBorderHeight - SystemParameters.CaptionHeight;
Point ptMouse = e.GetPosition(this);
ptMouse.X /= width;
ptMouse.Y /= height;
if (e.ChangedButton == MouseButton.Left)
{
brush.Center = ptMouse;
brush.GradientOrigin = ptMouse;
}else if(e.ChangedButton==MouseButton.Right)
{
brush.GradientOrigin = ptMouse;
}
}
}
}
此程序重写了 OnMouseDown 方法,所以点击客户区,也会有反应。鼠标左键将 Center 和 GradientOrigin 设置为相同的值,你会看到整个画出来的同心圆在客户区中移动;而当你鼠标右键时只会改变 GradientOrigin 。只要在圆的内部,你就会看到这个渐变如何在一边被挤压,而另一边却变得宽松。如果你点到了圆的外部,那就看到另外的一个效果,自己试试吧。
下面,我们尝试把它作成一个动画。先不使用任何 WPF 提供的动画功能,只用计时器来改变 GradientOrigin 属性。
在 .NET 中,至少有 4 个计时器类型,其中 3 个都叫做 Timer 。 System.Threading 和 System.Timers 内的 Timer 类,在我们这个例子中并不能被使用,因为这些 timer 事件发生在不同的线程中,而 Freezable 对象只能被同一个线程所改变,而不能被其他线程改变。 System.Window.Forms 的 Timer 类使用起来又比较麻烦,需要往项目中导入对 System.Windows.Forms.dll 组件的引用。
所以,我们觉得 System.Windows.Threading 命名空间的 DispatcherTimer 类是最适合的。你可以利用 TimeSpan 来设定 Interval 属性,不过最小间隔被限定在 10 毫秒。
下面的程序创建了一个正方形窗口,窗口不大,以免占用太多系统时间。
//*********************************************************
//RotateTheGradientOrigin.cs 2010 1st Auguest by mouyong
//*********************************************************
using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;
namespace part1.ch02
{
class RotateTheGradientOrigin:Window
{
RadialGradientBrush brush;
double angle;
[STAThread]
public static void Main()
{
Application app = new Application();
app.Run(new RotateTheGradientOrigin());
}
public RotateTheGradientOrigin()
{
Title = " 转动的渐变原点 ";
WindowStartupLocation = WindowStartupLocation.CenterScreen;
Width = 384;
Height = 384;
brush = new RadialGradientBrush(Colors.White,Colors.Blue);
brush.Center = brush.GradientOrigin = new Point(0.5,0.5);
brush.RadiusX = brush.RadiusY = 0.1;
brush.SpreadMethod = GradientSpreadMethod.Repeat;
Background = brush;
DispatcherTimer tmr = new DispatcherTimer();
tmr.Interval = TimeSpan.FromMilliseconds(100);
tmr.Tick += TimerOnTick;
tmr.Start();
}
void TimerOnTick(object sender, EventArgs e)
{
Point pt = new Point(0.5+0.05*Math.Cos(angle),0.5+0.05*Math.Sin(angle));
brush.GradientOrigin = pt;
angle += Math.PI / 6;
}
}
}
在这一章,我们重点讨论的是 Background 属性,其实 Window 还有另外两个属性也是 Brush 类型的,其中一个是 OpacityMask ,这个属性是从 UIElement 继承而来,第 31 章会详细讨论。
Window 的另两个 Brush 属性都是从 Control 继承而来的,一个是 BorderBrush ,可以在客户区的周边绘制一个边框。把下面的代码插入到程序中,看看结果会如何?
BorderBrush = Brushes.SaddleBrown;
BorderThickness = new Thickness(25,50,75,100);
Tickness 用来指示客户区四边的边界宽度。如果你想要让四边具有相同的边框,可以使用单一参数的构造函数:
BorderThickness = new Thickness(25,50,75,100);
当然,你也可以对边框使用渐变画刷。
BorderBrush = new LinearGradientBrush(Colors.Red,Colors.Blue,new Point(0,0),new Point(1,1));
BorderBrush 会让客户区的面积变小。如果你使用 BorderBrush 且设定 Background 属性为渐变画刷,就很容易看出来。即使两个画刷完全相同,它们也不会彼此交融。
Window 类的另一个 Brush 是 Foreground ,为了要让此属性可以发挥效用,我们需要在窗口上放置一些内容。内容的形式有很多种,可以是文字、图、控件等,下一章我们开始讨论。