I am trying to replicate some C# code which creates an IObservable
from a Button.Click
event.
I want to port this code to F#.
Here is the original C# code which compiles without errors:
Observable.FromEvent<RoutedEventHandler, RoutedEventArgs>(
h => new RoutedEventHandler(h),
h => btn.Click += h,
h => btn.Click -= h))
Here is my failing attempt to do the same in F#:
Observable.FromEvent<RoutedEventHandler, RoutedEventArgs>(
Func<EventHandler<RoutedEventArgs>, RoutedEventHandler>(fun h -> RoutedEventHandler(h)),
Action<RoutedEventHandler>(fun h -> btn.Click.AddHandler h),
Action<RoutedEventHandler>(fun h -> btn.Click.RemoveHandler h))
Everything is happy except for the second line of the statement.
The F# compiler complains about fun h -> RoutedEventHandler(h)
because
it doesn't want to except h
as a parameter to the RoutedEventHandler
constructor.
On th other hand the C# compiler seems to have no problem accepting h => new RoutedEventHandler(h)
Interestingly enough, in both code samples (C# and F#) the type of h
is EventHandler<RoutedEventArgs>
.
The error message I am getting from the F# compiler is:
Error 2 This expression was expected to have type obj -> RoutedEventArgs -> unit but here has type EventHandler
The signature for RoutedEventHandler
that I found inside PresentationCore is:
public delegate void RoutedEventHandler(object sender, RoutedEventArgs e);
As you can see it does take an object
and RoutedEventArgs
as parameters, so the F# compiler is actually correct.
Is there some magic that the C# compiler does behind the scenes to make this work that the F# compiler doesn't or am I just missing something here?
Either way, how can I make this work in F#?
The easiest way I know of to make an
IObservable<_>
out of a WPF Button.Click event is to cast it:Examining obsClick...
This is possible because the F# representation of standard .NET events is the type (in this case)
IEvent<Windows.RoutedEventHandler,Windows.RoutedEventArgs>
. As you can see from the documentation, IEvent implements IObservable. In other words, in F# every single event already is anIObservable
.