Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

.NET

Properties, Dependency Properties, and WPF


Retained Graphics

What's not going on in PropertySettingsDemo.xaml is a lot of redrawing—at least, by most of the TextBlock elements. In earlier Windows programming environments, when a control is moved from one part of a window to another, it needs to be redrawn. The surface of the window is invalidated, which generates repainting calls.

In contrast, the WPF has a retained graphics system. Once an element draws itself—a process that happens in the virtual OnRender method—it doesn't need to draw itself again unless something happens to cause it to require a new appearance. This is the case with the TextBlock whose FontSize is animated, and the one whose FontSize is bound to the ScrollBar. A new FontSize requires redrawing; but the others are drawn only once, including the one being rotated.

To make this program more efficient, it would be better to change the size of TextBlock elements with a ScaleTransform rather than altering the FontSize. The transform is performed on the retained graphics object rather than requiring the element to redraw itself.

Properties and Dependency Properties

The developers of the WPF realized they were designing a system where properties could be set in a variety of ways, some of them possibly interacting with each other. It was important to construct a system where these interactions would have strict levels of precedence and predictability. Their solution was to build a layer on top of the existing property mechanism called "dependency properties."

If you were privy to source code for TextBlock, you would probably find it has something like this code:


public static DependencyProperty 
  FontSizeProperty =
   DependencyProperty.Register
     ("FontSize", typeof(double), 
      typeof(TextBlock), 
       new FrameworkPropertyMetadata
        (default, flags,
         FontSizeChanged), 
          ValidateFontSize);

This is the definition of a static field named FontSizeProperty—that is, the FontSize property name followed by the word Property—of type DependencyProperty. The initialization code that follows could alternatively be in the class's static constructor. This code defines the name of the property, its type (double), its owner, and a default value, indicated by default. Let me come back to the flags parameter.

The code also references two static methods. One provides a systematic approach to validation. The ValidateFontSize method returns True if the FontSize property is being set to a value of at least 1/300 inch.


static bool ValidateFontSize
    (object obj)
{
  double fntsize = (double) obj;
  return fntsize > 1.0 / 300;
}

I don't have access to WPF source code, so I can't tell you precisely what happens in the method I've called FontSizeChanged. The method is called whenever the FontSize value changes, but it might not exist at all, and if it does, it probably only performs some preparation work, such as creating an object of type FormattedText. Anything more is unnecessary, as you'll see soon.

The TextBlock class also includes a regular FontSize property, but it only refers to the FontSizeProperty dependency property:


public double FontSize
{
  get { return (double)
     GetValue (FontSizeProperty);      }
  set { SetValue(FontSizeProperty,
     value); }
}

The GetValue and SetValue methods are defined by the DependencyObject class. Any class that implements dependency properties must derive from DependencyObject.

I haven't yet discussed the flags parameter in the dependency property initialization code, and for the FontSize property, these flags are crucial. The flags parameter consists of zero or more members of the FrameworkPropertyMetadataOptions enumeration, combined with the bitwise OR operator. For FontSize, there are three flags set:

  • The AffectsMeasure flag indicates that whenever the FontSize property changes, the current measure information for the element should be invalidated. This causes a call to the MeasureOverride method, which then triggers a call to ArrangeOverride so the element can be repositioned based on its new size.
  • The AffectsRender flag indicates that whenever the FontSize property changes, the current visual appearance of the element is invalidated, generating a call to OnRender. Notice that the AffectsMeasure and AffectsRender flags are independent. For example, the Foreground property, which indicates the color of the text displayed by the TextBlock, has its AffectsRender flag set but not AffectMeasure because the color doesn't affect the size of the element.
  • Finally, the Inherits flag is set, indicating that the FontSize property can be set from the element's closest ancestor.

Yes, the TextBlock element is still responsible for determining how large it needs to be and what it should look like, but all the notification mechanisms for property changes have been encapsulated in the DependencyProperty object. TextBlock doesn't have to invalidate its size or rendering information, nor does TextBlock have to worry about how property inheritance works. The retained graphics system provides that any change to these properties won't cause flickering on the screen.

Dependency properties are so important that data binding and animation don't work with anything that's not a dependency property. The data-binding and animation markup in PropertySettingsDemo.xaml seems to refer to the FontSize property, but binding and animation classes actually access the FontSizeProperty field directly.

That means that if you're writing a WPF class in which you want properties to be bindable or animatable, you'll want to make them dependency properties, and in the process save yourself from implementing a lot of custom notification logic.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.