如何使用Rx和F将WPF Button.Click事件转换为Observable#
我试图复制一些从Button.Click
事件创建IObservable
的C#代码。 我想将此代码移植到F#。如何使用Rx和F将WPF Button.Click事件转换为Observable#
这里是原来的C#代码编译没有错误:
Observable.FromEvent<RoutedEventHandler, RoutedEventArgs>(
h => new RoutedEventHandler(h),
h => btn.Click += h,
h => btn.Click -= h))
这是我没有尝试做相同的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))
一切,除了第二行快乐该声明。
F#编译器会抱怨,因为fun h -> RoutedEventHandler(h)
它 并不想除了h
作为参数的构造函数RoutedEventHandler
。
在th另一方面C#编译器似乎也没有问题接受h => new RoutedEventHandler(h)
有趣的是,这两个代码的样品(C#和F#)的h
类型是EventHandler<RoutedEventArgs>
英寸
我从F#编译器得到的错误信息是:
错误2,预计这种表达有型的obj - > RoutedEventArgs - >单元,但这里有EventHandler类型
的为RoutedEventHandler
,我发现里面PresentationCore签名是:
public delegate void RoutedEventHandler(object sender, RoutedEventArgs e);
正如你所看到的,它确实需要object
和RoutedEventArgs
作为参数,所以F#编译器实际上是正确的。
C#编译器在幕后做了些什么以使F#编译器不工作或我只是在这里丢失什么?
无论哪种方式,我如何使这项工作在F#?
我知道的最简单的方法,使IObservable<_>
了WPF Button.Click事件是投它:
open System
open System.Windows.Controls
let btn = new Button()
let obsClick = btn.Click :> IObservable<_>
检查obsClick ...
val obsClick : IObservable<Windows.RoutedEventArgs>
这是可能的,因为标准.NET事件的F#表示是类型(在本例中)为IEvent<Windows.RoutedEventHandler,Windows.RoutedEventArgs>
。正如你可以从文档中看到的那样,IEvent implements IObservable。换句话说,在F#中,每个事件已经是IObservable
。
乔尔·穆勒是现货,所以仅仅是为了记录: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)
)
谢谢,看着反射的C#代码让我意识到,“H”实际上得到扩大到'h。Invoke',然后将其视为代表'(s,e)=> h.Invoke(s,e)'的方法组,从而满足RoutedEventHandler签名。一旦明确,很明显,你用你建议的F#实现就是正确的。 我也同意,Joel Mueller建议的较为详细的转换是首选,除非您需要直接获取发件人的持有者(例如,不通过args.Source),因为它只返回RoutedEventArgs的IObservable。 – 2011-02-27 17:31:02