Gotcha: Silverlight DependencyProperty metadata: 0d not 0 for double
Just came accross a runtime error message that troubled me a bit to resolve while adding Prezi-like content scaling functionality in ClipFlair‘s FloatingWindowHostZUI (ZUI = Zoomable User Interface) container.
I had added the following:
/// Identifies the <see cref="FloatingWindow.Scale" /> dependency property. /// </summary> /// <value> /// The identifier for the <see cref="FloatingWindow.Scale" /> dependency property. /// </value> public static readonly DependencyProperty ScaleProperty =
DependencyProperty.Register(
"Scale",
typeof(double),
typeof(FloatingWindow),
new PropertyMetadata(0d, OnScalePropertyChanged));
in the context of adding a dependency property (with some extra code for OnScalePropertyChanged static method and for Scale property that calls GetValue/SetValue methods of Control’s far ancestor DependencyObject to update the ScaleProperty).
It seems that the issue was that I was setting a default value of 0 (an integer in C#) instead of 0d (a double – for float type one would use 0f instead). The strange exception returned was saying:
Failed to create a ‘System.Windows.DependencyProperty’ from the text ‘Width’. [Line: 10 Position: 44]
and was pointing me to line 24 of FloatingWindow.cs (obviously the line 10 mentioned in the message meant in some XAML file, but failed to mention which XAML file – or at least say “near …” copying some part the context of the XAML stream, similar to how some server-side scripting languages do).
Clicking “View detail” on the (bad in terms of usability) exception dialog of Visual Studio, I saw in another window a XamlParseException with the following content (alternatively one could expand the tree shown there and examine just the InnerException node’s content there):
{System.Windows.Markup.XamlParseException: Failed to create a ‘System.Windows.DependencyProperty’ from the text ‘Width’. [Line: 10 Position: 44] —> System.TypeInitializationException: The type initializer for ‘SilverFlow.Controls.FloatingWindow’ threw an exception. —> System.ArgumentException: Default value type does not match type of property.
at System.Windows.DependencyProperty.Register(Boolean fIsAttachedDP, String name, Type propertyType, Type ownerType, PropertyMetadata propertyMetadata, Boolean readOnly)
at System.Windows.DependencyProperty.Register(String name, Type propertyType, Type ownerType, PropertyMetadata typeMetadata)
at SilverFlow.Controls.FloatingWindow..cctor()
— End of inner exception stack trace —
at System.Runtime.CompilerServices.RuntimeHelpers._RunClassConstructor(RuntimeType type)
at System.Windows.DependencyProperty.QueryRegisteredProperty(String name, Type ownerType)
at MS.Internal.ManagedTypeInfoProviderRPInvokes.LookupDependencyProperty(Type type, String name)
at MS.Internal.ManagedTypeInfoProviderRPInvokes.ResolveDependencyPropertyName(XamlTypeToken sTypeToken, String inPropertyName, XamlPropertyToken& outProperty, XamlTypeToken& outPropertyTypeToken)
— End of inner exception stack trace —
at System.Windows.Application.LoadComponent(Object component, Uri resourceLocator)
at FloatingWindowZUI.Demo.App.InitializeComponent()
at FloatingWindowZUI.Demo.App..ctor()}
Now why it was saying "from the text Width", I guess it’s something in the XAML template of the control, but I really am not sure – it sure was very misleading to say that, since it had nothing to do with the issue.
Moreover DependencyProperty.Register could have been implemented better to force implicit type conversions in such cases (by having several overloaded versions to accept primitive datatypes such as float and double – probably its a victim of the effort to keep Silverlight installer small).
It seems this design is the reason DependencyProperty snippets usually have an explicit type cast at call PropertyMetadata constructor, e.g. one could also use “new PropertyMetadata((double)0, …” instead of “new PropertyMetadata(0d, …”.
Update:
BTW, using 0d as the default value for a Scale property as I originally was doing above isn’t a good idea, since scale factor is practically a multiplier and you can get really strange results. Better use 1d (scale factor 1) which is more logical after all as a default scale value.
-
2012/08/15 at 19:02HowTo: Scale control arround its center using a render transform « George Birbilis @zoomicon