开发工具与关键技术:Visual Studio 2017
作者:邓崇富
撰写时间:2019 年 6 月 4 日
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
依赖属性(Dependency Property):
在WPF中,依赖属性就是一种可以自己没有值,并能通过使用Binding从数据源获得值(依赖在别人身上)的属性。拥有依赖属性的对象被称为“依赖对象”。与传统的CLR属性和面向对象思想相比依赖属性有很多新颖之外,其中包括:
- 节省实例对内存的开销。
- 属性值可以通过Binding依赖在其他对象上。
依赖属性对内存的使用方式:
在传统的.NET开发中,一个对象所占用的内存空间在调用new操作符进行实例化的时候就已经决定了,而WPF允许对象在被创建的时候并不包含用于存储数据的空间(即字段所占用的空间)、只保留在需要用到数据时能够获得默认值、借用其他对象数据或实时分配空间的能力,这种对象就称为依赖对象(Dependency Object)而它这种实时或取数据的能力则依靠依赖属性(Dependency Property)来实现。WPF开发中,必须使用依赖对象作为依赖属性的宿主,使二者结合起来,才能形成完整的Binding目标被数据所驱动。
在WPF系统中,依赖对象的概念被DependencyObject类所实现,依赖属性的概念则由DependencyProperty类所实现。DependencyObject具有GetValue和SetValue两个方法:
using System.Windows;
using System.Windows.Threading;
namespace WPF练习
{
public class DependencyObject:DispatcherObject
{
public object GetValue(DependencyProperty db)
{
//.....
return null;
}
public void SetValue(DependencyProperty db,object value)
{
//...
}
}
}
这两个方法都以DependencyProperty对象为参数,GetValue方法通过DependencyProperty对象获取数据;SetValue通过DependencyProperty对象存储值,正是这两个方法把DependencyObject和DependencyProperty紧密结合在一起。
DependencyObject是WPF系统中相当底层的一个基类,如下图:
从上面的图中可以看出,WPF的所有UI控件都是依赖对象。WPF的类库在设计时充分利用了依赖属性的优势,UI控件的绝大数属性都已经依赖化了。
声明和使用依赖属性:
下面使用一个简单的实例来说明依赖属性的使用方法,先准备好一个界面,XAML代码如下:
<Window x:Class="WPF练习.Window12"
<!--此处省略了引用的命名空间-->
Title="Window12" Height="165" Width="260">
<StackPanel>
<TextBox x:Name="textBox1" BorderBrush="Black" Width="Auto" Height="25" Margin="10,20,10,5"/>
<TextBox x:Name="textBox2" BorderBrush="Black" Width="Auto" Height="25" Margin="10"/>
<Button Content="OK" Margin="10" Click="Button_Click"/>
</StackPanel>
</Window>
前面说过,DependencyProperty必须以DependencyObject为宿主、借助它的SetValue和GetValue方法进行写入与读取。因此,想使用·自定义的DependencyObject,宿主一定是DependencyObject的派生类。DependencyProperty实例的声明特点很鲜明——引用变量由public static readonly三个修饰符修饰,实例并非使用new操作得到而是使用DependencyProperty.Register方法生成,类的代码如下:
using System.Windows;
namespace WPF练习
{
public class Student: DependencyObject
{
public static readonly DependencyProperty NameProperty =
DependencyProperty.Register("Name", typeof(string), typeof(Student));
}
}
UI界面中OK按钮的Click事件处理器代码如下:
namespace WPF练习
{
/// <summary>
/// Window12.xaml 的交互逻辑
/// </summary>
public partial class Window12 : Window
{
public Window12()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Student stu = new Student();
stu.SetValue(Student.NameProperty, this.textBox1.Text);
textBox2.Text = (string)stu.GetValue(Student.NameProperty);
}
}
}
程序运行后,在两个输入框内输入内容,单击OK按钮,输入框2内容会被清空。
效果如下:
附加属性(Attached Properties)
附加属性就是一个属性本来不属于某个对象,但由于某种需求而被后来附加上。也就是把对象放入一个特定环境后对象才具有的属性(表现出来就是被环境赋予的属性)就称为附加属性(Attached Propertise)。
附加属性的本质是依赖属性——附加属性也可以使用Binding依赖在其他对象的数据上。下面的例子是用Canvas布局的窗体,两个Slider用来控制矩形在Canvas中的横纵坐标。
界面的XAML代码如下:
<Window x:Class="WPF练习.Window13"
<!--此处省略了引用的命名空间-->
Title="Window13" Height="Auto" Width="Auto">
<Canvas>
<Slider x:Name="sliderX" Canvas.Top="10" Canvas.Left="10" Width="260" Minimum="50" Maximum="200"/>
<Slider x:Name="sliderY" Canvas.Top="40" Canvas.Left="10" Width="260" Minimum="50" Maximum="200"/>
<Rectangle x:Name="rect" Fill="Blue" Width="30" Height="30"
Canvas.Left="{Binding ElementName=sliderX,Path=Value}"
Canvas.Top="{Binding ElementName=sliderY,Path=Value}"/>
</Canvas>
</Window>
程序运行后。第一条滑动条向右移动,矩形就会向右移动;第二条滑动条向右移动,矩形就会向下移动;效果图如下: