Как преобразовать событие WPF Button.Click в Observable с помощью Rx и F #
Я пытаюсь реплицировать некоторый код С#, который создает IObservable
из события Button.Click
.
Я хочу передать этот код в F #.
Вот исходный код С#, который компилируется без ошибок:
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
.
С другой стороны, у компилятора С# нет проблем с принятием h => new RoutedEventHandler(h)
Интересно, что в обоих образцах кода (С# и F #) тип h
равен EventHandler<RoutedEventArgs>
.
Сообщение об ошибке, которое я получаю от компилятора F #:
Ошибка 2 Это выражение должно было иметь тип obj → RoutedEventArgs → unit, но здесь есть тип EventHandler
Подписи для RoutedEventHandler
, которые я нашел внутри PresentationCore, это:
public delegate void RoutedEventHandler(object sender, RoutedEventArgs e);
Как вы можете видеть, он принимает параметры object
и RoutedEventArgs
, поэтому компилятор F # на самом деле правильный.
Есть ли какая-то магия, которую компилятор С# делает за кулисами, чтобы сделать эту работу компилятором F # или я просто что-то пропустил здесь?
В любом случае, как я могу сделать эту работу в F #?
Ответы
Ответ 1
Самый простой способ, с помощью которого я могу сделать 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
.
Ответ 2
Джоэл Мюллер находится на месте, поэтому только для записи: прямой перевод кода на С# будет
Observable.FromEvent(
(fun h -> RoutedEventHandler(fun sender e -> h.Invoke(sender, e))),
(fun h -> b.Click.AddHandler h),
(fun h -> b.Click.RemoveHandler h)
)