WPF依赖属性
WPF提供了一组服务,这些服务可用于扩展公共语言运行时 (CLR) 属性的功能。 这些服务通常统称为 WPF 属性系统。 由 WPF 属性系统支持的属性称为依赖属性。
为何要使用依赖属性?
场景一:一个界面有100个按钮,每个按钮有100个属性,那么系统需要为10000个属性分配内存,然而大部分属性都是使用初始时的默认值。
场景二:假如按钮父类Background为黑色,按钮样式的Background为红色,按钮的Background属性绑定到了另外一个按钮的背景色(蓝色),同时这个按钮正在播放一个动画,Background由黄色变成绿色,那么按钮显示出来的背景色到底是什么颜色,动画播放完后又会是什么颜色?
依赖属性使用的场景
- 希望可在样式中设置属性
- 希望属性支持数据绑定
- 希望可使用动态资源引用设置属性
- 希望从元素树中的父元素自动继承属性值
- 希望属性可进行动画处理
- 希望属性在属性系统、环境或用户执行的操作或者读取并使用样式更改了属性以前的值时报告
- 希望使用已建立的、WPF 进程也使用的元数据约定,例如报告更改属性值时是否要求布局系统重新编写元素的可视化对象
自定义依赖属性
1、从DependencyObject类继承
2、定义一个静态的DependencyProperty对象
public static readonly DependencyProperty IsSpinningProperty =
DependencyProperty.Register( "IsSpinning", typeof(Boolean), ... );
public bool IsSpinning
{
get { return (bool)GetValue(IsSpinningProperty); }
set { SetValue(IsSpinningProperty, value); }
}
依赖属性元数据
在注册依赖属性时可以指定其元数据(PropertyMetadata)。
1、默认值
2、属性变更回调函数
3、强制转换回调函数
4、元数据是否可修改
5、是否在该属性上禁用动画
6、是否会影响布局系统的排列
7、是否会影响布局系统的测量
8、是否会影响父元素布局系统的排列
9、是否会影响父元素布局系统的测量
10、是否会影响该元素的重绘
11、默认情况下是否是双向绑定
12、获取或设置在应用具有该元数据的属性的绑定时要使用的 UpdateSourceTrigger的默认值,这些绑定的 UpdateSourceTrigger设置为 Default。
13、该元素是否可以由子元素继承
14、是否支持数据绑定
依赖属性用途
动态资源——Background="{DynamicResource MyBrush}"
数据绑定——Background="{Binding MyBrush}"
样式——<Setter Property="Background" Value="Red"/>
动画——<ColorAnimation Storyboard.TargetName="MyButton" Storyboard.TargetProperty="Background" From="Red" To="Blue"/>
元数据重写——通过依赖属性的OverrideMetadata来重写父类的属性默认行为
属性值继承——继承元素树父级的属性值(DataContext,FontSize)
WPF设计器集成——使用WPF设计器时,可以在属性窗口编辑属性值
依赖属性的优先级
首先分析下面代码
<Button Background="Red" Content="Click Me!">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="Green"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Blue" />
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
优先级:
1、来自依赖属性元数据的默认值
2、继承
3、默认(主题)样式
4、样式 Setter
5、模板触发器
6、样式触发器
7、隐式样式
8、TemplatedParent 模板属性
9、本地值
10、活动动画或具有 Hold 行为的动画
11、属性系统强制转换
依赖属性之附加属性
附加属性是一种特殊的依赖属性,它的一个用途是允许不同的子元素为实际在父元素中定义的属性指定唯一值
DependencyProperty.RegisterAttached
1、在父元素中定义及设计附加属性。之后,父元素循环遍历其子元素,获取值,并以某种方式应用这些值,如Grid.Row,DockPanel.Dock,Canvas.Top。
2、定义附加属性的类型将用作各种可能的父元素和内容模型的子元素,如ScrollViewer. HorizontalScrollBarVisibility。
3、定义附加属性的类型表示一个服务。其他类型为该附加属性设置值,之后,当在服务的上下文中计算设置该属性的元素时,将通过服务类的内部逻辑获取附加属性的值。
集合类型的依赖属性
代码分析:
public class Aquarium : DependencyObject
{
private static readonly DependencyPropertyKey AquariumContentsPropertyKey =
DependencyProperty.RegisterReadOnly(
"AquariumContents",
typeof(List<FrameworkElement>),
typeof(Aquarium),
new FrameworkPropertyMetadata(new List<FrameworkElement>())
);
public static readonly DependencyProperty AquariumContentsProperty =
AquariumContentsPropertyKey.DependencyProperty;
public List<FrameworkElement> AquariumContents
{
get { return (List<FrameworkElement>)GetValue(AquariumContentsProperty); }
}
}
var myAq1 = new Aquarium();
var myAq2 = new Aquarium();
var e1 = new Button();
var e2 = new Button();
myAq1.AquariumContents.Add(e1);
myAq2.AquariumContents.Add(e2);
MessageBox.Show("aq1 contains " + myAq1.AquariumContents.Count + " things");
MessageBox.Show("aq2 contains " + myAq2.AquariumContents.Count + " things");
public Aquarium()
{
SetValue(AquariumContentsPropertyKey, new List<FrameworkElement>());
}
来源:深圳筑星科技