问题
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 ?
回答1:
See the following link: http://www.bobpowell.net/dependencyproperty.aspx
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):
- Property system coercion
- Active animations, or animations with a Hold behavior
- Local value
- TemplatedParent template
- Style triggers
- Template triggers
- Style setters
- Theme style
- Inheritance
- 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>
回答2:
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.
来源:https://stackoverflow.com/questions/7137291/how-does-the-wpf-dependency-property-design-save-memory-consumption