Attached dependency property as being the property equivalent of an extension method.
You basically attach a new property to an existing object. Without actually modifying the object definition.
Which is especially handy when inheritance is not possible, like in sealed objects.
The most important application, as far as I am concerned, is that you can make something bindable that is not
bindable out of the box. If some value(s) a GUI component can only be set by a method, you cannot use it from MVVM,
for example. By making an attached dependency property that passes on the new value to said method you work around that.
See below for how you make such a callback.
So how do you make an attached dependency property?
You make a static class, in which the property is declared and 'hosted'
public static class DependencyPropertyHoster
{
public static readonly DependencyProperty MyPropertyNameProperty =
DependencyProperty.RegisterAttached("MyPropertyName",
typeof(TargetPropertyType),
typeof(DependencyPropertyHoster),
new PropertyMetadata(CallBackWhenPropertyIsChanged));
// Called when Property is retrieved
public static TargetPropertyType GetMyPropertyName(DependencyObject obj)
{
return obj.GetValue(MyPropertyNameProperty) as TargetPropertyType;
}
// Called when Property is set
public static void SetMyPropertyName(
DependencyObject obj,
TargetPropertyType value)
{
obj.SetValue(MyPropertyNameProperty, value);
}
// Called when property is changed
private static void CallBackWhenPropertyIsChanged(
object sender,
DependencyPropertyChangedEventArgs args)
{
var attachedObject = sender as ObjectTypeToWhichYouWantToAttach;
if (attachedObject != null )
{
// do whatever is necessary, for example
// attachedObject.CallSomeMethod(
// args.NewValue as TargetPropertyType);
}
}
}
This is roughly the equivalent of
public partial class ObjectTypeToWhichYouWantToAttach
{
TargetPropertyType _myPropertyName;
TargetPropertyType MyPropertyName
{
get
{
return _myPropertyName;
}
set
{
if( _myPropertyName != value )
{
//CallBackWhenPropertyIsChanged...
}
}
}
}
The whole thing works by naming convention. So if you call your property "MyPropertyName", then:
When you register your property the way I do, the members in the RegisterAttached method call are, from left to right:
You basically attach a new property to an existing object. Without actually modifying the object definition.
Which is especially handy when inheritance is not possible, like in sealed objects.
The most important application, as far as I am concerned, is that you can make something bindable that is not
bindable out of the box. If some value(s) a GUI component can only be set by a method, you cannot use it from MVVM,
for example. By making an attached dependency property that passes on the new value to said method you work around that.
See below for how you make such a callback.
So how do you make an attached dependency property?
You make a static class, in which the property is declared and 'hosted'
public static class DependencyPropertyHoster
{
public static readonly DependencyProperty MyPropertyNameProperty =
DependencyProperty.RegisterAttached("MyPropertyName",
typeof(TargetPropertyType),
typeof(DependencyPropertyHoster),
new PropertyMetadata(CallBackWhenPropertyIsChanged));
// Called when Property is retrieved
public static TargetPropertyType GetMyPropertyName(DependencyObject obj)
{
return obj.GetValue(MyPropertyNameProperty) as TargetPropertyType;
}
// Called when Property is set
public static void SetMyPropertyName(
DependencyObject obj,
TargetPropertyType value)
{
obj.SetValue(MyPropertyNameProperty, value);
}
// Called when property is changed
private static void CallBackWhenPropertyIsChanged(
object sender,
DependencyPropertyChangedEventArgs args)
{
var attachedObject = sender as ObjectTypeToWhichYouWantToAttach;
if (attachedObject != null )
{
// do whatever is necessary, for example
// attachedObject.CallSomeMethod(
// args.NewValue as TargetPropertyType);
}
}
}
This is roughly the equivalent of
public partial class ObjectTypeToWhichYouWantToAttach
{
TargetPropertyType _myPropertyName;
TargetPropertyType MyPropertyName
{
get
{
return _myPropertyName;
}
set
{
if( _myPropertyName != value )
{
//CallBackWhenPropertyIsChanged...
}
}
}
}
The whole thing works by naming convention. So if you call your property "MyPropertyName", then:
- Your DependecyProperty needs to be called MyPropertyNameProperty
- Your Set method needs to be called SetMyPropertyName
- Your Get method needs to be called GetMyPropertyName
When you register your property the way I do, the members in the RegisterAttached method call are, from left to right:
- The name of your property (as a string, yes)
- Property value type (here “TargetPropertyType”, but of course that can be anything)
- Type of the hosting class (i.e. DependencyPropertyHoster in this case)
- Callbackmethod to be called when the property is changed.
No comments:
Post a Comment