Windows Presentation Foundation (WPF) 提供了一组服务,这些服务可用于扩展公共语言运行时 (CLR) 属性的功能。这些服务通常统称为 WPF 属性系统。由 WPF 属性系统支持的属性称为依赖项属性。本概述介绍 WPF 属性系统以及依赖项属性的功能,这包括如何在可扩展应用程序标记语言 (XAML) 中和代码中使用现有的依赖项属性。
依赖项属性的用途在于提供一种方法来基于其他输入的值计算属性值。这些其他输入可以包括系统属性(如主题和用户首选项)、实时属性确定机制(如数据绑定和动画/演示图板)、重用模板(如资源和样式)或者通过与元素树中其他元素的父子关系来公开的值。另外,可以通过实现依赖项属性来提供独立验证、默认值、监视其他属性的更改的回调以及可以基于可能的运行时信息来强制指定属性值的系统。派生类还可以通过重写依赖项属性元数据(而不是重写现有属性的实际实现或者创建新属性)来更改现有属性的某些具体特征。
1、依赖项属性与CLR 包装属性
以Button的Backgroud为例,设置或获取其值可以有以下几种方式:
XAML文件中
1: <StackPanel>
2: <!--
3: 在所生成的代码中,XAML加载器将 XAML 属性的简单字符串值的
4: 类型转换为 WPF 类型(一种 Color,通过 SolidColorBrush)。
5: -->
6: <Button Margin="3" Background="Yellow" Content="Button A" />
7:
8: <!--
9: 使用嵌套元素的方式,设置Button.Backgroud的值
10: -->
11: <Button Margin="3" Content="Button B" x:Name="btn_ButtonB">
12: <Button.Background>
13: <SolidColorBrush Color="Gold" />
14: </Button.Background>
15: </Button>
16:
17: <!--预留给代码使用的控件-->
18: <Button Margin="3" Content="Button C" x:Name="btn_ButtonC" />
19: <Button Margin="3" Content="Button D" x:Name="btn_ButtonD" />
20: <TextBox Margin="3" x:Name="txt_Value1" />
21: <TextBox Margin="3" x:Name="txt_Value2" />
22: </StackPanel>
代码文件中:
1: // 通过包装的属性设置按钮的背景颜色
2: btn_ButtonC.Background = new SolidColorBrush(Colors.Red);
3:
4: // 通过依赖性属性的SetValue设置按钮的背景颜色
5: SolidColorBrush brush = new SolidColorBrush(Colors.Blue);
6: btn_ButtonD.SetValue(
7: Button.BackgroundProperty, brush);
8:
9: // 通过包装的属性获取ButtonB的背景颜色
10: SolidColorBrush b_Brush1 = (SolidColorBrush) (btn_ButtonB.Background);
11: txt_Value1.Text = b_Brush1.Color.ToString();
12:
13: // 通过依赖性属性的GetValue获取ButtonB的背景颜色
14: SolidColorBrush b_Brush2 = (SolidColorBrush) (btn_ButtonB.GetValue(
15: Button.BackgroundProperty));
16: txt_Value2.Text = b_Brush2.Color.ToString();
如果使用的是现有属性,则上述操作通常不是必需的(使用包装会更方便,并能够更好地向开发人员工具公开属性)。但是在某些情况下适合直接调用 API。
2、使用由依赖项属性提供的属性功能
依赖项属性提供用来扩展属性功能的功能,这与字段支持的属性相反。每个这样的功能通常都表示或支持整套 WPF 功能中的特定功能:
· 资源
· 数据绑定
· 样式
· 动画
· 元数据重写
· 属性值继承
· WPF 设计器集成
3、自定义依赖项属性及重写依赖项属性
对于自定义依赖项属性,其所在的类型必须直接或间接继承System.Windows.DependencyObject类,依赖项属性是通过调用 Register 方法(或 RegisterReadOnly,自定义的只读的依赖项属性)在 WPF 属性系统中注册,并通过 DependencyProperty 标识符字段备份的属性。依赖项属性只能由 DependencyObject 类型使用,但 DependencyObject 在 WPF 类层次结构中的级别很高,因此,WPF 中的大多数可用类都支持依赖项属性。在对依赖项属性及CLR包装属性命名时必须满足:CLR包装属性名+Property=依赖项属性名。
例如:在某DependencyObject类的子类中定义:
1: // 定义并注册依赖项属性
2: public static readonly DependencyProperty AquariumGraphicProperty =
3: DependencyProperty.Register(
4: "AquariumGraphic", // 要注册的依赖项对象的名称
5: typeof(Uri), // 属性的类型
6: typeof(AquariumObject), // 正注册依赖项对象的所有者类型
7: new FrameworkPropertyMetadata( // 依赖项对象的属性元数据
8: null,
9: FrameworkPropertyMetadataOptions.AffectsRender,
10: new PropertyChangedCallback(OnUriChanged)
11: )
12: );
13:
14: // 定义CLR包装属性
15: public Uri AquariumGraphic
16: {
17: get { return (Uri)GetValue(AquariumGraphicProperty); }
18: set { SetValue(AquariumGraphicProperty, value); }
19: }
Register方法有多种重载,示例中用到的是以下签名:
public static DependencyProperty Register(string name, Type propertyType, Type ownerType, PropertyMetadata typeMetadata);
//
// 摘要:
// 使用指定的属性名称、属性类型、所有者类型和属性元数据注册依赖项属性。
//
// 参数:
// name:
// 要注册的依赖项对象的名称。
//
// propertyType:
// 属性的类型。
//
// ownerType:
// 正注册依赖项对象的所有者类型。
//
// typeMetadata:
// 依赖项对象的属性元数据。
//
// 返回结果:
// 一个依赖项对象标识符,应使用它在您的类中设置 public static readonly 字段的值。然后,在以后使用该标识符引用依赖项对象,用于某些操作,例如以编程方式设置其值,或者获取元数据。
这里说一下ownerType参数,它只的是注册依赖项属性的类型,如本例中就是Student类。
typeMetadata是所谓的元数据,就是属性的默认,当然,它也有N个构造函数,可以同时传递事件委托来对属性的改性或类型转换时进行事件处理。