Welcome to RioterDeckers' HeadQuarter Sign in | Join | Help

[WPF Core] Attached DependencyProperty and VisualTree

Introduction


After several month of investigation about WPF, We are used to working on enhanced user graphical experience and the foundamentals are quickly forgotten.
So I 've decided to stop one minute on one of the most famous mechanism that allows a parent to provide functionalities to its children, its descendants or much more.

Whereas nobody can ignore the law, nobody can ignore the DependencyProperty. You certainly used a canvas to position your visual elements using absolute position and you might notice that the children of the canvas were able to use canvas capabilities to define this postion. The code below can easily refresh your memory:

<Canvas>
  <
Button Canvas.Top="10" Canvas.Left="30" Height="30" Width="50"
/>
</
Canvas>

The button is decorated by the attached DependencyProperty objects of its parent which is the canvas. So now how to implement this powerful mechanism ?

Creating the attached DependencyProperty


To describe the concept, I suggest to create a panel that allows displaying a disclaimer message, i.e. each child of this panel is decorated with this feature.
So I consume the panel as describes below:

<l:DisclaimerPanel>
  <
Button Height="35" Width="90" Content="Disclaimer child" l:DisclaimerPanel.Disclaimer="Copyright © 2006 The RioterDeckers" Margin="0,40,0,10"
/>
  <
Button Height="35" Width="90" Content="Disclaimer child" l:DisclaimerPanel.Disclaimer="Powered by the RioterDeckers" Margin="0,40,0,10"
/>
</
l:DisclaimerPanel>

Figure 1. the disclaimer panel and its children

So, in the DisclaimerPanel class, I first create the DependencyProperty. Then I register and attach it into the DependencyProperty system:

private static readonly DependencyProperty DisclaimerProperty;

static DisclaimerPanel()
{
 
DisclaimerProperty =
DependencyProperty.RegisterAttached("Disclaimer", typeof(string), typeof(DisclaimerPanel), new FrameworkPropertyMetadata(string.Empty, new PropertyChangedCallback(_DisclaimerChangedCallBack)), new ValidateValueCallback(_ValidateValueCallBack));
}

When you declare an attached DependencyProperty, WPF needs at least one accessor method to be called when the value of the property is set. I need no more energy to create another method to get the value of my attached property. Be careful that WPF defines a naming constraint for these method and so in my case, must be SetPropertyName and GetPropertyName and respect a particular signature.

public static string GetDisclaimer(UIElement element)
{
 
return (string
)element.GetValue(DisclaimerProperty);
}
public static void SetDisclaimer(UIElement element, string value)
{
  element.SetValue(DisclaimerProperty, value);
}

Defining a behavior when the DependencyProperty is set


In the RegisterAttached method signature, the PropertyChangedCallBack parameter enables to define a behavior to execute when a value is set to the DependencyProperty. In my case, I would like to create the visual tree for the specified disclaimer message.

private static void _DisclaimerChangedCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
 
if(d == null) return
;
 
 
FrameworkElement __element = (d as FrameworkElement
);
  if (__element == null) return
;

  Control __disclaimerControl = _BuildDisclaimerVisualTree(e.NewValue.ToString());
  (__element.Parent
as DisclaimerPanel
).Children.Add(__disclaimerControl);
}

I also use the ValidateValueCallback argument in order to check the good type of the attended value. In order to avoid having a null value, it's recommended to give a default value passed as the first parameter of the RegisterAttached method.

private static bool _ValidateValueCallBack(object value)
{
 
return (value is string
);
}

Building the VisualTree of the disclaimer message


To display the disclaimer message, I don't need to create a complex logical tree, I think that a simple control will be sufficient. I just need to create a visual tree through a ControlTemplate applied to the control and to build the tree I simply use several FrameworkElementFactory objects which are very useful to create the visual composition.

private static Control _BuildDisclaimerVisualTree(string value)
{
 
Control __control = new Control
();

  FrameworkElementFactory __fePanelFactory = new FrameworkElementFactory(typeof(StackPanel));

  FrameworkElementFactory __feFactory = new FrameworkElementFactory(typeof(TextBlock));
  __feFactory =
new FrameworkElementFactory(typeof(TextBlock
));
  __feFactory.SetValue(
TextBlock
.TextProperty, value);
  __feFactory.SetValue(
TextBlock.HorizontalAlignmentProperty, HorizontalAlignment
.Center);
  __feFactory.SetValue(
TextBlock.ForegroundProperty, new SolidColorBrush(Colors
.Red));
  __feFactory.SetValue(
TextBlock
.FontSizeProperty, 9.0d);
  __feFactory.SetValue(
TextBlock.FontStyleProperty, FontStyles
.Italic);

  __fePanelFactory.AppendChild(__feFactory);

  FrameworkElementFactory __feHLTextBlockFactory = new FrameworkElementFactory(typeof(TextBlock));
 
FrameworkElementFactory __feHlinkFactory = new FrameworkElementFactory(typeof(Hyperlink
));
 
FrameworkElementFactory __feSubTBFactory = new FrameworkElementFactory(typeof(TextBlock
));
  __feHLTextBlockFactory.SetValue(
TextBlock.HorizontalAlignmentProperty, HorizontalAlignment
.Center);
  __feHlinkFactory.SetValue(
Hyperlink.NavigateUriProperty, new Uri
(RD_URI));
  __feHlinkFactory.AddHandler(
Hyperlink.RequestNavigateEvent, new RequestNavigateEventHandler
(_NavigateToRD));
  __feSubTBFactory.SetValue(
TextBlock
.TextProperty, RD_URI);
  __feSubTBFactory.SetValue(
TextBlock
.FontSizeProperty, 9.0d);

  __feHlinkFactory.AppendChild(__feSubTBFactory);
  __feHLTextBlockFactory.AppendChild(__feHlinkFactory);
  __fePanelFactory.AppendChild(__feHLTextBlockFactory);

  ControlTemplate __template = new ControlTemplate(typeof(Control));
  __template.VisualTree = __fePanelFactory;
  __control.Template = __template;

  return __control;
}

Conclusion


As you can see, WPF provides powerful mechanisms to add extended functionalities during the life cycle of dependent objects that it's the behavior of children like the visual tree on the fly. The sources and the binaries come from the WinFX February CTP.

Download the sources
Download the binaries

Published Friday, February 24, 2006 6:48 PM by Chaz
Filed Under:

Comments

# ProxyFactory launch

A first release has been just published. You can get it from the Releases section.

Release 1.0 Beta
http://www.codeplex.com/Release/ProjectReleases.aspx?ProjectName=ProxyFactory&amp;ReleaseId=1079

This library offers a convenient way to provide
Tuesday, November 21, 2006 2:56 AM by Nezdeboeuf

# ProxyFactory launch

A first release has been just published. You can get it from the Releases section.

Release 1.0 Beta
http://www.codeplex.com/Release/ProjectReleases.aspx?ProjectName=ProxyFactory&amp;ReleaseId=1079

This library offers a convenient way to provide
Tuesday, November 21, 2006 2:57 AM by Nezdeboeuf

# ProxyFactory launch

Even if the revolution announced by MS with its .Net 3.0 platform is just around the corner, the fact...
Tuesday, November 21, 2006 3:03 AM by Valhalla
Anonymous comments are disabled