I am wandering if there is a way of hooking an event defined in XAML to a F# function of member ? Of course, I could do it diagrammatically but it is kind of inconvenient.
-
I am unclear about what is being asked; if you have some XAML code and maybe e.g. the corresponding C# code to demonstrate what you are talking about, it may help get an answer. – Brian Nov 10 '10 at 22:19
-
1I hope that _diagrammatically_ has nothing to do with category theory :-) – Tomas Petricek Nov 10 '10 at 22:32
4 Answers
I suppose the question is whether you can specify F# member as an event handler using XAML markup:
<Button x:Name="btnClick" Content="Click!" Click="button1_Click" />
As far as I know, the answer is No.
The way this works in C# is that the registration of event handler is done in C# code (partial class) generated by the designer (you can see that in the obj
directory in files named e.g. MainForm.g.cs
). F# doesn't have any direct support for WPF designer, so it cannot generate this for you. You'll have to write the code to attach event handlers by hand (but that's quite easy).
I have some examples in my London talk about Silverlight. You can implement the ?
operator to get nice access to the XAML elements:
type MainPage() as this =
inherit UserControl()
let uri = new System.Uri("/App;component/MainPage.xaml", UriKind.Relative)
do Application.LoadComponent(this, uri)
// Get button using dynamic access and register handler
let btn : Button = this?btnClick
do btnClick.Click.Add(fun _ -> (* ... *))
The ?
operator declaration that I used is:
let (?) (this : Control) (prop : string) : 'T = // '
this.FindName(prop) :?> 'T

- 240,744
- 19
- 378
- 553
-
Thank-you for the example, the operator is handy. It is was what I though but I was not clear in my mind. Could the x:Subclass attribute be of some help ? – user503775 Nov 11 '10 at 19:55
It is possible to add binding to a command, eg. using the Command="..." property in the button.
So in you XAML you can have:
<Button Command="{Binding MyCommandHandler}">
Then in your ViewModel code, if you have a member called MyCommandHandler, it'll be bound to the above button. So in your F#, something like:
module ViewModel =
type FuncCommand (canExec:(obj -> bool), doExec:(obj -> unit)) =
let theEvent = new DelegateEvent<EventHandler>()
interface ICommand with
[<CLIEvent>]
member x.CanExecuteChanged = theEvent.Publish
member x.CanExecute arg = canExec(arg)
member x.Execute arg = doExec(arg)
type MyViewModel() =
member this.MyCommandHandler =
new FuncCommand(
(fun _ -> ... SOME CODE WHICH RETURNS TRUE OR FALSE ...),
(fun _ -> ... SOME CODE TO HANDLE THE CLICK ...)
)

- 5,703
- 4
- 29
- 55
You can do it using an attached property:
namespace Foo
open System.Windows
open System.Windows.Controls
open System.Windows.Controls.Primitives
open System.Windows.Media
module Register =
// http://stackoverflow.com/a/14706890/1069200
type internal Marker = interface end
let ClickHandlerProperty = DependencyProperty.RegisterAttached(
"ClickHandler",
typeof<RoutedEventHandler>,
typeof<Marker>.DeclaringType,
PropertyMetadata(null))
let SetClickHandler (element: UIElement, value : RoutedEventHandler) =
element.SetValue(ClickHandlerProperty, value)
let GetClickHandler (element: UIElement) : RoutedEventHandler =
element.GetValue(ClickHandlerProperty) :?> _
let private OnClick (sender : obj) args =
let button = sender :?> UIElement
let handler = GetClickHandler button
if not (obj.ReferenceEquals(handler, null)) then
handler.Invoke(sender, args)
let private initialize =
EventManager.RegisterClassHandler(
typeof<FrameworkElement>,
ButtonBase.ClickEvent,
RoutedEventHandler(OnClick))
Then use it in xaml like this:
<Window ...
xmlns:foo="clr-namespace:Foo;assembly=Foo">
<Button Content="Click!" foo:Register.ClickHandler="{x:Static foo:Bar.OnClicked}" />
</Window>
Where bar is:
namespace Foo
open System.Windows
module Bar =
let OnClicked =
let onClick _ _ = MessageBox.Show "clicked" |> ignore
RoutedEventHandler(onClick)
I don't know f# so the above code can probably be cleaned up a lot.
For the click event David's suggestion to bind the command is probably nicest.

- 17,112
- 9
- 74
- 88
-
Trying this example but getting XAML parser error: "The attachable property 'ClickHandler' was not found in type 'Register'". Any ideas? – Dmitry G. Dec 18 '16 at 16:07
-
Have you added `xmlns:foo="clr-namespace:YourAssemblyName;assembly=YourAssemblyName"`? – Johan Larsson Dec 18 '16 at 16:48
-
I found that `Register` is not really necessary. Adding a handler directly also works. E.g. `MouseDoubleClick="{x:Static local:Bar.OnDoubleClicked}"` – Dmitry G. Dec 28 '16 at 03:55
-
This is now supported in the newer versions of FsXaml, though it works slightly differently than it does in C#.
Using FsXaml, you can define your Xaml and specify your event handler. For example, in a window named "MyWindow", you can do:
<Button Content="Click!" Click="button1_Click" />
In your "code behind" file, you would handle this like so:
type MyWindowBase = XAML<"MyWindow.xaml">
type MyWindow () =
inherit MyWindowBase
override this.button1_Click (_,_) = () // Handle event here

- 554,122
- 78
- 1,158
- 1,373
-
1Is this documented in detail anywhere? Doesn't work for all controls (e.g. ListBox). – MiloDC Jul 02 '19 at 01:51