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

发布于 2024-11-30 18:48:08 字数 454 浏览 1 评论 0原文

我在以下链接中阅读了此内容:-

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

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

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

I read this in the following link:-

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

However, because GetValue and SetValue internally use an efficient sparse storage system and because IsDefaultProperty is a static field (rather than an instance field), the dependency property implementation saves per-instance memory compared to a typical .NET property. If all the properties on WPF controls were wrappers around instance fields (as most .NET properties are), they would consume a significant amount of memory because of all the local data attached to each instance.

But eventually they are getting stored somewhere, how does it saves memory consumption ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

痴情换悲伤 2024-12-07 18:48:08

请参阅以下链接:依赖属性

对象声明为依赖属性的实际上是
无非是一个标识符。这个静态“属性”实际上是一个
将对象与特定存储标识符关联起来的键。为了
示例图形对象有一个可以设置的背景属性
明确地或通过使用模板或样式..

只要依赖属性使用其默认状态(这很常见),它就不会占用任何额外的内存,因为将使用默认值。默认值不是按实例存储的,而是按依赖项属性存储的,并由元数据设置。

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

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

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

<StackPanel>
    <TextBlock .../>
    <TextBlock .../>
    <TextBlock .../>
    <TextBlock Foreground="Green" .../>
</StackPanel>

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

不过,对于第四个 TextBlock,您已将 Foreground 显式设置为绿色,以便该值作为 Foreground 的本地值插入到字典中这个实例因此需要额外的内存(而且,它最终会出现在下面列表中的第 3 个位置,覆盖 SettersTriggers 等)

另外,请参阅 Josh Smith 的以下帖子,这是一本很好的读物: 揭秘依赖属性

WPF 内部使用一组明确定义的规则
弄清楚DP的真正价值是什么。这是一个简短的总结
解析 DP 值时使用的优​​先级规则(读
有关更多信息此处):

  1. 属性系统强制
  2. 活动动画或具有保持行为的动画
  3. 本地价值
  4. TemplatedParent 模板
  5. 样式触发器
  6. 模板触发器
  7. 样式设置器
  8. 主题风格
  9. 继承
  10. 依赖属性元数据的默认值

编辑: 回答以下评论Duane

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

两个 TextBlocks 都将 Foreground 设置为 Black,但后者设置了本地值。 Style 只能在第一个 TextBlock 上设置 Foreground,而不能在后面设置 Foreground,因为样式设置器的优先级低于本地值。

<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>

See the following link: Dependency Properties.

What is declared by an object as a dependency property is in fact
nothing more than an identifier. This static "property" is really a
key which associates an object with a specific storage identifier. For
example graphical objects have a Background property that can be set
explicitly or through the use of templates or styles..

As long as a Dependency Property uses its default state (which is very common), it won't take up any additional memory since the default value will be used. The default value isn't stored per instance, it is stored per Dependency Property and it's set by metadata.

Example, notice how Brushes.Black is set as the default value

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

Think of it this way: Say you have four TextBlocks in Xaml

<StackPanel>
    <TextBlock .../>
    <TextBlock .../>
    <TextBlock .../>
    <TextBlock Foreground="Green" .../>
</StackPanel>

The three TextBlocks at the top have Foreground set to Black although you have never explicitly set it to Black. They are using their default value. So for the Foreground property for the three TextBlocks above, you only need one field (since it is a static field).

For the forth TextBlock though, you have explicitly set Foreground to Green, so that value is inserted into a dictionary as the local value for Foreground on this instance and thus requires additional memory (also, it will end up at place number 3 in the list below, overriding Setters, Triggers etc).

Also, see the following post by Josh Smith, it's a good read: Demystifying dependency properties

There is a well-defined set of rules which is used internally by WPF
to figure out what the real value of a DP is. Here is a brief summary
of the rules of precedence used when resolving the value of a DP (read
more about it here):

  1. Property system coercion
  2. Active animations, or animations with a Hold behavior
  3. Local value
  4. TemplatedParent template
  5. Style triggers
  6. Template triggers
  7. Style setters
  8. Theme style
  9. Inheritance
  10. Default value from dependency property metadata

Edit: To answer the comment from Duane

If you explicitly set the value to the same value as the default value, it will still get stored as the local value. This can easily be verified with the following Xaml.

Both TextBlocks will have Foreground set to Black, but the later has a local value set. The Style will only be able to set Foreground on the first TextBlock and not the later since Style setters has lower priority than local value.

<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>
向日葵 2024-12-07 18:48:08

首先,假设您创建一个具有十几个属性的类。创建 100,000 个。您现在有多少个对象引用? 1,200,000。

现在实现一个名为 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;
    }
}

构建一个派生类,如下所示:

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

    // create 11 more properties like this
}

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

这就是属性值继承在依赖对象中的工作原理。

First, suppose you create a class with a dozen properties. Create 100,000 of them. How many object references do you now have? 1,200,000.

Now implement a class called 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;
    }
}

Build a derived class like this:

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

    // create 11 more properties like this
}

Now create 100,000 instances of MyDependencyObject and set their Parent. How many object references are used (not counting the parent)? 300,000.

That's how property value inheritance works in dependency objects.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文