WPF学习手记-03 Basic Brushse(一)

来源:互联网 发布:如何知道mysql的密码 编辑:程序博客网 时间:2024/05/16 17:51

Chapter 2 Basic Brushes

 

在上一章里我们看到Window的颜色是White,你可以通过控制面板来改变这个默认颜色,WPF中颜色被定义为名为Color的结构体,该结构体位于System.Windows.Media namespace(注意:这里的ColorSystem.Drawing下的Color是不同的, System.Drawing下的Color用于Windows Form Application,是基于GDI or GDI+),WPF下的这个新的Color结构与原有Windows Form中的Color有什么不同呢?

先来说说相同的地方,你依然可以使用RGB值来定义Color的颜色,你也依然可以使用A来定义Color的透明度,ARGB依然是byte类型的,取值从0255.

再来说说不同的地方,新的Color结构与原来的Color最大不同就是多了4个新的属性,叫做ScA,ScR,ScG,ScB,这四个属性的数据类型是float类型的, ScA,ScR,ScG,ScBA,R,G,B是相互影响的,改变ScA,ScR,ScG,ScB的值同时也会改变A,R,G,B的值.

ScR,ScG,ScBR,G,B之间并非一个线形的关系,它们之间的关系如下表:

scG

G

<= 0

0

0.1

89

0.2

124

0.3

149

0.4

170

0.5

188

0.6

203

0.7

218

0.8

231

0.9

243

>= 1.0

255

ScR,ScG,ScBR,G,B之间有一样的关系.

阴极射线管所显示的光并非是线性的,光强I(light intensity)与显示器上的电压V(voltages)存在如下的关系:

I = Vγ

γ表示的值是代表显示器的特征和周围环境的光,而我们通常所使用的显示器该值的范围在2.2~2.5之间,R,G,B采用的是值为2.2的转换(这里一大堆理论知识的描述,看的好头晕,什么人类感知光是非线性的,但近似是线性的@#$%... ...),总之,ScGG之间存在下面的近似转换公式:

ScG(G/255)2.2

意这个近似关系,当值很小的时候此公式越准确,ScAA之间存在更加简单的关系:

ScA = A/255

Sc-类型的Color的引入主要是为了解决WPF Application在不同的场合下能够拥有相同的表现而引入的;

你还可以使用以下的静态方法创建Color结构:

Color.FromRgb(r,g,b);

Color.FromArgb(a,r,g,b);

Color.FromScRgb(a,r,g,b);

System.Windows.Media下同时还包含一个名为Colors的类,里面定义了141个只读属性比如AliceBlue,AntiqueWhite,Yellow,Lime. 这些颜色在Web程序上也是同样的.

141个颜色的中有一个特殊的就是Transparent(透明),它与其它140Color的不同在于TransparentA0,而其它ColorA255;

 

介绍完了Color,这时让我们来设置一下Window的背景颜色,我尝试像Windows Form那样去设置Windowbackground:

win.Background = Colors.Blue;

报错了,因为Window对象的Background是一个Brush类型的属性.

 

BrushWPF体系中的应用是如此的广泛,Brush本身是一个抽象类,Brush的类层次如下所示:

Object

    DispatcherObject (abstract)

          DependencyObject

                Freezable (abstract)

                       Animatable (abstract)

                             Brush (abstract)

                                   GradientBrush (abstract)

                                         LinearGradientBrush

                                         RadialGradientBrush

                                   SolidColorBrush

                                   TileBrush (abstract)

                                          DrawingBrush

                                          ImageBrush

                                          VisualBrush

Brush同样位于System.Windows.Media namespace,本章要介绍的是SolidColorBrushGradientBrush下面的2Brush.

SolidColorBrush是单色Brush,你可以用下面的代码为WindowBackground赋值:

win.Background = new SolidColorBrush(Colors.Blue);

Colors类似,System.Windows.Media下面同样有一个Brushes Class,该类中也包含了141只读属性,141个属性返回141SolidColorBrush,贴段代码:

 

//--------------------------------------------------

// VaryTheBackground.cs (c) 2006 by Charles Petzold

//--------------------------------------------------

using System;

using System.Windows;

using System.Windows.Input;

using System.Windows.Media;

 

namespace Petzold.VaryTheBackground

{

    
public class VaryTheBackground : Window

    
{

        SolidColorBrush brush 
= new

 SolidColorBrush(Colors.Black);

 

        [STAThread]

        
public static void Main()

        
{

            Application app 
= new Application();

            app.Run(
new VaryTheBackground());

        }


        
public VaryTheBackground()

        
{

            Title 
= "Vary the Background";

            Width 
= 384;

            Height 
= 384;

            Background 
= brush;

        }


        
protected override void OnMouseMove

(MouseEventArgs args)

        
{

            
double width = ActualWidth

                
- 2 * SystemParameters

.ResizeFrameVerticalBorderWidth;

            
double height = ActualHeight

                
- 2 * SystemParameters

.ResizeFrameHorizontalBorderHeight

                
- SystemParameters.CaptionHeight;

 

            Point ptMouse 
= args.GetPosition(this);

            Point ptCenter 
= new Point(width / 2,

 height 
/ 2);

            Vector vectMouse 
= ptMouse - ptCenter;

            
double angle = Math.Atan2(vectMouse.Y,

 vectMouse.X);

            Vector vectEllipse 
= new Vector(width

/ 2 * Math.Cos(angle),

                                            height

 
/ 2 * Math.Sin(angle));

            Byte byLevel 
= (byte)(255 * (1 - Math

.Min(
1, vectMouse.Length /

 

        vectEllipse.Length)));

            Color clr 
= brush.Color;

            clr.R 
= clr.G = clr.B = byLevel;

            brush.Color 
= clr;

        }


    }


}


 

    运行一下这段代码,很酷吧!现在把

SolidColorBrush brush = new SolidColorBrush(Colors.Black);

换成

SolidColorBrush brush = Brushes.Black;

竟然报错了

Cannot set a property on object '#FF000000' because it is in a read-only state.

原因稍后解释,首先对于上面的代码,你看到了很酷的效果,你会发现当你移动鼠标的时候Window一直在重绘,但其实这一切都发生在后台,这种动态响应的方式是由于Brush继承了Freezable抽象类,实现了该类的一个名为Changed的事件,这个事件在Brush发生任何改变时触发,这也是为什么Background一直会被重绘的原因.对于Animation以及WPF的其它一些特征Changed事件用相同的机制在后台发挥着作用.

现在来解释一下上面的错误.Brushes返回的SolidColorBrush是一个frozen(被冻结)Freezable对象,这就意味着它将不能再被改变,由于SolidColorBrushChanged事件等都是从Freezable继承来的,如果Freezable对象的CanFreeze属性设置为true,你就可以调用Freeze方法得到一个被冻结的不能改变的对象,因为它不再需要监控任何改变.一个frozen(被冻结)Freezable对象可以被其它线程共享(share),而一个unfrozen(未被冻结)Freezable对象却不能.尽管我们无法为一个已经frozen(被冻结)Freezable对象解冻”,但我们可以从这个已经frozen(被冻结)Freezable对象获得一个unfrozen(未被冻结)Copy!

你现在可以把

SolidColorBrush brush = Brushes.Black;

换成

SolidColorBrush brush = Brushes.Black.Clone();

现在程序又可以正常工作了.System.Window下面有一个SystemColors的类,该类下面定义了与系统相关的ColorBrush,这里的Brush也是frozen(被冻结),所以可以改变这个Brush

Brush brush = new SystemColorBrush(SystemColors.WindowColor);

但不可以改变这个Brush

Brush brush = SystemColors.WindowBrush;

    只有从Freezable对象继承来的对象才可以,WPF里没有frozen (被冻结)Color,因为Color是结构体(structure not object).
原创粉丝点击