原理
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
>
运行结果如下:
3. 依赖属性具有属性值继承关系,即一些属性可以对于子元素进行向下继承,比如,我在UserControl设置了FontSize="20",并且在邮箱那个文本框设置了FontSize=”12”:运行得到:
说明这两个设置将会向下传递,由子元素继承。
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
>
运行结果两个起始状态图:
从运行结果可以得出,最后的状态为FontSize="40”,说明动画值的优先级比本地值FontSize=”12”高。
如果本地值还是读取不到,那么就读取模板和样式中设置的值,然后才是读取前面说的属性值继承,最后才是系统默认的设置值。
先写到这么多,晚了去睡觉了:)
源代码下载:SilverlightAppDemo.rar