如何使用Rx和F#将WPF Button.Click事件转换为Observable

Tho*_*enz 14 wpf f# routedevent system.reactive

我试图复制一些C#代码,它创建IObservable一个Button.Click事件.我想将此代码移植到F#.

这是原始的C#代码,它编译时没有错误:

Observable.FromEvent<RoutedEventHandler, RoutedEventArgs>(
                                    h => new RoutedEventHandler(h),
                                    h => btn.Click += h,
                                    h => btn.Click -= h))
Run Code Online (Sandbox Code Playgroud)

这是我在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))
Run Code Online (Sandbox Code Playgroud)

除了声明的第二行,一切都很愉快.

F#编译器抱怨,fun h -> RoutedEventHandler(h)因为它不希望除了h作为RoutedEventHandler构造函数的参数.

另一方面,C#编译器似乎没有接受的问题 h => new RoutedEventHandler(h)

有趣的是,在两个代码示例(C#和F#)中,类型h都是EventHandler<RoutedEventArgs>.

我从F#编译器获取的错误消息是:

错误2此表达式应该具有类型obj - > RoutedEventArgs - > unit但这里有类型EventHandler

RoutedEventHandler我在PresentationCore中找到的签名是:

public delegate void RoutedEventHandler(object sender, RoutedEventArgs e);

正如您所看到的,它确实需要一个objectRoutedEventArgs作为参数,因此F#编译器实际上是正确的.

是否有一些魔术,C#编译器在幕后做了F#编译器没有的工作,或者我在这里错过了什么?

无论哪种方式,我怎样才能在F#中完成这项工作?

Joe*_*ler 17

我知道的最简单的方法IObservable<_>是使用WPF Button.Click事件来构建它:

open System
open System.Windows.Controls

let btn = new Button()
let obsClick = btn.Click :> IObservable<_>
Run Code Online (Sandbox Code Playgroud)

检查obsClick ...

val obsClick : IObservable<Windows.RoutedEventArgs>
Run Code Online (Sandbox Code Playgroud)

这是可能的,因为标准.NET事件的F#表示是类型(在本例中)IEvent<Windows.RoutedEventHandler,Windows.RoutedEventArgs>.从文档中可以看出,IEvent实现了IObservable.换句话说,在F#中,每个事件都已经是一个IObservable.


Seb*_*ich 6

Joel Mueller很有见,所以只是为了记录:直接翻译C#代码

Observable.FromEvent(
    (fun h -> RoutedEventHandler(fun sender e -> h.Invoke(sender, e))),
    (fun h -> b.Click.AddHandler h),
    (fun h -> b.Click.RemoveHandler h)
)
Run Code Online (Sandbox Code Playgroud)