A very common idiom in WPF/Silverlight is the attached property. Attached properties are properties that only have meaning in certain contexts, usually in relation to another class. Attached properties are everywhere in WPF/Silverlight. Although they are widely useful they are most commonly used with layout panels. By introducing the notion of attached properties the architects of WPF were able to avoid having to add every conceivable property for every conceivable layout panel to each control (Top, Left, Grid Column, Grid Row, Rotation, and so on).
Of course neither the CLR nor C# has any notion of attached properties. Therefore attached properties are typically implemented using a pair of static set and get methods on the Layout class. These static setter/getter methods use a static dictionary to link a control to its attached property value. As an example the Canvas panel lays controls out in a Cartesian coordinate system and has a Left attached property and a Top attached property. Specifying these properties on a control looks something like this in C#:
Canvas.SetLeft(myTextBox, 23.0); Canvas.SetTop(myTextBox,24.0); myCanvas.Children.Add(myTextBox);
This works but it isn't ideal. For one thing attached properties are not discoverable because they do not show up in the control’s intellisense list. However the real issue though is that the code is too low-level, exposing the developer to the implementation of attached properties rather than simply letting them express their intent.
F# has the notion of extension properties. Like extension methods in C#, extension properties can be defined on a class outside of the class definition. So with the smallest dab of code...
type UIElement with member this.Left with get() = Canvas.GetLeft(this) and set(value) = Canvas.SetLeft(this, value) member this.Top with get() = Canvas.GetTop(this) and set(value) = Canvas.SetTop(this, value)
…I can do this…
myTextBox.Left <- 23.0 myTextBox.Top <- 24 myCanvas.Children.Add(myTextBox)
Much better. Now the properties belong to the control but like extension methods they only appear when the assembly with Canvas is imported. Unfortunately with the current build of F# you can't use attached properties in object expressions like this...
Image(Uri = Uri(“test.png”), Left = x * 20, Top = x * 40)
...however I've been assured by Don Syme himself that this will be fixed by VS 2010 Beta 2.
So there you have it. An admittedly small, but very nice trick. More to follow.