This project is read-only.

Maybe some contrib...

Mar 8, 2010 at 5:15 PM

Hi, reactive developers =)

Maybe this WPF-releated stuff may be useful for this project:

namespace System.Windows
{
  public static class ReactiveExtensions
  {
    #region DependencyProperty

    /// <summary>
    /// Returns the observable sequence of the
    /// <see cref="DependencyProperty"/> values.
    /// </summary>
    /// <typeparam name="T">
    /// Observable sequence values type, must be assignable
    /// from the dependency property type.</typeparam>
    /// <param name="property">Dependency property to convert.</param>
    /// <param name="target">Property's owner instance.</param>
    /// <returns><see cref="IObservable{T}"/> sequence.</returns>
    public static IObservable<T> ToObservable<T>(
      this DependencyProperty property,
      DependencyObject target)
    {
      return ToObservable<T>(property, target, false);
    }

    /// <summary>
    /// Returns the observable sequence of the
    /// <see cref="DependencyProperty"/> values.
    /// </summary>
    /// <typeparam name="T">
    /// Observable sequence values type, must be assignable
    /// from the dependency property type.</typeparam>
    /// <param name="property">Dependency property to convert.</param>
    /// <param name="target">Property's owner instance.</param>
    /// <param name="allowAttached">
    /// Indicates that atteched properties should be allowed.</param>
    /// <returns><see cref="IObservable{T}"/> sequence.</returns>
    public static IObservable<T> ToObservable<T>(
      this DependencyProperty property,
      DependencyObject target,
      bool allowAttached)
    {
      if (target == null)
        throw new ArgumentNullException("target");
      if (property == null)
        throw new ArgumentNullException("property");

      // get the dependency property descriptor
      var descriptor = DependencyPropertyDescriptor
        .FromProperty(property, target.GetType());

      if ((descriptor == null) ||
          (descriptor.IsAttached && !allowAttached))
      {
        throw new ArgumentException(
          string.Format(
            "Dependency property '{0}.{1}' is not found at '{2}' type.",
            property.OwnerType.Name, property.Name, target.GetType()));
      }

      // check for type capability
      if (!typeof(T).IsAssignableFrom(descriptor.PropertyType))
      {
        throw new ArgumentException(
          string.Format(
            "Can't create IObservable of '{0}' type " +
            "from the dependency property of type '{1}' .",
            typeof(T), descriptor.PropertyType));
      }

      return Observable.Create<T>(o => {
        EventHandler handler = delegate {
          o.OnNext((T) target.GetValue(property));
        };

        descriptor.AddValueChanged(target, handler);
        return () => descriptor.RemoveValueChanged(target, handler);
      });
    }

    #endregion
    #region RoutedEvents

    /// <summary>
    /// Returns the observable sequence that contains
    /// the values of underlying WPF routed event.
    /// </summary>
    /// <typeparam name="TEventArgs">
    /// Routed event arguments type.</typeparam>
    /// <param name="routedEvent">
    /// <see cref="RoutedEvent"/> to convert.</param>
    /// <param name="element">Routed event owner.</param>
    /// <returns><see cref="IObservable{T}"/> sequence.</returns>
    public static IObservable<IEvent<TEventArgs>>
      ToObservable<TEventArgs>(
        this RoutedEvent routedEvent, UIElement element)
      where TEventArgs : RoutedEventArgs
    {
      if (routedEvent == null)
        throw new ArgumentNullException("routedEvent");
      if (element == null)
        throw new ArgumentNullException("element");

      return Observable.Create<IEvent<TEventArgs>>(o => {
        EventHandler<TEventArgs> genericHandler =
          (sender, e) => o.OnNext(Event.Create(sender, e));

        Delegate handler = Delegate.CreateDelegate(
          routedEvent.HandlerType,
          genericHandler.Target,
          genericHandler.Method,
          false);

        if (handler == null)
        {
          throw new ArgumentException(
            "Can't create correct event handler, use this method " +
            "overload to specify correct event handler type.");
        }

        element.AddHandler(routedEvent, handler);
        return () => element.RemoveHandler(routedEvent, handler);
      });
    }

    /// <summary>
    /// Returns the observable sequence that contains
    /// the values of underlying WPF routed event.
    /// </summary>
    /// <typeparam name="TEventHandler">
    /// Event handler type.</typeparam>
    /// <typeparam name="TEventArgs">
    /// Routed event arguments type.</typeparam>
    /// <param name="routedEvent">
    /// <see cref="RoutedEvent"/> to convert.</param>
    /// <param name="conversion">Conversion of delegate.</param>
    /// <param name="element">Routed event owner.</param>
    /// <returns><see cref="IObservable{T}"/> sequence.</returns>
    public static IObservable<IEvent<TEventArgs>>
      ToObservable<TEventHandler, TEventArgs>(
        this RoutedEvent routedEvent,
        Func<EventHandler<TEventArgs>, TEventHandler> conversion,
        UIElement element)
      where TEventArgs : RoutedEventArgs
      where TEventHandler : class
    {
      if (routedEvent == null)
        throw new ArgumentNullException("routedEvent");
      if (element == null)
        throw new ArgumentNullException("element");
      if (typeof(TEventHandler) != routedEvent.HandlerType)
        throw new ArgumentException(
          "TEventHandler should of routed event handler type.");

      return Observable.Create<IEvent<TEventArgs>>(o => {
        var handler = (Delegate) (object) conversion(
          (sender, e) => o.OnNext(Event.Create(sender, e)));

        element.AddHandler(routedEvent, handler);
        return () => element.RemoveHandler(routedEvent, handler);
      });
    }

    #endregion
  }
}

 

There is a LOT of checks here and some kind of documentation (sorry me my english).

This extensions allows to use Rx with the WPF dependency properties and routed events, for example:

 

 
private void Window_Loaded(object sender, RoutedEventArgs e)
{
  Window1.MouseMoveEvent
    .ToObservable<MouseEventArgs>(this)
    .Select(_ => _.EventArgs.GetPosition(this))
    .Select(_ => string.Format("x: {0}, y: {1}", _.X, _.Y))
    .Subscribe(s => {
      this.textBlock.Text = s;
    });

  TextBlock.TextProperty
    .ToObservable<string>(this.textBlock)
    .Delay(TimeSpan.FromSeconds(1))
    .ObserveOnDispatcher()
    .Subscribe(s => {
      this.textBlock2.Text = s;
    });
}

 

Looks nice, isn't it? =)

I will be very glad if this will contribute this project.

Also I'm ready to post some other useful (maybe) extensions for Rx, if anybody interested.

private void Window_Loaded(object sender, RoutedEventArgs e)
{
  Window1.MouseMoveEvent
    .ToObservable<MouseEventArgs>(this)
    .Select(_ => _.EventArgs.GetPosition(this))
    .Select(_ => string.Format("x: {0}, y: {1}", _.X, _.Y))
    .Subscribe(x => {
      MouseCoords = x;

      RaiseEvent(new FooEventArgs(x));
      this.
    });