6.WPF属性

6.WPF属性

属性

依赖属性

依赖属性就是一种自己可以没有值,并能通过Binding从数据源获取值的属性。拥有依赖属性的对象被称为依赖对象。

传统开发中,一个对象占用的内存空间在使用new进行实例化的时候已经确定了,而WPF允许对象在创建的时候不包含用于存储数据的空间,而是拥有在需要用到数据的时候能够获取默认值、借用其他对象数据或实时分配空间的能力。这种对象叫做依赖对象,这种获取数据的能力叫做依赖属性。

依赖对象要由DependencyObject来实现,该类中具有GetValue和SetValue方法,这两个方法都是以DependencyProperty对象为参数。

1
2
public object GetValue(DependencyProperty dp);
public void SetValue(DependencyProperty dp, object value);

依赖属性的声明和使用

  • 依赖属性的使用
1
2
3
4
5
<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>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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的依赖属性
}
  • 依赖属性的包装器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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才会生效<TextBox Background="AliceBlue" Grid.Column="1" Grid.Row="1"/>

附加属性的声明和使用

附加属性的本质就是依赖属性,两者仅仅在包装器上有一些区别。

案例:人放在学校,才会有年级和班级,说明年级和班级是附加属性,宿主是学校。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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));
}
1
public class Human:DependencyObject{}

增加一个button按钮,然后添加点击事件

1
2
3
4
5
6
7
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依赖在其他对象上。

<TextBox Grid.Column="1" Grid.Row="1"/>所对应的C#代码是

1
2
3
TextBox txt = new TextBox();
Grid.SetColumn(txt,1);
Grid.setRow(txt,1);

案例:

1
2
3
4
5
<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>

作者

步步为营

发布于

2024-05-08

更新于

2025-03-15

许可协议