WinRT vs. Silverlight - Part 3 - Dependency Properties

See intro blogpost here.

UPDATE Feb. 29, 2012: As hinted at below that this would happen, this blogpost on dependency properties is now outdated. Since the Consumer Preview of Windows 8 released, dependency properties now work exactly like they do in Silverlight and WPF.

---

Declaration of dependency properties has changed in the WinRT. This is a temporary change and will go away when WinRT hits beta, but still good to know if you start prototyping on WinRT today. If you are a control developer this is probably one of the things you would have to change in the most places.

Here’s what the API looks like for Silverlight and WPF for registering a Dependency Property or an Attached Property:

public static DependencyProperty Register(
      string name, 
      Type propertyType, 
      Type ownerType,
      PropertyMetadata typeMetadata);
public static DependencyProperty RegisterAttached(
      string name, 
      Type propertyType,
      Type ownerType, 
      PropertyMetadata defaultMetadata);

And here’s what this currently looks like in WinRT CTP :

public static DependencyProperty Register(
      string name, 
      string propertyTypeName, 
      string ownerTypeName,
      PropertyMetadata typeMetadata);
public static DependencyProperty RegisterAttached(
      string name, 
      string propertyTypeName,
      string ownerTypeName, 
      PropertyMetadata defaultMetadata);

Notice how the PropertyType and PropertyOwnerType is now strings instead of types!

This means you would have to write your code like this to make it cross-compile:

        public double MyDoubleProperty
        {
            get { return (double)GetValue(MyDoublePropertyProperty); }
            set { SetValue(MyDoublePropertyProperty, value); }
        }

        public static readonly DependencyProperty MyDoublePropertyProperty =
            DependencyProperty.Register("MyDoubleProperty", 
#if NETFX_CORE
             "Double", "MyNamespace.MyControl", 
#else
                typeof(double), typeof(MyNamespace.MyControl), 
#endif
                 new PropertyMetadata(0d));

Also note that you don’t use the full type name for the system types. Ie. here you use “Double” and not “double” or “System.Double”.

You could create a few static methods to replace the Register/RegisterAttached methods that will make your code cross-platform, and switch it out just there when this changes. Here’s one example how this could be accomplished (the ‘ToRTString’ method isn’t fully tested though…):

    public static DependencyProperty RegisterAttached(string name, Type propertyType, Type ownerType, PropertyMetadata metadata)
    {
        return DependencyProperty.RegisterAttached(name, 
#if NETFX_CORE
            propertyType.ToRTString(), ownerType.ToRTString()
#else
            propertyType, ownerType
#endif
            , metadata);
    }
    public static DependencyProperty Register(string name, Type propertyType, Type ownerType, PropertyMetadata metadata)
    {
        return DependencyProperty.Register(name,
#if NETFX_CORE
            propertyType.ToRTString(), ownerType.ToRTString()
#else
            propertyType, ownerType
#endif
            , metadata);
    }
#if NETFX_CORE
    private static string ToRTString(this Type type)
    {
        string name = type.FullName;
        if(name.StartsWith("System."))
            return name.Substring(7);
        else
            return name;
    }
#endif

Comments (12) -

  • Very nice blog series - thanks for that!

    I found an error In the WPF/SL prototype of the Register method the propertyType parameter should be Type instead of string.

    Regards,
    Miroslav Nedyalkov.
  • Miroslav: What do you mean? The type IS of type "type" in SL/WPF scenarios. That's what that "#if WINRT" is taking care of.
  • Morten, I was talking about the declaration of the Register method in Silverlight/WPF, not about the code. This is just after the text "Here’s what the API looks like for Silverlight and WPF for registering a Dependency Property or an Attached Property:".
  • Miroslav: Oh right. Good catch. That's fixed now. Thanks!
  • Thanks for sharing your experience!

    I am facing a strange problem with a NullReferenceException, generated upon registering a DependencyProperty:

    public class MyControl : Control
    {
        public static readonly DependencyProperty MyDoubleProperty =
            DependencyProperty.Register("MyDouble", "Double", typeof(MyControl).FullName, new PropertyMetadata(0d));

        public double MyDouble
        {
            get
            {
                return (double)this.GetValue(MyDoubleProperty);
            }
            set
            {
                this.SetValue(MyDoubleProperty, value);
            }
        }
    }

    Have you faced the same problem and if not do you have any clues what I may be doing wrong?

    Thanks in advance!
  • Hi Georgi,

    I'm note sure if this could be the problem, but why not use typeof(double).FullName instead of "Double"?
  • Miroslab: Here's where it gets weird. For system types you are supposed to use "Double" instead of "System.Double" that .FullName is returning.
    Georgi: Code looks ok to me. Are there any other code in that control or in your xaml that could be the cause of this?
  • @Morten: Thanks for your reply. I am testing on a clean new app solution and have this "MyControl" class only (without any XAML). The exception continues to appear and I am currently out of ideas. Another interesting pitfall is that I am unable to specify a Style for MyControl - neither through XAML, nor in code:

    Style style = new Style();
    style.TargetType = typeof(MyControl);

    This will generate HRESULT E_FAIL COM exception.

    I have the feeling that I have to register this new type in COM in some way but I have no clue how.

    Do you experience these two exceptions on your side, setting up the same scenario?
  • Could you please provide any sample for a C# class containing attached property that is actually compiling and working at runtime? Nothing from your article helps, it seems that attached properties are not working neither from XAML nor code behind.
  • The Dependency property registration in WinRT as given in this post works fine with system types like Double, Boolean.  But for the Custom type like enum, class properties it thorws TypeInitilaizationException. I used the code as follows:


    I register the dependency property with custom type as follows :

    public SizeMode SizeMode
            {
                get { return (SizeMode)GetValue(SizeModeProperty); }
                set { SetValue(SizeModeProperty, value); }
            }

            public static readonly DependencyProperty SizeModeProperty =
    DependencyProperty.Register("SizeMode", "Syncfusion.Windows.Tools.Controls.SizeMode", "Syncfusion.Windows.Tools.Controls.ButtonAdv", new PropertyMetadata("Normal", new PropertyChangedCallback(OnSizeFormChanged)));

    And the SizeMode enum defined with in the same namespace as follows.

    public enum SizeMode
            {            
                Normal,            
                Small,
                Large
            }

    It complies fine. but at runtime it throws TypeInitializationException. Any Solution ?
  • Hi Morten, great post.  Do you have any examples of where you actually bind to the property in the XAML for the control itself?  I noticed WinRT doesn't have RelativeSource-Self binding anymore, which is how it was done in WPF.  
  • Happy to see that all of these problems are fixed in the consumer preview version!

Pingbacks and trackbacks (3)+

Add comment