Dependency property registration
-
Monday, July 07, 2008 8:05 PMDependencyProperty.Register and DependencyProperty.RegisterAttached methods contain ownerType parameter.
The meaning of this parameter is obvious for attached properties: it means that we can use this attached property only with classes of ownerType type (or derived). But I can't understand what does this property mean for DependencyProperty.Register method.
All Replies
-
Tuesday, July 08, 2008 7:14 AMI guess it's just for efficient lookup, since all dependency properties are registered in some central storage system.
Don't spend too much time thinking about it, just use the type of the class you're declaring the property in ;-)
hth,
Marcel -
Tuesday, July 08, 2008 6:32 PMI would like to know does ownerType influence on something or not.
-
Wednesday, July 09, 2008 7:50 AMI don't even think it would work if you use the type of another class, because all dp's are registered at class level (static), so it needs that type to know which dp's belong to which classes.
OwnerType is also used if you want to re-use the same dp in another class: http://msdn.microsoft.com/en-us/library/ms754002.aspx.
Marcel -
Wednesday, July 09, 2008 11:42 AMBut why there is no exception if I use ownerType which is not derived from DependencyObject? RegisterAttached throws such an exception.
-
Wednesday, July 09, 2008 12:59 PM
Just did a little test and it does fail at runtime ("'Class1' type must derive from DependencyObject."). Are you really sure the ownertype does not derive (indirectly) from DependencyObject?
I did some more testing though. See this xaml:<Window x:Class="TempApplication1.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300"> <Grid> <Button x:Name="button1" Click="button1_Click" Width="100" Height="35"> Test1 </Button> </Grid> </Window>
Normal use would be this code:
Click the button and the MessageBox will tell you that the property has changed for Window1. So far, so good.private void button1_Click(object sender, RoutedEventArgs e) { Button b1 = sender as Button; this.IsAvailable = true; } public static readonly DependencyProperty IsAvailableProperty = DependencyProperty.Register("IsAvailable", typeof(bool), typeof(Window1), new FrameworkPropertyMetadata((bool)false, new PropertyChangedCallback(OnIsAvailableChanged))); public bool IsAvailable { get { return (bool)GetValue(IsAvailableProperty); } set { SetValue(IsAvailableProperty, value); } } private static void OnIsAvailableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { MessageBox.Show("IsAvailable changed for: " + d.ToString()); }
Setting the OwnerType to UIElement still works, because it's a baseclass for Window.
But it also has a side effect: you can now set this property on any UIElement, for example the button:
Now the MessageBox will tell you that the property has changed on the button, but you still handled the changed event in Window1!private void button1_Click(object sender, RoutedEventArgs e) { Button b1 = sender as Button; b1.SetValue(Window1.IsAvailableProperty, true); } public static readonly DependencyProperty IsAvailableProperty = DependencyProperty.Register("IsAvailable", typeof(bool), typeof(UIElement), new FrameworkPropertyMetadata((bool)false, new PropertyChangedCallback(OnIsAvailableChanged)));
The same would have worked if you had set it to type Button, but using UIElement has another effect when you combine it with 'FrameworkPropertyMetadataOptions.Inherits':
Now the MessageBox will tell you that this property has changed for the the button and all it's children, because they also derive from UIElement!public static readonly DependencyProperty IsAvailableProperty = DependencyProperty.Register("IsAvailable", typeof(bool), typeof(UIElement), new FrameworkPropertyMetadata((bool)false, FrameworkPropertyMetadataOptions.Inherits, new PropertyChangedCallback(OnIsAvailableChanged)));
So, all this can be useful in very special situations, but I didn't have a need for it yet. Also, I think you can't use this stuff in xaml, only in code.
hth,
Marcel -
Wednesday, July 09, 2008 3:23 PM
Look at this code:MyClass is not derived from DependencyObject, but there is no exception.public partial class Window1 : Window { public static readonly DependencyProperty IsAvailableProperty = DependencyProperty.Register("IsAvailable", typeof(bool), typeof(MyClass)); public Window1() { SetValue(IsAvailableProperty, true); InitializeComponent(); } } public class MyClass {}
-
Wednesday, July 09, 2008 3:44 PMDutchMarcel, dependency property with ownerType set to UIElement is very similar to attached dependency property, doesn't it?
-
Wednesday, July 09, 2008 5:30 PMIdsa said:
DutchMarcel, dependency property with ownerType set to UIElement is very similar to attached dependency property, doesn't it?
Yes, I think it is, but an attached property has the advantage that it can be used in xaml aswell.
I don't know why you don't get an error using the MyClass class, but I'll put my test project up for you to download as soon as I get back at work tomorrow. -
Thursday, July 10, 2008 7:06 AMI uploaded my test project here: http://cid-027cdb908d14e584.skydrive.live.com/self.aspx/WPFSamples/OwnerTypeTest.zip
It's using Class1 as the owner type now, so it should fail at runtime with a XamlParseException which, if you look at the details, boils down to a System.ArgmumentException saying: "'Class1' type must derive from DependencyObject."
If you don't get that exception, it might be that we're running different versions of .NET or Visual Studio? I'm using .NET 3.5 SP1 and VS2008 SP1Beta1.
hth,
Marcel- Edited by DutchMarcel Thursday, July 10, 2008 7:07 AM wrong link
-
Saturday, July 12, 2008 4:33 PM
Very interesting, very interesting.
If you reduce dependency property registration tothere would be no exception. If you extend the registration using Metadata, the exception will be raised. Strange...public static readonly DependencyProperty IsAvailableProperty = DependencyProperty.Register("IsAvailable", typeof(bool), typeof(Class1));

