代码改变世界

Freezable 对象(WPF)

2010-07-14 16:17  Clingingboy  阅读(3727)  评论(3编辑  收藏  举报

 

先看下图
image

Freezable继承自DependencyObject,同时添加了Freezable方法,用于冻结对象.

一.冻结对象

以此为示例

public class People : Freezable
{
    public string Name
    {
        get { return (string)GetValue(NameProperty); }
        set { SetValue(NameProperty, value); }
    }

    public static readonly DependencyProperty NameProperty =
        DependencyProperty.Register("Name", typeof(string), typeof(People), 
        new UIPropertyMetadata());


    protected override Freezable CreateInstanceCore()
    {
        throw new NotImplementedException();
    }
}

现实生活中,人的名字是不可以随意修改的,作为对象,当名字定下来以后,就把该对象冻结了.那么就不能再修改此对象的属性了,如下
People entity = new People();
entity.Name = "Terry";
entity.Freeze();
//error
entity.Name = "Curry";
在调用Freeze方法后,再次修改Name 会报错

 

二.依赖对象与冻结

当调用Freeze方法后,DependencyObject将成为一个密封类(Saled),一旦DependencyObject成为密封类,那么内部将无法修改依赖属性,
这也意味着如果定义普通的CLR属性则没有这个问题,在People中添加一个Age属性(人的年龄总是递增的),下面的代码没有问题

People entity = new People();
entity.Name = "Terry";
entity.Freeze(); entity.Age = 1;
因为Age 并非依赖属性.

三.冻结状态

(1)在冻结之前,需要知道该对象是否已经冻结(IsFrozen),当冻结之后IsFrozen为True
(2)即使继承了Freezable的对象,并非随时都可以冻结,在调用Freeze方法前,需要查看CanFrozen属性判断对象是否可以冻结(如果该对象可以冻结,即使调用Freeze方法后,该属性还是为True),否则会抛错
(3)冻结后的对象无法解冻,必须采用克隆方法创建一个新的对象.

四.无法冻结的情况

1.绑定时.
当一个dp对象其中有dp有绑定时,无法冻结;当dp解除绑定后则可以(如果进行了绑定就意味着值可能会修改,那么该对象就不是冻结的了)

People entity = new People();
BindingOperations.SetBinding(entity, People.NameProperty, new Binding("Name") { Source = entity });
//first not freeze
if (entity.CanFreeze)
    entity.Freeze();
entity.Name = "Terry"; 
//freeze
if (entity.CanFreeze)
    entity.Freeze();

2.Freezable中定义的dp属性类型必须为值类型或者是Freezable类型
比如在其中定义一个Button类型(非Freezable类型)的dp,当其有值时,则无法冻结

五.Freezable特性


1.可子属性变更通知
现在给People添加一个Skin属性

public class People : Freezable
{
    public string Name
    {
        get { return (string)GetValue(NameProperty); }
        set { SetValue(NameProperty, value); }
    }

    public static readonly DependencyProperty NameProperty =
        DependencyProperty.Register("Name", typeof(string), typeof(People), 
        new UIPropertyMetadata());

    public int Age { get; set; }

    public SolidColorBrush Skin
    {
        get { return (SolidColorBrush)GetValue(SkinProperty); }
        set { SetValue(SkinProperty, value); }
    }

    public static readonly DependencyProperty SkinProperty =
        DependencyProperty.Register("Skin", typeof(SolidColorBrush), typeof(People), new UIPropertyMetadata(null));

    
    protected override Freezable CreateInstanceCore()
    {
        throw new NotImplementedException();
    }
}

测试以下代码,将触发两次事件
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
    People entity = new People();
    SolidColorBrush brush = new SolidColorBrush();
    entity.Changed += new EventHandler(brush_Changed);
    //execute event
    entity.Skin = brush;
    //execute event
    brush.Color = Colors.Red;
}

void brush_Changed(object sender, EventArgs e)
{

}
2.克隆
如果定义的属性均为依赖属性
,那么克隆就会变的很简单,调用父类方法就行,如
public SolidColorBrush Clone()
{
    return (SolidColorBrush) base.Clone();
}
3.冻结之后的对象将与UI线程分离
其会将内部的Dispatcher属性设置为空,这是需要注意的.
总结:当对象不需要发生改变时,则冻结该对象,减少对象监听,提升性能