当前位置: 首页 > news >正文

明晰Silverlight中的依赖属性

转自:http://www.cnblogs.com/024hi/archive/2010/02/02/unleash_dependencyproperty_in_silverlight.html

 

在c#中--得益于c#3.0中的自动属性--我们可以十分轻松的通过如下代码创建一个叫做“AuthorName”的属性。

public string AuthorName { get; set; }

    上面的代码就是我们熟悉的CLR属性,我们可以很方便的读/取这个属性的值。不过在silverlight的世界中如果你想做更多更牛的事情,CLR属性就显得有些力不从心了。它们包括--动画、数据绑定、样式/模板等等。

    因此,微软在WPF中提出了依赖属性(Dependency Property,以下简称DP)的概念并将其延伸至Silverlight平台。在这篇文章我将介绍DP在Silverlight的定义和使用。

    要了解一件新事物最简单的方式就是找出一样我们熟悉的,与要介绍的新玩意相似的东西来做对比:将上文的AuthorName属性定义为DP的方式是如下这样的

public string AuthorName {
    get { return (string)GetValue(AuthorNameProperty); }
    set { SetValue(AuthorNameProperty, value); }
}
代码片段1
public static readonly DependencyProperty AuthorNameProperty = 
    DependencyProperty.Register("AuthorName", typeof(string), typeof(AuthorTextField), new PropertyMetadata(""));
代码片段2
 

哇!完成一个DP的定义需要这么多的代码,kidding me?

先别急,下面我们就来了解一下这些代码的含义。

首先,要构造一个DP,我们需要准备两样事

 

通过CLR属性包装

将DP用代码片段1中所示代码包装起来后,我们便可以轻松的像CLR属性一样设置和获取DP的值。因为这个包装用的就是标准的CLR声明方式,只是他的get和set中有一些简单的逻辑而已罢了。这里我们需要分别使用GetValue和SetValue方法获取或这是一个叫做AuthorNameProperty属性的值(没错,这是个DP。Silverlight中约定DP要以-Property词缀结尾)。

 

定义依赖属性(即本文中的AuthorNameProperty)

现在来看代码片段2,这里我们将其分成若干部分来解释:

public static readonly DependencyProperty AuthorNameProperty

代码片段3

先看看这部分,在定义DP时我们通常需要的返回类型是DependencyProperty(另外一种式附加属性AttachedProperty),而它的修饰符是public, static, 和 readonly

然后我们看接下来的部分:

DependencyProperty.Register("AuthorName",

  typeof(string),

  typeof(AuthorTextField),

new PropertyMetadata(""));

 

代码片段4
这段代码的作用是注册DP并为其添加一些标识,以便Silverlight可以使用它。

 

这样看来定义一个DP其实并不困难,通常我们只需按部就班的按照约定和格式完成定义而不需了解这背后可能令人头疼的具体细节--Silverlight的底层属性机制会确保这些DP在应用程序中的各尽其责。

现在,我们应该对DP的定义有了一个大体的了解。下面我们会将注册DP的代码部分(即代码片段4)进行详细剖析。

我们先来看一下Register()方法的定义

public static DependencyProperty Register(string name,

  Type propertyType,

  Type ownerType,

  PropertyMetadata typeMetadata);

 

代码片段5

Register()方法接受三个参数

  • name:故名思意,你要注册的DP的名称。这里建议你将其与你定义的DP名称保持一致(如例子中的AuthorName)。
  • propertyType:DP的类型,在本例中为string。
  • ownerType:DP所属类的类型,这将决定DP的作用域。在本例中我们假设它的作用域是一个叫做AuthorTextField的用户控件。
  • typeMetadata:通过PropertyMetadata类为该DP定义元数据。有很多silverlight开发者觉得这些元数据的定义没什么用,其实这种想法是错误的。元数据会对你在应用程序中使用DP产生很大的影响。比如我们可以通过元数据定义这个DP的默认值、定义当DP发生改变时引发的特定方法--抑或将这两样一齐定义,看一下PropertyMetadata的构造函数定义就知道了:
public class PropertyMetadata {public PropertyMetadata(object defaultValue);public PropertyMetadata(PropertyChangedCallback propertyChangedCallback);public PropertyMetadata(object defaultValue, PropertyChangedCallback propertyChangedCallback);public object DefaultValue { get; }
}

 

代码片段6

下面我们来做一个试验以便了解注册依赖属性时附加元数据的能力。

在没有默认值的情况下,我们在Expression Blend中观察这个AuthorName属性:

image 很明显,是空值。

接下来我们做如下定义

new





 PropertyMetadata("Sir Arthur Conan Doyle")

同样打开Expression Blend进行围观:

image 与我们通过PropertyMetadata构造函数构造的默认值相同。

由于在我们的例子中,AuthorName的类型是string,所以我们PropertyMetadata构造函数中的设置其默认值的类型也是string。而在上面我们已经知道,PropertyMetadata构造函数中接受的参数是object,所以在具体应用中我们应该根据实际情况决定传入的默认值(对象)。

 

另外一个可以指定给PropertyMetadata的参数对象是一个回调方法。这个方法将在DP的值发生变化时被调用。举个例子

new PropertyMetadata(new PropertyChangedCallback(AuthorNameChanged)

代码片段7

在上面的代码中,我们传入了一个类型为PropertyChangedCallback并命名为AuthorNameChanged的回调函数。然后,理所当然的,我们需要定义这个函数。

private static void AuthorNameChanged(DependencyObject d,

DependencyPropertyChangedEventArgs e) { // 一切皆有可能! 024hi.cnblogs.com 紫色永恒 }

代码片段8

由于我们定义的DP(以及注册DP的代码)是静态的,所以这里定义的事件(AuthorNameChanged)也必须是静态的。

这个回调方法需要传入两个参数。第一个参数是对具体DependendyObject的引用,第二个参数是特定委托的参数集DependencyPropertyChangedEventArgs。

有了静态修饰符及这两个参数,我们的AuthorNameChanged方法就定义完成了。每当AuthorName这个DP发生变化时,这个方法都会被调用。

 

最后,根据代码段6的定义,我们可以将定义默认值及回调函数的方式通过同一个构造函数传入。

DependencyProperty.Register("AuthorName",

  typeof(string),

  typeof(AuthorTextField),

  new PropertyMetadata("Sir Arthur Conan Doyle", new PropertyChangedCallback(AuthorNameChanged)));

Okay!Have fun~

相关文章:

  • rc.local自启动学习
  • Qt游戏编程_02
  • 超级终端使用简介
  • 粘包、丢包及TCP信息收发
  • 超前引用
  • Java中的volatile关键字-转载
  • jsp---EL存取器
  • 如何可以导入注册表文件时不提示?
  • 第八章异常和断言
  • VC++播放音频文件和音频数据的方法
  • ubuntu ftp服务器配置(转)
  • shell算数运算
  • 集线器、路由器、交换机、第三层交换技术
  • Slideshow ad
  • 13.6.1 新添加一个界面(Adding One Interface)
  • @angular/forms 源码解析之双向绑定
  • Github访问慢解决办法
  • HashMap ConcurrentHashMap
  • java B2B2C 源码多租户电子商城系统-Kafka基本使用介绍
  • JAVA SE 6 GC调优笔记
  • Java-详解HashMap
  • JS学习笔记——闭包
  • Swoft 源码剖析 - 代码自动更新机制
  • web标准化(下)
  • Web设计流程优化:网页效果图设计新思路
  • 从零开始的无人驾驶 1
  • 工作中总结前端开发流程--vue项目
  • 浏览器缓存机制分析
  • 七牛云假注销小指南
  • 如何合理的规划jvm性能调优
  • 如何用Ubuntu和Xen来设置Kubernetes?
  • 7行Python代码的人脸识别
  • CMake 入门1/5:基于阿里云 ECS搭建体验环境
  • 回归生活:清理微信公众号
  • ​软考-高级-系统架构设计师教程(清华第2版)【第9章 软件可靠性基础知识(P320~344)-思维导图】​
  • # Maven错误Error executing Maven
  • (1)(1.9) MSP (version 4.2)
  • (20050108)又读《平凡的世界》
  • (C语言)逆序输出字符串
  • (poj1.2.1)1970(筛选法模拟)
  • (接口封装)
  • (论文阅读笔记)Network planning with deep reinforcement learning
  • (十三)Java springcloud B2B2C o2o多用户商城 springcloud架构 - SSO单点登录之OAuth2.0 根据token获取用户信息(4)...
  • (原創) 如何安裝Linux版本的Quartus II? (SOC) (Quartus II) (Linux) (RedHat) (VirtualBox)
  • (状压dp)uva 10817 Headmaster's Headache
  • .\OBJ\test1.axf: Error: L6230W: Ignoring --entry command. Cannot find argumen 'Reset_Handler'
  • .h头文件 .lib动态链接库文件 .dll 动态链接库
  • .NET Core 版本不支持的问题
  • .NET Core 项目指定SDK版本
  • .net framwork4.6操作MySQL报错Character set ‘utf8mb3‘ is not supported 解决方法
  • .NET 药厂业务系统 CPU爆高分析
  • .NET 指南:抽象化实现的基类
  • .netcore 如何获取系统中所有session_如何把百度推广中获取的线索(基木鱼,电话,百度商桥等)同步到企业微信或者企业CRM等企业营销系统中...
  • .Net中的设计模式——Factory Method模式
  • /etc/motd and /etc/issue