现在的位置: 首页 > 综合 > 正文

WPF程序设计读书笔记(2-2)

2013年02月17日 ⁄ 综合 ⁄ 共 7818字 ⁄ 字号 评论关闭

 

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));
        }
    }
}
接着,我们做一点小小的变化,换个画笔。从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,为了要让此属性可以发挥效用,我们需要在窗口上放置一些内容。内容的形式有很多种,可以是文字、图、控件等,下一章我们开始讨论。

抱歉!评论已关闭.