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

发布于 2024-10-19 22:47:30 字数 1629 浏览 4 评论 0原文

我正在尝试复制一些从 Button.Click 事件创建 IObservable 的 C# 代码。 我想将此代码移植到 F#。

这是编译时没有错误的原始 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 作为 RoatedEventHandler 构造函数的参数。

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

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

我从 F# 编译器收到的错误消息是:

错误 2 该表达式的类型应为 obj -> RoutedEventArgs -> 路由事件参数单位但这里有类型 EventHandler

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

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

正如你所看到的,它确实需要objectRoulatedEventArgs 作为参数,因此 F# 编译器实际上是正确的。

C# 编译器是否在幕后执行了一些 F# 编译器无法执行的操作,或者我只是在这里遗漏了一些东西?

不管怎样,我怎样才能在 F# 中实现这个功能呢?

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#?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

鱼忆七猫命九 2024-10-26 22:47:30

据我所知,从 WPF Button.Click 事件中创建 IObservable<_> 的最简单方法是对其进行强制转换:

open System
open System.Windows.Controls

let btn = new Button()
let obsClick = btn.Click :> IObservable<_>

检查 obsClick...

val obsClick : IObservable<Windows.RoutedEventArgs>

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

The easiest way I know of to make an IObservable<_> out of a WPF Button.Click event is to cast it:

open System
open System.Windows.Controls

let btn = new Button()
let obsClick = btn.Click :> IObservable<_>

Examining obsClick...

val obsClick : IObservable<Windows.RoutedEventArgs>

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 an IObservable.

风为裳 2024-10-26 22:47:30

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)
)

Joel Mueller is spot on, so just for the record: a direct translation of the C# code would be

Observable.FromEvent(
    (fun h -> RoutedEventHandler(fun sender e -> h.Invoke(sender, e))),
    (fun h -> b.Click.AddHandler h),
    (fun h -> b.Click.RemoveHandler h)
)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文