• 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

  • 相关阅读:
    记一次干扰后处理特效的实现
    Cosine-Weighted采样算法
    PBR技术简介(三):菲涅尔公式
    PBR技术简介(二):Cook-Torrance BRDF
    PBR技术简介(一)
    Python函数的默认参数坑点解析
    屏幕空间环境光屏蔽(SSAO)探秘
    辐射度量学简介(二)
    辐射度量学简介(一)
    解决16bit压缩贴图失真问题
  • 原文地址:https://www.cnblogs.com/liping13599168/p/1729357.html
Copyright © 2020-2023  润新知