// -----------------------------------------------------------------------
//
// 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);
}
}
}
}
}