This article is compatible with the latest version of Silverlight.
1. Introduction
An attached property is a new concept that is defined by Extensible Application Markup Language (XAML). The attached properties are intended to be used as global properties that are settable on any type of object. In WPF/Silverlight, attached properties are typically defined as a form of a dependency property that does not have the conventional property 'wrapper'.
Download source code
2. What attached properties are?
The main ability of the attached properties is to allow different child elements to specify unique values for a property that is actually defined in a parent element. In our example bellow I will show how a child element can inform its parent of how it is to be presented in the user interface (UI). Lets use the widely spread example of how the DockPanel (please note that the DockPanel exists only in WPF but not in Silverlight) uses the attached properties. When you add an element to a DockPanel, you need to tell the DockPanel on what side to Dock the element (Left, Right, Center etc.). In WPF the Dock property is an attached property registered by the DockPanel while in WinForms the Dock property is hardcoded in the Control class, even though you are not always docked. The Dock property only makes sense to the docking code.
Bellow you can see how to assign value to an attached property from within C# and XAML:
C#
DockPanel.SetDock( uiElement, DockStyle.Left );
//or
uiElement.SetValue( DockPanel.DockProperty, DockStyle.Left );
XAML
<DockPanel>
<ButtonDockPanel.Dock="Left"/>
</DockPanel>
|
As you can see here the attached property is DockPanel.Dock and the DockPanel is the property provider that has registered it internally. This registration is explained later in our example.
3. Why we need attached properties?
The attached properties are a very powerful tool for dynamic extension of classes without inheritance. They also allow us to keep the properties located at their logical places – use what you need only when you need it. Moreover they allow the place, where the property is defined and the place, where it is stored, to be completely different classes that know nothing about each other. Like in the above example the Dock property value is stored in the button instance not in the DockPanel itself.
With the attached properties you can make your classes structure much more comprehensible for the developer by using only the properties that are valid in the specific context.
The good news is that many advantages from the dependency properties model are coming out of the box for the attached properties such as caching, data binding, default values, expressions, styling (which is nothing more than a set of predefined property values), property invalidation and more.
4. Registering and using custom attached properties in Silverlight
Probably the first most important thing to mention here is that only inheritors of DependencyObject can be extended with such attached properties. This is needed because either to set or to get value for a specific attached property, you need to use the methods SetValue and GetValue which are defined in DependencyObject class. As we have already said all values defined for a specific attached property are stored in the instance of the extended object, so it acts like a regular hash table for the defined properties and their values.
The property provider class itself does not need to derive from DependencyObject, but Microsoft recommends making it also an inheritor of the DependencyObject, because thus we will follow the overall WPF model.
Let’s look at the most important steps needed to define a custom attached property in Silverlight:
1. Define a hollow class that should act as the provider for the attached property. In our sample it will be named TabPanel and it derives directly from the StackPanel class.
public class TabPanel : StackPanel
{
publicTabPanel()
{
}
}
|
2. Define the attached property as a field of type DependencyProperty inside the TabPanel class.
public static readonly DependencyProperty TabStopProperty = DependencyProperty.RegisterAttached(
"TabStop", //Name of the property
typeof( bool ), //Type of the property
typeof( TabPanel ), // Type of the provider of the registered attached property
null ); //Callback invoked in case the property value has changed
|
We make this field public and read-only. Thus other people will be able to access it but they will not be able to change it. It is static because it describes a property that is valid for that class at all, not just for some specific instance of it.
3. Define the appropriate SetXXX and GetXXX methods inside the TabPanel class.
public static void SetTabStop( DependencyObject obj, booltabStop )
{
obj.SetValue( TabStopProperty, tabStop );
}
public static bool GetTabStop( DependencyObject obj )
{
return ( bool )obj.GetValue( TabStopProperty);
}
|
As you can see these methods represent simple static type-safe wrappers for the GetValues/SetValue methods of the extended dependency object.
Note that every attached property must have such methods defined because they are used by Silverlight when the value of the attached property should be changed from within XAML. The naming convention is pretty straightforward ‘Set + Property name’ and ‘Get + Property name’.
4. Here is how our TabPanel class finally should look like:
public class TabPanel : StackPanel
{
public static readonly DependencyProperty TabStopProperty = DependencyProperty.RegisterAttached(
"TabStop", //Name of the property
typeof( bool ), //Type of the property
typeof( TabPanel ), //Type of the provider of the registered attached property
null ); //Callback invoked in case the property value has changed
publicTabPanel()
{
}
public static void SetTabStop( DependencyObject obj, booltabStop )
{
obj.SetValue( TabStopProperty, tabStop );
}
public static bool GetTabStop( DependencyObject obj )
{
return ( bool )obj.GetValue( TabStopProperty );
}
//Just a sample method ilustrating the idea how to obtain the value
//of the TabStop property for a specific element.
private void ProcessTabKey()
{
foreach ( UIElement element in this.Children )
{
bool tabStop = TabPanel.GetTabStop( element );
//Perform some processing according to the tab stop.............
}
}
}
|
There is only one thing left to be added to the TabPanel class and this is the implementation of the sample method where the value of that attached property will be used. I named this method ProcessTabKey and in our sample its tasks are to obtain the tab stop value for every one of its child controls and make some processing according to this value.
5. Finally we have to define value for our new attached property for a control. Here are a few samples showing you how to do it from within XAML or the code behind.
C#
TabPanel.SetTabStop( uiElement, true );
//or
uiElement.SetValue( TabPanel.TabStopProperty, true );
XAML
…
xmlns:local="clr-namespace:SilverlightShow.AttachedProperties.Demo;assembly=AttachedPropertiesDemo"
…
<TabPanel>
<Button local:TabPanel.TabStop="True"/>
</TabPanel>
|
Do not forget to include in your XAML files the namespace and the assembly name containing the class that has registered the attached property, even though it is in the same assembly where your XAML is.
5. FAQ
a. How to set value to an attached property?
You can set the value of an attached property both within XAML and from the code behind. There are a few samples of both cases in the article above but in general the logic is very simple. From your code behind you can call the method SetValue of the instance of the class that the property is attached to. You will have to pass two parameters. The first one is the dependency property and the second one is the new value for that property.
uiElement.SetValue( TabPanel.TabStopProperty, true );
|
The other way is to call the appropriate static SetXXX method which belongs to the class that provides/registers the attached property. Depending on the implementation, you will need to pass some parameters that usually are the class whose property value should be changed and the new value for that property.
TabPanel.SetTabStop( uiElement, true );
|
The syntax in XAML is much easier. You just have to define the value for that property by typing its name like this ‘Provider.PropertyName’ where the Provider (i.e. TabPanel) is the name of the class that registers the attached property and the PropertyName (i.e. TabStop) is the name of that attached property.
<TabPanel>
<ButtonTabPanel.TabStop="True"/>
</TabPanel>
|
b. What kind of objects can be extended with the attached properties?
You can attach properties to any class in Silverlight that derives directly or indirectly from DependencyObject.
c. What happens if we set value to an attached property, which property is not appropriate in certain context?
What if I define value for the TabStop property of a button but that button isn’t contained within a TabPanel? What should happen in that case? Will we get an error? The answer is that this won’t harm your application at all. If you define value for an attached property that is not needed, this won’t lead to an error. This value will simply never be used because no one will ever look for the property.
d. How to register a custom attached property?
You can register an attached property by calling the static method RegisterAttached that belongs to DependencyProperty class. You can make the registration when declaring the static field of DependencyProperty type or in the static constructor of the class acting as a provider of that new property. For more information about the needed parameters see the comments bellow.
public static readonly DependencyProperty TabStopProperty = DependencyProperty.RegisterAttached(
"TabStop", //Name of the property
typeof( bool ), //Type of the property
typeof( TabPanel ), //Type of the provider of the registered attached property
null ); //Callback invoked in case the property value has changed
|
e. Are there any performance issues when working with attached properties?
To be honest I haven’t had time to perform a through performance test so far but I think that if there is a delay it won’t be anything tremendous at all. For me it is something I can live with.
f. Where is the value of an attached property stored?
The value of every attached property is stored in the class the property is being attached to. For example if you define value for the TabStop property of a button then this value is stored internally in the button, not in the TabPanel that registered it.
g. Can I bind to an attached property?
Yes, you can bind to an attached property. However, this feature is available after Silverlight 2.
h. When should I use attached properties?
I did not find any hardcoded rules for this. But according to me you should use attached properties in case you do not want to pollute your class code with artificial properties that are required so as other external classes to function.
i. When should I avoid using attached properties?
Attached properties are not universal painkiller. They have to be used carefully and only in cases they play reasonable role in your application design. Otherwise they might cause confusions and misunderstandings.
6. Conclusion
As a conclusion I could say that the attached properties are a very powerful thing if you use them at the right place and in the right time. Personally I will put them in my toolbox and grab them every time my design requires such behavior.
Bellow you can find a short list of the advantages and disadvantages of the attached properties as I saw them.
Pros:
- You can define the properties that are meaningful only to the class itself;
- You can keep your structure clearer and comprehensible by avoiding the artificial properties required by external classes to function;
- Many advantages from the dependency properties model are coming out of the box for the attached properties such as caching, data binding, default values, expressions, styling (which is nothing more than a set of predefined property values), property invalidation and more.
Cons:
- Some extra work is required to define an attached property;
- Confusing for someone who isn’t familiar with this concept;
- Hardly sensible performance decrease.
7. List of some attached properties in Silverlight
Below you can find a list of some of the attached properties available in .NET Framework. This list is a short reference that was not meant to be complete. I decided to put it here to give you an idea about the way Microsoft uses the attached properties.
Canvas.Top – Define the distance for a control from the top edge of its container;
Canvas.Left – Define the distance for a control from the left edge of its container;
Canvas.ZIndex – Z Index of the control;
Grid.Row – Define the row index for a control placed in a Grid container;
Grid.Column – Define the row index for a control placed in a Grid container;
ScrollViewer.HorizontalScrollBarVisibility – Define the visibility of the horizontal scrollbar;
ScrollViewer.VerticalScrollBarVisibility – Define the visibility of the vertical scrollbar;
ToolTipService.ToolTip – Define the tool tip associated with a control;
and many more….
8. Useful links/Resources
http://msdn.microsoft.com/en-us/library/cc265152(VS.95).aspx - See what Microsoft tells about the attached properties in Silverlight 2;
http://msdn.microsoft.com/en-us/library/ms749011.aspx – Attached properties in WPF;
http://blogs.msdn.com/bencon/archive/2006/07/24/677520.aspx - Attached properties the basics with nice example by BenCon’s.
http://www.nikhilk.net/Entry.aspx?id=194 – How to create default commit behavior using attached properties by Nikhil Kothari;