Why should I use an attached property instead of a regular dependency property? - wpf

I just discovered than I can do the following:
var button = new Button();
button.SetValue(TextBlock.TextProperty, "text");
var text = (string)button.GetValue(TextBlock.TextProperty); // text is "text"
While the above example is a bit unrealistic, it does show that I can attach a regular dependency property onto another object. It doesn't have to be a an attached property (TextBlock.TextProperty is not registerd with DependencyProperty.RegisterAttached().
This bares the questions why are there attached properties in the first place? The only difference I can see for now ist that I can't attach regular dependency properties in XAML. But that's about it. Are there any other differences?
Update:
To make it more clear, the below code works and looks pretty close to an attached property from the end users perspective:
public static class AttachedPropertyDeclarer
{
public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
"Text",
typeof(string),
typeof(Button),
new PropertyMetadata(default(string),OnTextChanged));
private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// do something when text changed
}
}
...
button.SetValue(AttachedPropertyDeclarer.TextProperty, "text");
var text = (string)button.GetValue(AttachedPropertyDeclarer.TextProperty);
Compare this to the attached property way:
public static class AttachedPropertyDeclarer
{
public static readonly DependencyProperty TextProperty = DependencyProperty.RegisterAttached(
"Text",
typeof(string),
typeof(AttachedPropertyDeclarer),
new PropertyMetadata(default(string),OnTextChanged));
private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// do something when text changed
}
}
The only effective differnce to an attached property here is that I have to declare the owner of type Button whereas in a attached property it would usually be AttachedPropertyDeclarer. But this only needs to be done if I need a changed event handler (i.e. OnTextChanged).

Regarding your example, you have not as you say, attached a regular dependency property onto another object. All your code has achieved is to store a string value in a Dictionary along with a reference to your object. That does not make it an Attached Property - importantly, you cannot access that string value from the Button directly, as there is no Text property on a Button.
What your code does is actually very similar to this:
Dictionary<object, object> values2 = new Dictionary<object, object>();
var button = new Button();
values2.Add(button, "text");
string text = values2[button].ToString();
Now to answer your question:
The main reason to declare an Attached Property is in order to add a property to a type that you didn't declare, thereby extending its functionality.
A great example of this would be to add a SelectedItems property to the ItemsControl or ListBox class. In doing so, we extend the current, or default functionality of the class. Another good example would be declaring an Attached Property that automatically brings added items into view (again in an ItemsControl or ListBox class).
UPDATE >>>
According to your comments, you seem to be refusing to accept the differences that I have outlined... you said:
There is literally no difference from the end users perspective except that I can't use it in XAML.
Firstly, do you not think that this is a huge difference?.. you won't be able to use it for data binding for a start. Furthermore, you keep saying that you can attach a property to a type that you haven't declared using a DependencyProperty, but you are 100% incorrect. You can reference an Attached Property directly in both code and XAML, while you can't reference what you are calling your attached property directly in either XAML or code.
All you are doing is storing a value in a Dictionary and you certainly don't need the overhead of a DependencyProperty to do that. There really is no comparison between doing that and declaring an Attached Property. From the Attached Properties Overview page on MSDN:
You might create an attached property when there is a reason to have a property setting mechanism available for classes other than the defining class.
Note the following part: a property setting mechanism
Adding values into a Dictionary is not a property setting mechanism. So again, you lose the ability to use your pretend Attached Property in Styles, Animations, Triggers, etc.
To clarify this situation for once and for all, you can develop a simple test project. Implement the IList SelectedItems Attached Property for a ListBox that I mentioned (you can find online tutorials for this) and then do the same using your pretend Attached Property (if it is even possible). The difference in the simplicity of development bewteen the two will clearly show you why you should use an Attached Property instead of a regular DependencyProperty.

If you look closely at dependency property identifier, all DP's are registered with class DependencyProperty and we pass the Owner class type and property name at time of registration.
Sample:
public static readonly DependencyProperty IsSpinningProperty =
DependencyProperty.Register(
"IsSpinning", typeof(Boolean), typeof(OwnerClass));
At time of registration it creates some unique hash code combining property name and owner class type to represent each DP uniquely.
So, when you set value for that DP on some object like in your case on Button, code flow is like this:
First it will get the unique value generated at time of registration of property and add the key value pair in private dictionary named _effectiveValues declared in class Dependency Object with Key set to unique hashcode at time of registration and value being the value set by user.
Note - No written documentation for this on MSDN but verified this by peeking into source code using reflector.
So, when you set the value from code behind it will work like I mentioned above because it does not validate before adding value in the dictionary if it belongs to that type or not and fetching value will get you the value from dictionary.
Not sure but might be constraint is there in XAML only where WPF guys enforced the type check. Sadly there is no written documentation for this on MSDN.

Attached properties are discovered, when you want to have control over an existing control, but dont want to extend it. A pretty good example is, there is no way to bind BlackOutDates property in XAML for WPF DatePicker. In that case you can use an Attached Property to attach a custom functionality to map the BlackOutDates. This suits good in MVVM, since attached properties provided way for binding in XAML.
public class BlackOutDatesAdapter
{
public static List<DateTime> GetBlackOutDates(DependencyObject obj)
{
return (List<DateTime>)obj.GetValue(BlackOutDatesProperty);
}
public static void SetBlackOutDates(DependencyObject obj, List<DateTime> value)
{
obj.SetValue(BlackOutDatesProperty, value);
}
// Using a DependencyProperty as the backing store for BlackOutDates. This enables animation, styling, binding, etc...
public static readonly DependencyProperty BlackOutDatesProperty =
DependencyProperty.RegisterAttached("BlackOutDates", typeof(List<DateTime>), typeof(BlackOutDatesAdapter), new PropertyMetadata(null, OnBlackOutDatesChanged));
private static void OnBlackOutDatesChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
var control = sender as DatePicker;
var list = (List<DateTime>)e.NewValue;
foreach(var date in list)
{
control.BlackoutDates.Add(new CalendarDateRange(date));
}
}
}
Binding in XAML will look like this,
<DatePicker VerticalAlignment="Center"
Width="200"
local:BlackOutDatesAdapter.BlackOutDates="{Binding BlackOutDates}"
DisplayDate="{Binding DisplayDate}" />
In the callback of property, you can do your own mapping of adding the dates to DatePicker. For more information, please read this post.

Related

About DependencyProperty in WPF

I'm very new to WPF and while studying (particularly creating a user control), I stumbled upon this thing called "DependencyProperty".
I understand how it works in code but why and when do we need it when I can just create a property and expose it for public use.
Example:
XAML:
<UserControl.....>
<StackPanel Orientation="Vertical">
<TextBlock x:Name="label" Text="Hello"/>
<TextBlock x:Name="text" Text="World!" />
</StackPanel>
</UserControl>
CS file:
public partial SampleUserCtrl : UserControl
{
public string LabelText { get { return this.label.Text; } set { this.label.Text = value; } }
public string TextBoxText { get { return this.text.Text; } set { this.text.Text = value; } }
}
DependecyProperty in WPF has different uses.
Advantages compared to normal .NET property
Reduced memory footprint It's a huge dissipation to store a field for
each property when you think that over 90% of the properties of a UI
control typically stay at its initial values. Dependency properties
solve these problems by only store modified properties in the
instance. The default values are stored once within the dependency
property.
Value inheritance When you access a dependency property the value is
resolved by using a value resolution strategy. If no local value is
set, the dependency property navigates up the logical tree until it
finds a value. When you set the FontSize on the root element it
applies to all textblocks below except you override the value.
Change notification Dependency properties have a built-in change
notification mechanism. By registering a callback in the property
metadata you get notified, when the value of the property has been
changed. This is also used by the databinding.
As you dig deeper to WPF you will also stumble upon DataBinding and object-oriented design patterns like MVVM or MVPVM. Both patterns rely on DataBinding which is achieved through using of Dependency Properties. You cannot perform data binding if it is not a dependency property.
Basically data binding through dependency properties allow the user to update the view when updating a value through code.
Ex: In Windows Forms in order to update a label text you assign its value on the code behind like this:
lbl1.Text = "foo";
In data binding where as you bind in the XAML (View)
<label Text = "{Binding foo}"></label>
and update the values in your code behind:
foo = "foo";
I am not an expert myself so sorry if I might sound confusing.
Dependency property has many benefits over normal property.
A dependency property value can be set by referencing a resource
It can reference a value through data binding
It can be animated. When an animation is
applied and is running, the animated value operates at a higher
precedence than any value (such as a local value) that the property
otherwise has.
You can learn more about it from msdn.
The main advantage of DP property you can find anything in DP like your Control info and you current DataContext info.
public string MyProperty
{
get { return (string)GetValue(MyPropertyProperty); }
set { SetValue(MyPropertyProperty, value); }
}
// Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.Register("MyProperty", typeof(string), typeof(MyUserControl), new PropertyMetadata(null, (s, e) => OnChangedValue(s, e)));
private static void OnChangedValue(DependencyObject s, DependencyPropertyChangedEventArgs e)
{
throw new NotImplementedException();
}

Updating source using DependencyProperty in custom usercontrol

I got a binding source not being updated when the targeted DependencyProperty of a custom UserControl changes.
The source is a ViewModel loaded with MEF into the DataContext of my custom UserControl.
My binding looks like this in the root XAML of MyUserControl
// MyUserControl.xaml
<MyUserControlBase x:Class="MyUserControl" MyDependencyProperty="{Binding ViewModelProperty}">
If i use the MyDependencyProperty with a FrameworkPropertyMetadata and use the callback function when the property changes i can do the following which works fine
// MyUserControlBase.cs
private static void MyDependencyProperty_Changed(DependencyObject depObj, DependencyPropertyChangedEventArgs args)
{
var filter = (UserControl )depObj;
var vm = (ViewModel)filter.DataContext;
vm.ViewModelProperty= (VMPropType)args.NewValue;
}
Registration of the DependencyProperty in MyUserControlBase which inherit UserControl.
// MyUserControlBase.cs
public static readonly DependencyProperty MyDependencyPropertyProperty = DependencyProperty.Register("MyDependencyProperty",
typeof(VMPropType),
typeof(MyUserControlBase),
new FrameworkPropertyMetadata(null, MyDependencyProperty_Changed));
But why can't i get the simple two way binding to work when done in the XAML?
Output window show no binding failurs. I can see the ViewModel.ViewModelProperty getter is being called. Just not the setter once MyDependencyProperty changes.
It don't appear to be a problem with the ordering of events. The ViewModel is created long before DependencyProperty is changed for the first time.
I've also looked at Setting up binding to a custom DependencyProperty inside a WPF user control
But his problem seems slightly different since i actualy inherit from my own Base class which holds the DependencyProperty.
Thank you for any help.
Edit: with link to example solution.
Solution zip here
Sorry for the scary looking link, I don't know alot of quick fileshareing sites. If its bad post comment and I will remove it asap, but it seems ok.
Answer updated / irrelevant info deleted
After looking at the code in your sample I saw what the problem is. You have this "selector" control. In the BindDependencies method you set a binding on the MyControlBase.MyDependencyProperty. But at the same time you also bind this property to your control's datacontext (in MyUserControl.xaml). Effectively this means that in the BindDependencies method you are overwriting the binding to your viewmodel thus it is not active after that method - you can see this yourself by breaking into before and after the SetBinding call and calling BindingOperations.GetBindingExpression(control, MyUserControlBase.MyPropertyDependencyProperty) - the bindings are different. This is why your code does not work. I guess you will have to find another way of transferring the value there :)
Some additional info
In WPF a property can be a target of only one binding. This is actually very logical - if a property is bound to two sources - which one should it use? The fact that the binding is marked as OneWayToSource does not really matter in this situation as it still counts as a binding that targets the control's property.
One way you can investigate and see if it works for you is the MultiBinding - it does allow to bind the control's property to several sources by implementing your own IMultiValueConverter. You can find more info on this on MSDN in the link provided.
Do you expose the ViewModelProperty as a regular property..
Usually you do the following....
public static readonly DependencyProperty ViewModelPropertyProperty = DependencyProperty.Register("ViewModelProperty",
typeof(VMPropType),
typeof(MyUserControlBase),
new FrameworkPropertyMetadata(null, ViewModelProperty_Changed));
public VMPropType ViewModelProperty {
get { return (VMPropType)GetValue(ViewModelPropertyProperty); }
set { SetValue(ViewModelPropertyProperty,value); }
}
EDIT -- After comment.
When are you checking that the property has changed? By default WPF bindings only update the values when they lose focus, you change change the UpdateSourceTrigger property of the binding to alter this behaviour.

Silverlight: How to add a Dependency Property to multiple controls?

Is it possible to create a Dependency Property for multiple controls without resorting to subclass every one of it?
I thought about using Attached Properties but they nest only one level deep as far as I understand it.
I want something like this to be possible:
<!-- MyDataGrid implements the new Attached Properties SourceData and TargetData -->
<MyDataGrid>
<StackPanel>
<TextBox MyDataGrid.SourceData="{Binding Somewhere}" MyDataGrid.TargetData="{Binding Somewhere}" />
</StackPanel>
<CheckBox MyDataGrid.SourceData="{Binding Somewhere}" MyDataGrid.TargetData="{Binding Somewhere}" />
</MyDataGrid>
This won't work since the Attached Properties wouldn't be found in the TextBox since it's no direct descendent of MyDataGrid.
Background is that I try to automatically convert an old Xaml-like Gui-syntax into real Xaml and with the old system it was possible to set different sources and targets for changed data. Now I'm searching for a Xaml-solution that doesn't involve subclassing every control there is.
Thanks in advance.
are you sure you are using Attached property correctly?
public static readonly DependencyProperty SourceDataProperty = DependencyProperty.RegisterAttached(
"SourceData", typeof (string), typeof (MyDataGrid), new PropertyMetadata("test"));
public static void SetSourceData(DependencyObject obj, string sourceData)
{
obj.SetValue(SourceDataProperty, sourceData);
}
public static string GetSourceData(DependencyObject obj)
{
return (string) obj.GetValue(SourceDataProperty);
}
This worked for me.Though SetSourceData was not get called, but data was there.
To retrive data.
MyDataGrid.GetSourceData(tbox);
Where tbox is the instance of your TextBox.

WPF - Expose a Bindable ReadOnly Dependency Property and add internally values

Thats my code:
public static readonly DependencyPropertyKey ItemsSourceKey =
DependencyProperty.RegisterReadOnly("ItemsSource", typeof(List<string>), typeof(MyTextBox), null);
public static readonly DependencyProperty ItemsSourceProperty = ItemsSourceKey.DependencyProperty;
public List<string> ItemsSource
{
get { return (List<string>)GetValue(ItemsSourceProperty); }
}
I have 2 problems here:
1.) Since I made it a DependencyPropertyKey as suggested on MSDN I can not see anymore the ItemsSource in my XAML.
2.) The user should be able to bind to the List getting the current strings in the ItemsSource of MyTextBox control. Internally inside MyTextBox I want to add strings to the ItemsSource but I can not create an instance of a List and assign it to ItemsSource as it is ReadOnly...
How can I solve that? I want a bindable readonly Property to which I can set data internally. Maybe you ask why I do not use the .Text Property to bind there. Well the user enters Data, I change it and want to return it changed in a list...
This problem is addressed in ItemsControl by using two separate properties: ItemsSource for Binding, Items as the readonly collection object used for actual display of data. Since ItemsControl already handles connecting these collections for you and doing all the necessary updates, if you want this behavior you should derive from ItemsControl. If you need the behavior of both ItemsControl and TextBox you can either create a control that is a composite of both and passes through properties to the internal controls, or create two related derived controls (one ItemsControl, one TextBox) that work with each other.
How can I solve that? I want a
bindable readonly Property to which I
can set data internally. Maybe you ask
why I do not use the .Text Property to
bind there. Well the user enters Data,
I change it and want to return it
changed in a list...
If you just need to modify your data you can use a converter for that.

How to Add Custom Silverlight XAML Attributes?

Is it possible to introduce 'custom' attributes into different UI Elements in XAML ? Also to read them later like we add attributes for server controls in ASP.NET ?
I intend to read specific attributes and operate on them together.
It sounds like you're trying to find Attached Properties.
An attached property lets you add in a property, definable in Xaml, which can be "attached" to any UIelement. You then retrieve them in code like any other Dependency Property.
Here is the approach I tend to take with this.
Create a new class file called Meta:-
namespace SilverlightApplication1
{
public static class Meta
{
#region SomeValue
public static string GetSomeValue(DependencyObject obj)
{
return (string)obj.GetValue(SomeValueProperty);
}
public static void SetSomeValue(DependencyObject obj, string value)
{
obj.SetValue(SomeValueProperty, value);
}
public static readonly DependencyProperty SomeValueProperty =
DependencyProperty.RegisterAttached("SomeValue", typeof(string), typeof(Meta),
new PropertyMetadata(null));
#end region
#region SomeOtherValue
// Boilerplate code from above.
#end region
}
}
A value can now be attached in XAML like this:-
<TextBox x:Name="txt" local:Meta.SomeValue="Hello, World!" />
At some point in code this value can be retrieved with:-
string value = Meta.GetSomeValue(txt);
Note you don't have to stick with String as the type of the property you can pretty much use any type you like with the limitation that if you can to attach it in XAML the type must be compatible with the way XAML constructs objects (for example requires a default constructor).
The way I've accomplished that is by creating a new class that inherits the base control.
For example, I have a class called WebTextBox that inherits TextBox. And inside WebTextBox are some custom properties and events. By doing this you're inheriting all the behaviors of the TextBox control. But you can get creative here if you choose, even modifying the behavior by overriding events and such.
Anyway, after you create the class you'll then have to add the namespace for the project to the XAML. Something like this:
xmlns:me="clr-namespace:YourNamespace;assembly=YourAssembly"
And then you can add a WebTextBox (or whatever you call it) like this:
<me:WebTextBox CustomAttribute="cool stuff" />

Resources