Silverlight渐进学习系列(2)——关于依赖属性

 原理

1. Silverlight和WPF一样都包含依赖属性,它是通过 DependencyProperty类来实现的。

CLR属性和依赖属性还是有本质的差别,什么是CLR属性?很简单,大家都用过,比如:

public   class  CLRButton 

    
public   string  Name {  get set ; } 

    
public   double  FontSize {  get set ; } 

    
public   string  Background {  get set ; } 

    
// 其他属性... 
}

传统的属性成员写法。那依赖属性会是如何书写,截取一段Control(实际上也是Button的基类)的代码:

代码
public   abstract   class  Control : FrameworkElement 

    
public   static   readonly  DependencyProperty FontWeightProperty  =  DependencyProperty.RegisterCoreProperty( 0x80003717 typeof (FontWeight)); 
    
public   static   readonly  DependencyProperty FontSizeProperty  =  DependencyProperty.RegisterCoreProperty( 0x80003714 typeof ( double )); 
    
public   double  FontSize 
    { 
        
get  
        { 
            
return  ( double ) base .GetValue(FontSizeProperty); 
        } 
        
set  
        { 
            
base .SetValue(FontSizeProperty, value); 
        } 
    } 
    
public  FontWeight FontWeight 
    { 
        
get  
        { 
            
return  (FontWeight) base .GetValue(FontWeightProperty); 
        } 
        
set  
        { 
            
base .SetValue(FontWeightProperty, value); 
        } 
    } 
}
其中GetValue和SetValue方法调用DependencyObject基类的方法。

比起CLR属性,这样有什么好处?如果CLR属性类,包含相当多的属性成员,势必将造成每个实例占用大量的内存,因为每个属性成员都要分配一块内存空间。这依赖属性就没有这个问题,因为它通过GetValue和SetValue来使用,因为DependencyObject维护着一套高效的存储系统。

 

2. Control对于DependencyProperty的使用,针对内置依赖属性的注册,使用了RegisterCoreProperty方法;而如果需要实现自己的依赖属性,那么就需要使用Register方法,那么接下来看下如何使用Register方法:

这个实例实现一个焦点高亮显示的文本框,那么直接继承 TextBox:

声明两个DependencyProperty属性:

代码
private   static   readonly  DependencyProperty FocusBackgroundProperty; 
private   static   readonly  DependencyProperty BlurBackgroundProperty;

///   <summary>  
///  获得焦点时的文本框背景色 
///   </summary>  
public  Brush FocusBackground 

     
set  
     { 
         SetValue (FocusBackgroundProperty, value); 
     } 
     
get  
     { 
         
return  (Brush)GetValue(FocusBackgroundProperty); 
     } 


///   <summary>  
///  失去焦点时的文本框背景色 
///   </summary>  
public  Brush BlurBackground 

     
set  
     { 
         SetValue (BlurBackgroundProperty, value); 
     } 
     
get  
     { 
         
return  (Brush)GetValue(BlurBackgroundProperty); 
     } 
}

那么需要在静态构造函数来注册这两个依赖属性:

代码
// 注册FocusBackgroundProperty依赖属性 
FocusBackgroundProperty  =  DependencyProperty.Register( 
    
" FocusBackground " typeof (Brush),  typeof (HightLightTextBox), 
    
new  PropertyMetadata( new  SolidColorBrush(Colors.Yellow), (obj, args)  =>  
    { 
        TextBox txt 
=  obj  as  TextBox; 
        txt.GotFocus 
+=   new  RoutedEventHandler((sender, e)  =>  
        { 
            txt.Background 
=  (Brush)args.NewValue; 
        }); 
    })); 

// 注册BlurBackgroundProperty依赖属性 
BlurBackgroundProperty  =  DependencyProperty.Register( 
    
" BlurBackground " typeof (Brush),  typeof (HightLightTextBox), 
    
new  PropertyMetadata( new  SolidColorBrush(Colors.White), (obj, args)  =>  
    { 
        TextBox txt 
=  obj  as  TextBox; 
        txt.LostFocus 
+=   new  RoutedEventHandler((sender, e)  =>  
        { 
            txt.Background 
=  (Brush)args.NewValue; 
        }); 
    }));

可以发现两个都执行了Register方法,它的声明为:

public static DependencyProperty Register(string name, Type propertyType, Type ownerType, PropertyMetadata typeMetadata);

第一个对应属性的名称,第二个对应属性的类型,第三个就是执行该依赖属性的载体,第四个为对属性赋值时,将执行的动作;

那么两个方法分别调用了TextBox中的获取焦点以及失去焦点时执行的事件,并且设置了背景色。

该高亮文本框完整代码如下:

HighLightTextBox代码
public   class  HightLightTextBox : TextBox 

    
private   static   readonly  DependencyProperty FocusBackgroundProperty; 
    
private   static   readonly  DependencyProperty BlurBackgroundProperty; 

    
static  HightLightTextBox() 
    { 
        
// 注册FocusBackgroundProperty依赖属性 
        FocusBackgroundProperty  =  DependencyProperty.Register( 
            
" FocusBackground " typeof (Brush),  typeof (HightLightTextBox), 
            
new  PropertyMetadata( new  SolidColorBrush(Colors.Yellow), (obj, args)  =>  
            { 
                TextBox txt 
=  obj  as  TextBox; 
                txt.GotFocus 
+=   new  RoutedEventHandler((sender, e)  =>  
                { 
                    txt.Background 
=  (Brush)args.NewValue; 
                }); 
            })); 

        
// 注册BlurBackgroundProperty依赖属性 
        BlurBackgroundProperty  =  DependencyProperty.Register( 
            
" BlurBackground " typeof (Brush),  typeof (HightLightTextBox), 
            
new  PropertyMetadata( new  SolidColorBrush(Colors.White), (obj, args)  =>  
            { 
                TextBox txt 
=  obj  as  TextBox; 
                txt.LostFocus 
+=   new  RoutedEventHandler((sender, e)  =>  
                { 
                    txt.Background 
=  (Brush)args.NewValue; 
                }); 
            })); 
    } 

    
///   <summary>  
    
///  获得焦点时的文本框背景色 
    
///   </summary>  
     public  Brush FocusBackground 
    { 
        
set  
        { 
            SetValue(FocusBackgroundProperty, value); 
        } 
        
get  
        { 
            
return  (Brush)GetValue(FocusBackgroundProperty); 
        } 
    } 

    
///   <summary>  
    
///  失去焦点时的文本框背景色 
    
///   </summary>  
     public  Brush BlurBackground 
    { 
        
set  
        { 
            SetValue(BlurBackgroundProperty, value); 
        } 
        
get  
        { 
            
return  (Brush)GetValue(BlurBackgroundProperty); 
        } 
    } 
}

 

 

接着,编写xaml用户控件的代码:

代码
< UserControl  x:Class ="SilverlightAppDemo.Demo2.HighLightTextBoxControl"  
    xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
    xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"  
             xmlns:uc
="clr-namespace:SilverlightAppDemo"  FontSize ="20" >  
    
< StackPanel  Margin ="20"  HorizontalAlignment ="Left" >  
        
< TextBlock > 用户名: </ TextBlock >< uc:HightLightTextBox  x:Name ="txt1"  Width ="200"  Height ="40"  FocusBackground ="Yellow"  BlurBackground ="White"  Margin ="0,0,0,5"   />  
        
< TextBlock > 邮箱: </ TextBlock >< uc:HightLightTextBox  FontSize ="12"  x:Name ="txt2"  Width ="200"  Height ="40"  FocusBackground ="Yellow"  BlurBackground ="White"   />  
    
</ StackPanel >  
</ UserControl >

运行结果如下:

4

 

3. 依赖属性具有属性值继承关系,即一些属性可以对于子元素进行向下继承,比如,我在UserControl设置了FontSize="20",并且在邮箱那个文本框设置了FontSize=”12”:运行得到:

5

说明这两个设置将会向下传递,由子元素继承。

 

4. 元素的依赖属性通过一定的优先级顺序进行设置。按照优先级从高到低的顺序分为:动画值、本地值、模版值、样式值、属性值继承、默认值。

动画值的优先级最高,看下面的一段代码:

代码
< UserControl  x:Class ="SilverlightAppDemo.Demo2.DependencyPropertyControl"  
    xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
    xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"  Margin ="20" >  
    
< StackPanel  HorizontalAlignment ="Left" >  
        
< Button  FontSize ="12"  Content ="Hello, Leepy!"  x:Name ="btnBlock" >  
            
< Button.Triggers >  
                
< EventTrigger >  
                    
< BeginStoryboard >  
                        
< Storyboard >  
                            
< DoubleAnimation 
                        
Storyboard.TargetName ="btnBlock"  
                        Storyboard.TargetProperty
="FontSize"  
                        To
="40"  
                        Duration
="Automatic"  
                        AutoReverse
="False"  
                        RepeatBehavior
="1x" >  
                            
</ DoubleAnimation >  
                        
</ Storyboard >  
                    
</ BeginStoryboard >  
                
</ EventTrigger >  
            
</ Button.Triggers >  
        
</ Button >  
    
</ StackPanel >  
</ UserControl >

运行结果两个起始状态图:

6 Silverlight渐进学习系列(2)——关于依赖属性

从运行结果可以得出,最后的状态为FontSize="40”,说明动画值的优先级比本地值FontSize=”12”高。

如果本地值还是读取不到,那么就读取模板和样式中设置的值,然后才是读取前面说的属性值继承,最后才是系统默认的设置值。

 

先写到这么多,晚了去睡觉了:)

源代码下载:SilverlightAppDemo.rar

 

你可能感兴趣的:(silverlight)