WPF之依赖属性
简而言之,依赖属性就是一种可以自己没有值,并能通过使用Binding从数据源获得值(依赖在别人身上)的属性。而拥有依赖属性的对象被称为依赖对象。
与传统的CLR属性和面向对象思想相比依赖属性有很多新颖之处:
- 节省实例对内存的开销。因为属性值在其他对象那里,而不在使用依赖属性的对象这里,所以节省了内存开销。
- 属性值可以通过Binding依赖在其他对象上。
依赖属性对内存的使用方式
传统的.NET开发中,一个对象所占用的内存控件在调用new操作符进行实例化的时候就已经决定了,而WPF允许对象在被创建的时候并不包含用于储存数据的控件,只保留在需要时候能够获得默认值,借用其他对象数据或者分配空间的能力,这种对象就称为依赖对象,而它这种实时获取数据的能力则依靠依赖属性来实现,注意依赖对象不是数据产生的对象,而是具备获取其他对象的数据的能力的对象。
需要注意的是ItemSource所绑定的属性,必须同时具备{get;set;},如果不允许用户修改,则{get;private set},但必须同时具备,否则绑定的UI元素不会显示名称.
在WPF中,依赖对象的概念被DependencyObject
类所实现,依赖属性的概念被DependencyProperty
类所实现。DependencyObject具有GetValue和SetValue两个方法,DependencyProperty
必须以DependencyObject
为宿主,以这两个方法来进行写入与读取。
public class DependencyOobject:DispatcherObject{
public object GetValue(DependencyPropertyy dp)//从DependencyProperty对象获取数据
{
...///
}
public void SetValue(DependencyProperty dp,object value)
{
...///
}
}
DependencyObject
是WPF系统中相当底层的一个基类,所有UI控件都是依赖对象。
例子:
<StackPanel Background="LightBlue">
<TextBox x:Name="textBox1" BorderBrush="Black" Margin="5"/>
<TextBox x:Name="textBox2" BorderBrush="Black" Margin="5"/>
<Button x:Name="btn" Content="OK" Click="btn_Click"/>
</StackPanel>
public partial class MainWindow : Window
{
Student stu;
public MainWindow()
{
InitializeComponent();
stu = new Student();
Binding binding = new Binding("Text") { Source = this.textBox1 };
stu.SetBinding(Student.NameProperty, binding);
textBox2.SetBinding(TextBox.TextProperty, new Binding("Name") { Source = stu });
}
private void btn_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show(stu.Name);
}
}
public class Student : DependencyObject
{
//注册依赖属性
public static readonly DependencyProperty NameProperty =
DependencyProperty.Register("Name", typeof(string), typeof(Student));
//CLR包装属性
public string Name
{
get { return (string)GetValue(NameProperty); }
set { SetValue(NameProperty, value); }
}
//SetBinding包装
public BindingExpressionBase SetBinding(DependencyProperty dp,BindingBase binding)
{
return BindingOperations.SetBinding(this, dp, binding);
}
}
简单总结下创建依赖对象,使用依赖属性的三部曲:
-
继承
DependancyObject
类 -
在依赖对象内用
DependancyProperty.Register
方法注册依赖属性 -
用CLR属性进行包装,结合依赖对象的
SetValue
和GetValue
方法。
附加属性
附加属性将的是一个属性本来不属于某个对象,但由于某种需求而被后来附加上。也就是把对象放入一个特定的环境后哦,对象才具有的属性。
Demo:
<StackPanel Background="LightBlue">
<Button x:Name="btn" Content="OK" Click="btn_Click"/>
</StackPanel>
namespace MessagePump
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void btn_Click(object sender, RoutedEventArgs e)
{
Human human = new Human();
School.SetGrade(human, 6);
int grade = School.GetGrade(human);
MessageBox.Show(grade.ToString());
}
}
public class School : DependencyObject
{
//通过GetGrade、SetGrade,调用Human的SetValue和GetValue方法,存储依赖变量的值。
public static int GetGrade(DependencyObject obj)
{
return (int)obj.GetValue(GradeProperty);
}
public static void SetGrade(DependencyObject obj, int value)
{
obj.SetValue(GradeProperty, value);
}
// Using a DependencyProperty as the backing store for GradeProperty. This enables animation, styling, binding, etc...(注册依赖变量)
public static readonly DependencyProperty GradeProperty =
DependencyProperty.RegisterAttached("Grade", typeof(int), typeof(School), new PropertyMetadata(0));
}
class Human : DependencyObject
{
}
}