惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

L
LINUX DO - 最新话题
T
Tor Project blog
G
GRAHAM CLULEY
S
Security Affairs
P
Palo Alto Networks Blog
TaoSecurity Blog
TaoSecurity Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
aimingoo的专栏
aimingoo的专栏
博客园_首页
C
CXSECURITY Database RSS Feed - CXSecurity.com
博客园 - 三生石上(FineUI控件)
Cloudbric
Cloudbric
Cyberwarzone
Cyberwarzone
A
About on SuperTechFans
Microsoft Azure Blog
Microsoft Azure Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
C
CERT Recently Published Vulnerability Notes
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
C
Check Point Blog
宝玉的分享
宝玉的分享
Forbes - Security
Forbes - Security
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Microsoft Security Blog
Microsoft Security Blog
Schneier on Security
Schneier on Security
The Last Watchdog
The Last Watchdog
T
The Blog of Author Tim Ferriss
S
SegmentFault 最新的问题
H
Heimdal Security Blog
Recorded Future
Recorded Future
L
LangChain Blog
WordPress大学
WordPress大学
Know Your Adversary
Know Your Adversary
C
Cyber Attacks, Cyber Crime and Cyber Security
V
Visual Studio Blog
B
Blog
H
Help Net Security
T
Tailwind CSS Blog
The Hacker News
The Hacker News
雷峰网
雷峰网
P
Proofpoint News Feed
博客园 - Franky
Attack and Defense Labs
Attack and Defense Labs
有赞技术团队
有赞技术团队
S
Schneier on Security
T
Troy Hunt's Blog
云风的 BLOG
云风的 BLOG
Hacker News - Newest:
Hacker News - Newest: "LLM"
Blog — PlanetScale
Blog — PlanetScale
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
P
Proofpoint News Feed

博客园 - 雪影

C#异步提示和技巧 关于System.Windows.Forms.DateTimePicker的一个Bug 关于frameset中指定区域回退的实现 如何编写出拥抱变化的代码? WCF RIA Services Domain Serive的生命周期和数据交互 [译]WCF RIA Services中的集合(2) [译]WCF RIA Services中的集合(1) windows8应用安装挂起的一个原因 WPF 详解模板 Silverlight --- Behavior技术(四) Silverlight --- Behavior技术(三) Silverlight --- Behavior技术(二) Silverlight --- Behavior技术(一) Silverlight的依赖属性与附加属性(六) Silverlight的依赖属性与附加属性(五) Silverlight的依赖属性与附加属性(三) Silverlight的依赖属性与附加属性(二) Silverlight的依赖属性与附加属性(一) 从数据库读取图片,并固定显示
Silverlight的依赖属性与附加属性(四)
雪影 · 2012-10-10 · via 博客园 - 雪影

接上篇,上篇我们真正接触到了依赖属性的用法,以及依赖属性的属性元数据的用法,并且也实实在在地解决了之前第二篇提到的一系列问题.来回顾一下

  1. 属性默认值
  2. 属性变更通知
  3. 属性强制回调

本篇将继续讨论上一篇提到的问题,主题依然是属性元数据.

内容概要

  1. 属性值验证
  2. 默认值问题
  3. 依赖属性的不变与可变
  4. 属性元数据的唯一性
  5. 重写属性元数据
  6. 改写属性元数据

一.属性值验证

依赖属性具备属性验证的功能,其也会对依赖属性默认值进行验证,在DependencyProperty的Register方法中最后一个参数为ValidateValueCallback,用于属性值验证,如下代码

public static readonly DependencyProperty AgeProperty =
    DependencyProperty.Register("Age", typeof(int), typeof(DPCustomPeople),
    new PropertyMetadata(1), new ValidateValueCallback(AgeValidateValueCallback));

public virtual int Age
{
    get { return (int)GetValue(AgeProperty); }
    set { SetValue(AgeProperty, value); }
}

public static bool AgeValidateValueCallback(object value)
{
    int age=(int)value;
    if (age < 1) return false;
    return true;
}

ValidateValueCallback有一个传入的参数(即依赖属性值)和一个返回值(表示属性值是否是正确的).

注意:
1.当返回值为false的时候,将会抛出异常
2.不要试图在该回调方法中校正传入的值类型(即使引用类型也不符合逻辑),其主要职责在于验证.

此功能用的不是很频繁,因为返回false会抛异常,还要额外处理.再说强制回调方法也可以处理.

二.默认值问题

上一篇有讲到依赖属性的默认值问题

在构造函数里给属性赋值并不能解决问题(这是依赖属性默认值带来的额外问题,因为其是静态属性)

类继承带来的默认值重写问题,看以下代

public class RootClass
{
    public RootClass()
    {
        this.Name = "RootClass";
    }
    public string Name { get; set; }
}

public class SubClass : RootClass
{
    public SubClass()
    {
        this.Name = "SubClass";
    }
}

上面代码应该没问题,但如果这样就有问题了

public class RootClass
{
    public RootClass()
    {
        Name = "RootClass";
    }
    public static string Name { get; set; }
}

public class SubClass : RootClass
{
    public SubClass()
    {
        Name = "SubClass";
    }
}

如果是静态属性的话,子类一旦改写就会改变父类,破坏内部逻辑

那么就需要保证属性在每个类默认值的唯一性.

三.依赖属性的不变与可变

上篇有提到过这样一句话

(依赖属性)属性名字,属性类型,属性所有者类型一经注册将无法更改

这便不可变的地方,即使在子类重写也不行.
但依赖属性的默认值是可以修改的,修改的前提是保证父类的属性默认值不被影响,上篇我们有提出疑问,给默认值为什么需要属性元数据(PropertyMetadata),以下的代码也应该走的通

    public static readonly DependencyProperty NameProperty =
DependencyProperty.Register("Name", typeof(string), typeof(DPCustomPeople),
string.Empty);

是的,若依赖属性内部有一个列表维护默认值,也保证了在不同类型中默认值不会发生错误.这样的代码是没问题的,但不要忘了,还有属性变更通知和属性强制回调.PropertyMetadata把依赖属性可变的行为全部抽取出来了,我想这样做的原因可以保持依赖属性功能的清晰程度(个人猜想,但确实有这样的效果).那么就意味着我们可以重写属性元数据.

四.属性元数据的唯一性

DependencyProperty提供了OverrideMetadata方法重写属性元数据,但一个依赖属性在同一个类中不允许重写,即在同一类型中,保证属性元数据在依赖属性中的唯一性,如下代码是错误的

public class DPCategory : DependencyObject
{
    public static readonly DependencyProperty NameProperty =
           DependencyProperty.Register("Name", typeof(string), typeof(DPCategory),
           new PropertyMetadata(string.Empty));

    public void TestOverrideMetadata()
    {
        //wrong
        NameProperty.OverrideMetadata(typeof(DPCategory), new PropertyMetadata("WPF"));
    }
}

将会抛出异常

image

五.重写属性元数据

继承的子类允许重写属性元数据,如下代码

public class DPWPFCategory : DPCategory
{
    public void TestOverrideMetadata()
    {
        NameProperty.OverrideMetadata(typeof(DPWPFCategory), new PropertyMetadata("WPF"));
        Console.WriteLine(NameProperty.GetMetadata(typeof(DPWPFCategory)).DefaultValue);
        //output 30
    }
}

注意:在重写属性元数据时,应该要知道一下规则.
1.重写元数据是一个以重写元数据为主的合并的过程,即子类的重写后的元数据会与父类的进行合并

我们在父类定义一个Group的依赖属性

public string Group
{
    get { return (string)GetValue(GroupProperty); }
    set { SetValue(GroupProperty, value); }
}
public static readonly DependencyProperty GroupProperty =
    DependencyProperty.Register("Group", typeof(string), typeof(DPCategory), 
    new PropertyMetadata(string.Empty,new PropertyChangedCallback(GroupPropertyChangedCallback)));

public static void GroupPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    Console.WriteLine(e.NewValue);
}

然后在子类重写此依赖属性的元数据

public void TestOverrideMergeMetadata()
{
    GroupProperty.OverrideMetadata(typeof(DPWPFCategory), new PropertyMetadata("Computer Technology"));
    Console.WriteLine(this.Group);
    this.Group = "Technology";
}

输出结果,当属性值发生变化时,父类的属性变更通知回调方法就会触发

image

2.实例匹配(Type.IsAssignableFrom 返回为true)

注意:要重写的父类属性元数据类型必须要是重写的属性元数据的父类或者与之类型相同.如下为属性元数据的继承关系

image

可以看出如果用FrameworkPropertyMetadata来重写的话是最保险的

如下示例

public int Order
{
    get { return (int)GetValue(OrderProperty); }
    set { SetValue(OrderProperty, value); }
}

public static readonly DependencyProperty OrderProperty =
    DependencyProperty.Register("Order", typeof(int), typeof(DPCategory), new UIPropertyMetadata(0));
//UIPropertyMetadata

注意父类的属性元数据为UIPropertyMetadata,以下子类重写的属性元数据类型为PropertyMetadata 即会报错.

public void TestOverrideDriveMetadata()
{
    OrderProperty.OverrideMetadata(typeof(DPWPFCategory), new PropertyMetadata(1));
    //wrong
    //must >=UIPropertyMetadata
}

输出

image

六.改写属性元数据

改写与重写有几点不同.

  1. 改写是将已存在的依赖属性添加到不同类型当中
  2. 改写不是一个合并属性元数据的过程,改写后的是全新的

如下:
为一个全新的类型添加已有依赖属性,并重写属性元数据,重写后将不会触发DPCategory类型的GroupProperty属性变更通知,不会影响原依赖属性逻辑

public class DPGroup:DependencyObject
{
    public static readonly DependencyProperty GroupProperty =
    DPCategory.GroupProperty.AddOwner(typeof(DPGroup),
    new PropertyMetadata("Technology"));
    public string Group
    {
        get { return (string)GetValue(GroupProperty); }
        set { SetValue(GroupProperty, value); }
    }

    public void TestAddOwnerMetadata()
    {
        Console.WriteLine(Group);
        this.Group = "Computer Technology";
    }
}

注意:如果在子类进行此操作,将与重写效果一样

本篇主要讲到了属性元数据的一些特点及注意点.FrameworkPropertyMetadata还有许多特性,但必须有实际场景结合.所以这里无法展开.讲了这么多貌似都没触及到WPF什么事,这部分也是比较枯燥,但却非常重要.下篇继续,然后依赖属性就告一段落.

原文地址:

http://www.cnblogs.com/Clingingboy/archive/2010/02/02/1661842.html