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

 原理

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

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

public class CLRButton 

    
public string Name { getset; } 

    
public double FontSize { getset; } 

    
public string Background { getset; } 

    
//其他属性... 
}

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

代码
public abstract class Control : FrameworkElement 

    
public static readonly DependencyProperty FontWeightProperty = DependencyProperty.RegisterCoreProperty(0x80003717typeof(FontWeight)); 
    
public static readonly DependencyProperty FontSizeProperty = DependencyProperty.RegisterCoreProperty(0x80003714typeof(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

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

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

 

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

源代码下载:SilverlightAppDemo.rar

 

posted @ 2010-05-07 01:37 Leepy 阅读(...) 评论(...) 编辑 收藏