原理
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