1.为什么会出现依赖属性?
先回想一下传统的属性(Property):通常我们读取或赋值一个属性时,实际上是在对属性背后的某个私有成员进行读写。那么随着对象的属性越来越多,再加上从对象派生出去的子对象,子对象再生出“孙子”对象......最终的对象运行实例中会有大量的私有成员,而每私有成员都要分配内存,占用一定的资源。
但反过来想想,通常我们在使用一个控件/对象时,往往只用到了某几个属性,大部分属性(有时候甚至达到90%以上)都是采用的默认值(或者也可以理解为没有用到),这对于WPF/SL来说无疑是一种极大的性能损耗。
所以在此背景之下,DP(Dependency Properties的简称)就出现了,我们再回想一下静态(static)方法或成员,静态成员/方法的调用不依赖于实例,它是class级别的,不管这个类有多少个实例,静态成员在内存中只占一份,这正是我们所要的!
2.依赖属性的大致原理及好处
所有具备依赖属性的对象,都是继承自DependencyObject,DependencyObject中有一个"字典"存储区用来存放依赖属性,而且都是用static方式读取的,所以你现在应该想明白了:为啥不能直接用txt.Left = xxx来直接赋值,而必须用txt.SetValue(Canvas.Left,xxx)来处理,因为static成员是实例无法调用的。
DP的优点:
(1)有效降低内存消耗。
3.依赖属性值的读取策略
这张图描述了GetValue与SetValue的内部读取策略.
4.依赖属性的使用示例:
(1)先建一个Silverlight User Control,取名为MyControl
xaml部分:
xaml部分:
代码
<
UserControl
x:Class
="DPStudy.MyControl"
xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml"
>
< Border CornerRadius ="5" BorderThickness ="3" BorderBrush ="#FFEF410D" Width ="300" Height ="40" Margin ="5" >
< TextBlock x:Name ="txt" Text ="" VerticalAlignment ="Center" HorizontalAlignment ="Center" ></ TextBlock >
</ Border >
</ UserControl >
xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml"
>
< Border CornerRadius ="5" BorderThickness ="3" BorderBrush ="#FFEF410D" Width ="300" Height ="40" Margin ="5" >
< TextBlock x:Name ="txt" Text ="" VerticalAlignment ="Center" HorizontalAlignment ="Center" ></ TextBlock >
</ Border >
</ UserControl >
CS部分:(技巧:vs2008中,只要键入propdp,再连敲二次Tab键,vs就会自动添加一个依赖属性的代码模板)
代码
using
System.Windows;
using System.Windows.Controls;
namespace DPStudy
{
public partial class MyControl : UserControl
{
public static readonly DependencyProperty MessageProperty = DependencyProperty.Register( " Message " , typeof ( string ), typeof (MyControl), new PropertyMetadata( " Message的默认值 " , new PropertyChangedCallback(OnMessagePropertyChanged)));
public string Message
{
get { return ( string ) GetValue (MessageProperty); }
set { SetValue (MessageProperty, value); }
}
/// <summary>
/// Message变化时的通知处理
/// </summary>
/// <param name="d"></param>
/// <param name="e"></param>
private static void OnMessagePropertyChanged (DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MyControl ctl = d as MyControl;
ctl.txt.Text = d.GetValue(MyControl.MessageProperty).ToString();
}
public MyControl()
{
InitializeComponent();
this .Loaded += new RoutedEventHandler(MyControl_Loaded);
}
void MyControl_Loaded( object sender, RoutedEventArgs e)
{
this .txt.Text = Message; // 初始加载时,显示Message的初始值
}
}
}
using System.Windows.Controls;
namespace DPStudy
{
public partial class MyControl : UserControl
{
public static readonly DependencyProperty MessageProperty = DependencyProperty.Register( " Message " , typeof ( string ), typeof (MyControl), new PropertyMetadata( " Message的默认值 " , new PropertyChangedCallback(OnMessagePropertyChanged)));
public string Message
{
get { return ( string ) GetValue (MessageProperty); }
set { SetValue (MessageProperty, value); }
}
/// <summary>
/// Message变化时的通知处理
/// </summary>
/// <param name="d"></param>
/// <param name="e"></param>
private static void OnMessagePropertyChanged (DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MyControl ctl = d as MyControl;
ctl.txt.Text = d.GetValue(MyControl.MessageProperty).ToString();
}
public MyControl()
{
InitializeComponent();
this .Loaded += new RoutedEventHandler(MyControl_Loaded);
}
void MyControl_Loaded( object sender, RoutedEventArgs e)
{
this .txt.Text = Message; // 初始加载时,显示Message的初始值
}
}
}
这里我们定义了一个Message的string类型依赖属性,和普通属性的区别是:必须使用DependencyProperty.Register来注册该属性,而且“属性命名”要以Property为后缀;另外在读取时,必须调用SetValue/GetValue静态方法来读取其值,最后我们还可以添加一个"属性值变化时的"回调处理。
(2)将MyControl放到MainPage.xaml中小试牛刀
MainPage.Xaml内容如下:
代码
<
UserControl
x:Class
="DPStudy.MainPage"
xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d ="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc ="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:l ="clr-namespace:DPStudy"
mc:Ignorable ="d" d:DesignWidth ="640" d:DesignHeight ="480" >
< StackPanel x:Name ="LayoutRoot" >
< l:MyControl x:Name ="myctl" ></ l:MyControl >
< Button Click ="Button_Click" Content ="改变Message属性值" Width ="130" ></ Button >
</ StackPanel >
</ UserControl >
xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d ="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc ="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:l ="clr-namespace:DPStudy"
mc:Ignorable ="d" d:DesignWidth ="640" d:DesignHeight ="480" >
< StackPanel x:Name ="LayoutRoot" >
< l:MyControl x:Name ="myctl" ></ l:MyControl >
< Button Click ="Button_Click" Content ="改变Message属性值" Width ="130" ></ Button >
</ StackPanel >
</ UserControl >
MainPage.Xaml.cs内容如下:
运行后,点击按钮将改变MyControl控件的Message属性值,同时MyControl中的文本控件的文字也将变成"新值"
转载请注明来自菩提树下的杨过
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。