csharpc-sharpdotnetxamlavaloniauicross-platformcross-platform-xamlavaloniaguimulti-platformuser-interfacedotnetcore
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
162 lines
5.3 KiB
162 lines
5.3 KiB
// Copyright (c) The Avalonia Project. All rights reserved.
|
|
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
|
|
|
using System;
|
|
using System.Reactive.Subjects;
|
|
using System.Reflection;
|
|
using System.Runtime.ExceptionServices;
|
|
|
|
namespace Avalonia.Interactivity
|
|
{
|
|
[Flags]
|
|
public enum RoutingStrategies
|
|
{
|
|
Direct = 0x01,
|
|
Tunnel = 0x02,
|
|
Bubble = 0x04,
|
|
}
|
|
|
|
public class RoutedEvent
|
|
{
|
|
private Subject<Tuple<object, RoutedEventArgs>> _raised = new Subject<Tuple<object, RoutedEventArgs>>();
|
|
private Subject<RoutedEventArgs> _routeFinished = new Subject<RoutedEventArgs>();
|
|
|
|
public RoutedEvent(
|
|
string name,
|
|
RoutingStrategies routingStrategies,
|
|
Type eventArgsType,
|
|
Type ownerType)
|
|
{
|
|
Contract.Requires<ArgumentNullException>(name != null);
|
|
Contract.Requires<ArgumentNullException>(eventArgsType != null);
|
|
Contract.Requires<ArgumentNullException>(ownerType != null);
|
|
Contract.Requires<InvalidCastException>(typeof(RoutedEventArgs).GetTypeInfo().IsAssignableFrom(eventArgsType.GetTypeInfo()));
|
|
|
|
EventArgsType = eventArgsType;
|
|
Name = name;
|
|
OwnerType = ownerType;
|
|
RoutingStrategies = routingStrategies;
|
|
}
|
|
|
|
public Type EventArgsType
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
public string Name
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
public Type OwnerType
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
public RoutingStrategies RoutingStrategies
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
public IObservable<Tuple<object, RoutedEventArgs>> Raised => _raised;
|
|
public IObservable<RoutedEventArgs> RouteFinished => _routeFinished;
|
|
|
|
public static RoutedEvent<TEventArgs> Register<TOwner, TEventArgs>(
|
|
string name,
|
|
RoutingStrategies routingStrategy)
|
|
where TEventArgs : RoutedEventArgs
|
|
{
|
|
Contract.Requires<ArgumentNullException>(name != null);
|
|
|
|
var routedEvent = new RoutedEvent<TEventArgs>(name, routingStrategy, typeof(TOwner));
|
|
RoutedEventRegistry.Instance.Register(typeof(TOwner), routedEvent);
|
|
return routedEvent;
|
|
}
|
|
|
|
public static RoutedEvent<TEventArgs> Register<TEventArgs>(
|
|
string name,
|
|
RoutingStrategies routingStrategy,
|
|
Type ownerType)
|
|
where TEventArgs : RoutedEventArgs
|
|
{
|
|
Contract.Requires<ArgumentNullException>(name != null);
|
|
|
|
var routedEvent = new RoutedEvent<TEventArgs>(name, routingStrategy, ownerType);
|
|
RoutedEventRegistry.Instance.Register(ownerType, routedEvent);
|
|
return routedEvent;
|
|
}
|
|
|
|
public IDisposable AddClassHandler(
|
|
Type targetType,
|
|
EventHandler<RoutedEventArgs> handler,
|
|
RoutingStrategies routes = RoutingStrategies.Direct | RoutingStrategies.Bubble,
|
|
bool handledEventsToo = false)
|
|
{
|
|
return Raised.Subscribe(args =>
|
|
{
|
|
var sender = args.Item1;
|
|
var e = args.Item2;
|
|
|
|
if (targetType.GetTypeInfo().IsAssignableFrom(sender.GetType().GetTypeInfo()) &&
|
|
((e.Route == RoutingStrategies.Direct) || (e.Route & routes) != 0) &&
|
|
(!e.Handled || handledEventsToo))
|
|
{
|
|
try
|
|
{
|
|
handler.DynamicInvoke(sender, e);
|
|
}
|
|
catch (TargetInvocationException ex)
|
|
{
|
|
// Unwrap the inner exception.
|
|
ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
internal void InvokeRaised(object sender, RoutedEventArgs e)
|
|
{
|
|
_raised.OnNext(Tuple.Create(sender, e));
|
|
}
|
|
|
|
internal void InvokeRouteFinished(RoutedEventArgs e)
|
|
{
|
|
_routeFinished.OnNext(e);
|
|
}
|
|
}
|
|
|
|
public class RoutedEvent<TEventArgs> : RoutedEvent
|
|
where TEventArgs : RoutedEventArgs
|
|
{
|
|
public RoutedEvent(string name, RoutingStrategies routingStrategies, Type ownerType)
|
|
: base(name, routingStrategies, typeof(TEventArgs), ownerType)
|
|
{
|
|
Contract.Requires<ArgumentNullException>(name != null);
|
|
Contract.Requires<ArgumentNullException>(ownerType != null);
|
|
}
|
|
|
|
public IDisposable AddClassHandler<TTarget>(
|
|
Func<TTarget, Action<TEventArgs>> handler,
|
|
RoutingStrategies routes = RoutingStrategies.Direct | RoutingStrategies.Bubble,
|
|
bool handledEventsToo = false)
|
|
where TTarget : class, IInteractive
|
|
{
|
|
EventHandler<RoutedEventArgs> adapter = (sender, e) =>
|
|
{
|
|
var target = sender as TTarget;
|
|
var args = e as TEventArgs;
|
|
|
|
if (target != null && args != null)
|
|
{
|
|
handler(target)(args);
|
|
}
|
|
};
|
|
|
|
return AddClassHandler(typeof(TTarget), adapter, routes, handledEventsToo);
|
|
}
|
|
}
|
|
}
|
|
|