// ----------------------------------------------------------------------- // // Copyright 2014 MIT Licence. See licence.md for more information. // // ----------------------------------------------------------------------- namespace Perspex.Interactivity { using System; using System.Collections.Generic; using System.Linq; using System.Reactive; using System.Reactive.Linq; using Perspex.Layout; public class Interactive : Layoutable, IInteractive { private Dictionary> eventHandlers = new Dictionary>(); public void AddHandler(RoutedEvent routedEvent, Delegate handler) { Contract.Requires(routedEvent != null); Contract.Requires(handler != null); List delegates; if (!this.eventHandlers.TryGetValue(routedEvent, out delegates)) { delegates = new List(); this.eventHandlers.Add(routedEvent, delegates); } delegates.Add(handler); } public IObservable> GetObservable(RoutedEvent routedEvent) where T : RoutedEventArgs { Contract.Requires(routedEvent != null); return Observable.FromEventPattern( handler => this.AddHandler(routedEvent, handler), handler => this.RemoveHandler(routedEvent, handler)); } public void RemoveHandler(RoutedEvent routedEvent, Delegate handler) { Contract.Requires(routedEvent != null); Contract.Requires(handler != null); List delegates; if (this.eventHandlers.TryGetValue(routedEvent, out delegates)) { delegates.Remove(handler); } } public void RaiseEvent(RoutedEventArgs e) { Contract.Requires(e != null); e.Source = e.Source ?? this; e.OriginalSource = e.OriginalSource ?? this; if (!e.Handled) { switch (e.RoutedEvent.RoutingStrategy) { case RoutingStrategy.Bubble: this.BubbleEvent(e); break; case RoutingStrategy.Direct: this.RaiseEventImpl(e); break; case RoutingStrategy.Tunnel: this.TunnelEvent(e); break; } } } private void BubbleEvent(RoutedEventArgs e) { Contract.Requires(e != null); foreach (var target in this.GetSelfAndVisualAncestors().OfType()) { target.RaiseEventImpl(e); if (e.Handled) { break; } } } private void TunnelEvent(RoutedEventArgs e) { Contract.Requires(e != null); foreach (var target in this.GetSelfAndVisualAncestors().OfType().Reverse()) { target.RaiseEventImpl(e); if (e.Handled) { break; } } } private void RaiseEventImpl(RoutedEventArgs e) { Contract.Requires(e != null); List delegates; if (this.eventHandlers.TryGetValue(e.RoutedEvent, out delegates)) { foreach (Delegate handler in delegates) { handler.DynamicInvoke(this, e); } } } } }