WPF程序设计读书笔记(2
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,为了要让此属性可以发挥效用,我们需要在窗口上放置一些内容。内容的形式有很多种,可以是文字、图、控件等,下一章我们开始讨论。