WPF依赖属性设计如何节省内存消耗?

tee*_*nup 9 wpf dependency-properties

我在以下链接中读到了这个: -

http://www.informit.com/articles/article.aspx?p=688529&seqNum=2

但是,因为GetValue和SetValue在内部使用高效的稀疏存储系统,并且因为IsDefaultProperty是静态字段(而不是实例字段),所以依赖属性实现与典型的.NET属性相比可以节省每个实例的内存.如果WPF控件上的所有属性都是围绕实例字段的包装器(与大多数.NET属性一样),则由于每个实例附加的所有本地数据,它们将占用大量内存.

但最终它们会被存储在某个地方,它如何节省内存消耗?

Fre*_*lad 17

请参阅以下链接:http://www.bobpowell.net/dependencyproperty.aspx

对象声明为依赖属性的内容实际上只不过是一个标识符.这个静态"属性"实际上是一个将对象与特定存储标识符相关联的键.例如,图形对象具有可以显式设置或通过使用模板或样式设置的Background属性.

只要依赖属性使用其默认状态(这是非常常见的),它将不会占用任何额外的内存,因为将使用默认值.默认值不是每个实例存储的,它是根据Dependency Property存储的,它由元数据设置.

例如,请注意如何Brushes.Black设置为默认值

public static readonly DependencyProperty ForegroundProperty =
    DependencyProperty.Register(
        "Foreground",
        typeof(Brush),
        typeof(TextElement),
        new FrameworkPropertyMetadata(Brushes.Black, ...));
Run Code Online (Sandbox Code Playgroud)

可以这样想:假设您TextBlocks在Xaml中有四个

<StackPanel>
    <TextBlock .../>
    <TextBlock .../>
    <TextBlock .../>
    <TextBlock Foreground="Green" .../>
</StackPanel>
Run Code Online (Sandbox Code Playgroud)

尽管您从未明确将其设置为黑色,TextBlocks顶部的三个已Foreground设置为黑色.他们正在使用他们的默认值.因此,对于上述三个属性,您只需要一个字段(因为它是一个静态字段).ForegroundTextBlocks

对于第四个TextBlock,您已明确设置Foreground为绿色,因此该值作为Foreground此实例的本地值插入字典中,因此需要额外的内存(此外,它将最终位于下面列表中的第3位,覆盖Setters,Triggers等等).

另外,请参阅Josh Smith的以下文章,这是一个很好的解读:揭开依赖属性的神秘面纱

有一套明确定义的规则,WPF在内部使用这些规则来确定DP的实际价值.以下是解析DP值时使用的优​​先规则的简要概述(在此处详细了解):

  1. 财产制度强制
  2. 活动动画或具有保持行为的动画
  3. 本地价值
  4. TemplatedParent模板
  5. 风格触发器
  6. 模板触发器
  7. 风格二传手
  8. 主题风格
  9. 遗产
  10. 依赖项属性元数据的默认值

编辑:回答杜安的评论

如果将值显式设置为与默认值相同的值,它仍将存储为本地值.使用以下Xaml可以轻松验证这一点.

两者都TextBlocksForeground设置为黑色,但后者具有本地值集.由于样式设置器的优先级低于本地值,Style因此只能Foreground在第一个TextBlock而不是后一个设置.

<StackPanel>
    <StackPanel.Resources>
        <Style TargetType="TextBlock">
            <Setter Property="Foreground" Value="Green"/>
        </Style>
    </StackPanel.Resources>
    <TextBlock Text="Displays in Green"/>
    <TextBlock Foreground="Black" Text="Displays in Black"/>
</StackPanel>
Run Code Online (Sandbox Code Playgroud)


Rob*_*ney 5

首先,假设您创建了一个包含十几个属性的类.创造100,000个.你现在有多少个对象引用?1200000.

现在实现一个名为的类DependencyObject:

public class DependencyObject
{
    public DependencyObject()
    {
       LocalValues = new Dictionary<string, object>();
    }

    protected Dictionary<string, object> LocalValues { get; set; }

    public DependencyObject Parent { get; set; }

    protected object GetValue(string propertyName)
    {
       if (LocalValues.ContainsKey(propertyName))
       {
          return LocalValues[propertyName];
       }
       return Parent.GetValue(propertyName);
    }

    protected void SetValue(string propertyName, object value)
    {
       LocalValues[propertyName] = value;
    }
}
Run Code Online (Sandbox Code Playgroud)

像这样构建一个派生类:

public class MyDependencyObject : DependencyObject
{
    public SomeType Property1
    {
       get { return (SomeType)GetValue("Property1"); }
       set { SetValue("Property1", value]; }
    }

    // create 11 more properties like this
}
Run Code Online (Sandbox Code Playgroud)

现在创建100,000个实例MyDependencyObject并设置它们Parent.使用了多少个对象引用(不包括父对象)?300,000.

这就是属性值继承在依赖对象中的工作方式.