2011-02-27 15 views
13

Estoy tratando de replicar algún código C# que crea un IObservable desde un evento Button.Click. Quiero portar este código a F #.Cómo convertir un botón WPF. Haga clic en Evento en Observable usando Rx y F #

Aquí es el código C# original que compila sin errores:

Observable.FromEvent<RoutedEventHandler, RoutedEventArgs>(
            h => new RoutedEventHandler(h), 
            h => btn.Click += h, 
            h => btn.Click -= h)) 

Aquí está mi intento de dejar de hacer lo mismo en C#:

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

Todo está contento con excepción de la segunda línea de la declaración.

El F # compilador se queja de fun h -> RoutedEventHandler(h) porque que no quiere excepto h como un parámetro para el constructor de RoutedEventHandler.

En ª otro lado el compilador de C# parece tener ningún problema en aceptar h => new RoutedEventHandler(h)

Curiosamente, en ambos ejemplos de código (C# y F #) del tipo de h es EventHandler<RoutedEventArgs>.

El mensaje de error que estoy recibiendo de la F # compilador es:

de error 2 Se esperaba que esta expresión para tener tipo obj -> RoutedEventArgs -> unidad, pero aquí tiene tipo manejador de sucesos

El RoutedEventHandler firma para que me encontré dentro PresentationCore es:

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

Como puede ver, toma un object y RoutedEventArgs como parámetros, por lo que el compilador F # es realmente correcto.

¿Hay alguna magia que el compilador C# haga entre bastidores para hacer que esto funcione que el compilador F # no lo hace o me falta algo aquí?

De cualquier manera, ¿cómo puedo hacer que esto funcione en F #?

Respuesta

17

La forma más sencilla que conozco para hacer una IObservable<_> de un evento de WPF Button.Click es para su emisión: obsClick

open System 
open System.Windows.Controls 

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

Examinar ...

val obsClick : IObservable<Windows.RoutedEventArgs> 

Esto es posible porque la representación F # de eventos .NET estándar es el tipo (en este caso) IEvent<Windows.RoutedEventHandler,Windows.RoutedEventArgs>. Como puede ver en la documentación, IEvent implements IObservable. En otras palabras, en F #, cada evento individual ya es IObservable.

6

Joel Mueller es el clavo, por lo que sólo para el registro: una traducción directa del código C# sería

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

Gracias, mirando el código C# en el reflector me hizo comprender que 'h' en realidad se expandió a 'h.Invoque ', que luego se trata como un grupo de métodos que representa' (s, e) => h.Invocar (s, e) 'y por lo tanto satisface la firma RoutedEventHandler. Una vez que está claro, es obvio que tiene razón con la implementación sugerida de F #. También estoy de acuerdo en que la conversión menos detallada sugerida por Joel Mueller es preferible a menos que necesite contactar al remitente directamente (por ejemplo, no a través de args.Source), ya que solo devuelve un IObservable de RoutedEventArgs. –

Cuestiones relacionadas