原理
1. Silverlight和WPF一样都包含依赖属性,它是通过 DependencyProperty类来实现的。
CLR属性和依赖属性还是有本质的差别,什么是CLR属性?很简单,大家都用过,比如:
{
public string Name { get ; set ; }
public double FontSize { get ; set ; }
public string Background { get ; set ; }
// 其他属性...
}
传统的属性成员写法。那依赖属性会是如何书写,截取一段Control(实际上也是Button的基类)的代码:


{
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);
}
}
}
比起CLR属性,这样有什么好处?如果CLR属性类,包含相当多的属性成员,势必将造成每个实例占用大量的内存,因为每个属性成员都要分配一块内存空间。这依赖属性就没有这个问题,因为它通过GetValue和SetValue来使用,因为DependencyObject维护着一套高效的存储系统。
2. Control对于DependencyProperty的使用,针对内置依赖属性的注册,使用了RegisterCoreProperty方法;而如果需要实现自己的依赖属性,那么就需要使用Register方法,那么接下来看下如何使用Register方法:
这个实例实现一个焦点高亮显示的文本框,那么直接继承 TextBox:
声明两个DependencyProperty属性:


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 = 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中的获取焦点以及失去焦点时执行的事件,并且设置了背景色。
该高亮文本框完整代码如下:


{
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用户控件的代码:


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 >
运行结果如下:
3. 依赖属性具有属性值继承关系,即一些属性可以对于子元素进行向下继承,比如,我在UserControl设置了FontSize="20",并且在邮箱那个文本框设置了FontSize=”12”:运行得到:
说明这两个设置将会向下传递,由子元素继承。
4. 元素的依赖属性通过一定的优先级顺序进行设置。按照优先级从高到低的顺序分为:动画值、本地值、模版值、样式值、属性值继承、默认值。
动画值的优先级最高,看下面的一段代码:


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 >
运行结果两个起始状态图:
从运行结果可以得出,最后的状态为FontSize="40”,说明动画值的优先级比本地值FontSize=”12”高。
如果本地值还是读取不到,那么就读取模板和样式中设置的值,然后才是读取前面说的属性值继承,最后才是系统默认的设置值。
先写到这么多,晚了去睡觉了:)
源代码下载:SilverlightAppDemo.rar