依赖属性就是一种自己可以没有值,并能通过Binding从数据源获取值的属性。拥有依赖属性的对象被称为依赖对象。
传统开发中,一个对象占用的内存空间在使用new进行实例化的时候已经确定了,而WPF允许对象在创建的时候不包含用于存储数据的空间,而是拥有在需要用到数据的时候能够获取默认值、借用其他对象数据或实时分配空间的能力。这种对象叫做依赖对象,这种获取数据的能力叫做依赖属性。
依赖对象要由DependencyObject
来实现,该类中具有GetValue和SetValue方法,这两个方法都是以DependencyProperty
对象为参数。
public object GetValue(DependencyProperty dp);
public void SetValue(DependencyProperty dp, object value);
<StackPanel>
<TextBox x:Name="txt1" Margin="5"/>
<TextBox x:Name="txt2" Margin="5"/>
<Button x:Name="btn" Content="OK" Margin="5" Click="Btn_Click"/>
StackPanel>
public class Student : DependencyObject
{
//参数1:指明以哪个属性作为依赖属性的包装器,此处使用Name属性作为依赖属性的包装器
//参数2:指明依赖属性存储什么类型的值
//参数3:指明宿主类型,这将依赖属性和依赖对象关联到了一起
public static readonly DependencyProperty NameProperty = DependencyProperty.Register("Name", typeof(string), typeof(Student));
}
private void Btn_Click(object sender, RoutedEventArgs e)
{
Student su = new Student();
su.SetValue(Student.NameProperty, this.txt1.Text);//将su的依赖属性绑定到txt1.Text上
txt2.Text = (string)su.GetValue(Student.NameProperty);//获得su的依赖属性
}
public class Student : DependencyObject
{
//参数1:指明以哪个属性作为依赖属性的包装器,此处使用Name属性作为依赖属性的包装器
//参数2:指明依赖属性存储什么类型的值
//参数3:指明宿主类型,这将依赖属性和依赖对象关联到了一起
public static readonly DependencyProperty NameProperty = DependencyProperty.Register("Name", typeof(string), typeof(Student));
//Name属性 作为NameProperty依赖属性的包装器,没有该包装器依赖属性仍能正常工作
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);
}
}
//实现了上面的包装,就可以这样写
private void Btn_Click(object sender, RoutedEventArgs e)
{
Student su = new Student();
su.SetBinding(Student.NameProperty, new Binding("Text") { Source = txt1 });
txt2.SetBinding(TextBox.TextProperty, new Binding("Name") { Source = su });//Name是包装器
}
尽管上面的Student类没有实现INotifyPropertyChanged接口,但是属性值发生改变时与之关联的Binding对象依然可以得到通知,依赖属性默认带有这样的功能。
可以使用propdp在vs中快速定义依赖属性代码段
附加属性就是一个属性本来不属于某个对象,但是把这个对象放到特定环境后(宿主)会新增这个属性。
比如TextBox只有放在Grid里面,Grid.Column才会生效
附加属性的本质就是依赖属性,两者仅仅在包装器上有一些区别。
案例:人放在学校,才会有年级和班级,说明年级和班级是附加属性,宿主是学校。
public class School : DependencyObject
{
//和依赖属性的不同点1:不再使用一个属性,而是将属性拆分成两个静态方法
public static int GetGrade(DependencyObject obj)
{
return (int)obj.GetValue(GradeProperty);
}
public static void SetGrade(DependencyObject obj, int value)
{
obj.SetValue(GradeProperty, value);
}
//和依赖属性的不同点2:使用RegisterAttached进行注册,但是用法完全相同
public static readonly DependencyProperty GradeProperty =
DependencyProperty.RegisterAttached("Grade", typeof(int), typeof(School), new PropertyMetadata(0));
}
public class Human:DependencyObject{}
增加一个button按钮,然后添加点击事件
private void Button_Click(object sender, RoutedEventArgs e)
{
Human human = new Human();
School.SetGrade(human, 6);
int grade = School.GetGrade(human);
MessageBox.Show(grade.ToString());
}
附加属性的本质就是依赖属性,所以附加属性也可以使用Binding依赖在其他对象上。
所对应的C#代码是
TextBox txt = new TextBox();
Grid.SetColumn(txt,1);
Grid.setRow(txt,1);
案例:
<Canvas>
<Slider x:Name="sldX" Width="260" Minimum="50" Maximum="200" Canvas.Left="15" Canvas.Top="10"/>
<Slider x:Name="sldY" Width="260" Minimum="50" Maximum="200" Canvas.Left="15" Canvas.Top="40"/>
<Rectangle x:Name="Rect" Fill="Black" Width="30" Height="30" Canvas.Left="{Binding ElementName=sldX,Path=Value}" Canvas.Top="{Binding ElementName=sldY,Path=Value}"/>
Canvas>