When creating a desktop application with WPF using F# there are a number of options:
For small desktop applications, the last option, creating WPF elements directly from F# can produce good self-contained code, but at time is a little less readable than the XAML equivalent. Lets consider placing a button bound to a command on a grid at a certain position.
The XAML fragment might look like this:
<Button Content="_1" Command="{Binding Key1Command}"
Grid.Column="0" Grid.Row="2"/>
Code equivalent:
let button = Button(Content="_1")
button.SetBinding(Button.CommandProperty,Binding("Key1Command")) |> ignore
Grid.SetColumn(button,0)
Grid.SetRow(button,2)
Code equivalent using (+) operator overloads to add the dependency properties:
Button(Content="_1") + Button.Command(Binding "Key1Command")
+ Grid.Column 0 + Grid.Row 2
The glue is just a couple of classes that define a dependency property and value/binding pair with a (+) operator overload that sets the value on the target WPF element.
For Dependency Property values:
type DependencyPropertyValuePair(dp:DependencyProperty,value:obj) =
member this.Property = dp
member this.Value = value
static member (+)
(target:#UIElement,pair:DependencyPropertyValuePair) =
target.SetValue(pair.Property,pair.Value)
target
For Dependency Property bindings:
type DependencyPropertyBindingPair(dp:DependencyProperty,binding:BindingBase) =
member this.Property = dp
member this.Binding = binding
static member (+)
(target:#FrameworkElement,pair:DependencyPropertyBindingPair) =
target.SetBinding(pair.Property,pair.Binding) |> ignore
target
Finally relevant WPF types must be extended with helper methods (note: this could be code generated):
type Grid with
static member Column (value:int) =
DependencyPropertyValuePair(Grid.ColumnProperty,value)
static member Row (value:int) =
DependencyPropertyValuePair(Grid.RowProperty,value)
Attached is a sample calculator VS2010 project showing the mechanism in action.
Calculator.zip (3.57 kb)