2011-02-27 67 views
13

我試圖複製一些從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);

正如你所看到的,它確實需要objectRoutedEventArgs作爲參數,所以F#編譯器實際上是正確的。

C#編譯器在幕後做了些什麼以使F#編譯器不工作或我只是在這裏丟失什麼?

無論哪種方式,我如何使這項工作在F#?

回答

17

我知道的最簡單的方法,使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

6

喬爾·穆勒是現貨,所以僅僅是爲了記錄: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) 
) 
+0

謝謝,看着反射的C#代碼讓我意識到,「H」實際上得到擴大到'h。Invoke',然後將其視爲代表'(s,e)=> h.Invoke(s,e)'的方法組,從而滿足RoutedEventHandler簽名。一旦明確,很明顯,你用你建議的F#實現就是正確的。 我也同意,Joel Mueller建議的較爲詳細的轉換是首選,除非您需要直接獲取發件人的持有者(例如,不通過args.Source),因爲它只返回RoutedEventArgs的IObservable。 – 2011-02-27 17:31:02

相關問題