Как преобразовать событие WPF Button.Click в Observable, используя Rx и F # - PullRequest
14 голосов
/ 27 февраля 2011

Я пытаюсь скопировать некоторый код C #, который создает IObservable из события Button.Click.Я хочу перенести этот код на 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 в качестве параметра для конструктора 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);

Как вы можете видеть, он принимает object и RoutedEventArgs в качестве параметров, поэтому компилятор F # действительно корректен.

Есть ли какая-то магия, которую компилятор C # делает за кулисами, чтобы сделать эту работу, чего не делает компилятор F #, или я просто что-то здесь упускаю?

В любом случае, как мне сделатьэта работа в F #?

Ответы [ 2 ]

17 голосов
/ 27 февраля 2011

Самый простой из известных мне способов сделать 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>

Это возможно, потому что F # представление стандартных событий .NET является типом (в данном случае) IEvent<Windows.RoutedEventHandler,Windows.RoutedEventArgs>. Как видно из документации, IEvent реализует IObservable . Другими словами, в F # каждое отдельное событие уже является IObservable.

6 голосов
/ 27 февраля 2011

Джоэл Мюллер на месте, так что просто для записи: прямой перевод кода 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)
)
...