Creating WPF Dependency Properties in F#

This is a quick post demonstrating how to create WPF Dependency Properties in F#. There is a bit of a trick to it as you have to use the val keyword to define a field and that field must be mutable and you also have to use explicit interface access.

An example is easier than an explanation!

  open System.Windows
  open System.Windows.Controls
  
  type CustomControl() =
    inherit FrameworkElement()
    
    [<DefaultValue(false)>]
    static val mutable OrientationProperty:DependencyProperty
    
    static do 
      (CustomControl.OrientationProperty 
        <- DependencyProperty.Register
          ("Orientation", typeof<Orientation>, typeof<CustomControl>,
           new FrameworkPropertyMetadata(Orientation.Horizontal)))
    
    let toDep x = x :> DependencyObject
    
    member self.Orientation
      with get() = (self |> toDep).GetValue(Axis.OrientationProperty) :?> Orientation
      and  set (x:Orientation) = (self |> toDep).SetValue(Axis.OrientationProperty, x)

The key considerations are as follows:

  • The static field for the dependency property must be declared as static val mutable and must also have the DefaultValue attribute. The attribute has the argument false because the value will be created by the static constructor rather than as a default value
  • The initialization of the static property is wrapped in parentheses because otherwise the F# syntax is incorrect
  • Because access of the GetValue and SetValue methods use the DependencyObject class methods, it is necessary to cast the instance object to DependencyObject (a little F# semantic), and so toDep is a helper function for that purpose
  • In other .NET languages you need to cast the result of GetValue and the same is true here, but because it is a runtime cast you need the dynamic operator “:?>” and not the static one “:>”

The following links have more information about dependency properties:

You may also find the F# specification (section 8.5.4) useful if you want to know more about creating interoperable class fields (as opposed to methods and properties).

Advertisements

6 thoughts on “Creating WPF Dependency Properties in F#

  1. Pingback: Rick Minerich's Development Wonderland : F# Discoveries This Week 08/16/2009

  2. Sebastian U

    Huh!? Why not use “static let”? And – sorry – the part about Get/SetValue is just plain wrong…

    type CustomControl() =
    inherit FrameworkElement()

    static let OrientationProperty =
    DependencyProperty.Register(“Orientation”, typeof, typeof,
    new FrameworkPropertyMetadata(Orientation.Horizontal))

    member self.Orientation
    with get() = self.GetValue(OrientationProperty) :?> Orientation
    and set (x:Orientation) = self.SetValue(OrientationProperty, x)

    Reply
    1. Steve Horsfield Post author

      All fields created with “let” are private. Although F# will generally create fields, the draft F# specification says that the creation of fields is optional. (I have noticed that the MSDN documentation for VS 2010 Beta 1 suggests this behaviour is guaranteed). The XAML engine requires (or at least expects) that the dependency fields are public as it will bypass the property getters/setters. See the section The WPF XAML Loader Implementation, and Performance in http://msdn.microsoft.com/en-us/library/bb613563.aspx.

      Regarding base members, you may be correct. In general, interfaces methods must be cast to (like explicit interface implementations in C#) but as these are base class methods the same may not be true: I need to check.

      Thanks for the comment.

      Reply
      1. Sebastian U

        Interesting, I never realized vals defaulted to public – actually pretty awkward, I think :) .
        However, as the article you linked to states, XAML doesn’t need a field at all – you could throw away the result of Register, the DP would still be accessible. For the rare case where you need programmatic access to the DependencyProperty instance, you can expose the let via a “static member”. Still a bit more readable than val.

        PS: Didn’t get any reply notification mails :( .

      2. Steve Horsfield Post author

        Yes, the field is not necessary for XAML, but it is helpful for type documentation (not sure if the XAML processor investigates this) and for native .NET access.

        I’m not sure if defaulting to “private” is good behaviour for “val” (in implementation files, not signatures) but it sure is good that we can force the creation of a field!

        PS. Not sure why e-mail notification isn’t working. I get the notifications, but then that’s just me!

    2. Steve Horsfield Post author

      Hi Sebastian,

      I’ve checked the behaviour with SetValue and it does work without the explicit cast, as you say. This is also in agreement with the F# draft specification (14.1.4 Name Resolution for Members), so my mistake. Interfaces behave slightly differently and are often not accessible (for example IAddChild in System.Windows.Markup) so I got carried away with the casts.

      Thanks for pointing out my error,

      Steve

      Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s