Browse Source

Merge pull request #3067 from MarchingCube/alloc-interactive-traversal

Optimize Interactive hierarchy traversal
pull/3075/head
Jumar Macato 7 years ago
committed by GitHub
parent
commit
378f3442f7
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 77
      src/Avalonia.Interactivity/Interactive.cs
  2. 24
      src/Avalonia.Interactivity/InteractiveExtensions.cs

77
src/Avalonia.Interactivity/Interactive.cs

@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using Avalonia.Layout;
using Avalonia.VisualTree;
@ -170,10 +171,9 @@ namespace Avalonia.Interactivity
e.Route = RoutingStrategies.Bubble;
foreach (var target in this.GetBubbleEventRoute())
{
((Interactive)target).RaiseEventImpl(e);
}
var traverser = HierarchyTraverser<RaiseEventTraverse, NopTraverse>.Create(e);
traverser.Traverse(this);
}
/// <summary>
@ -186,10 +186,9 @@ namespace Avalonia.Interactivity
e.Route = RoutingStrategies.Tunnel;
foreach (var target in this.GetTunnelEventRoute())
{
((Interactive)target).RaiseEventImpl(e);
}
var traverser = HierarchyTraverser<NopTraverse, RaiseEventTraverse>.Create(e);
traverser.Traverse(this);
}
/// <summary>
@ -262,5 +261,67 @@ namespace Avalonia.Interactivity
_subscriptions.Remove(_subscription);
}
}
private interface ITraverse
{
void Execute(IInteractive target, RoutedEventArgs e);
}
private struct NopTraverse : ITraverse
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Execute(IInteractive target, RoutedEventArgs e)
{
}
}
private struct RaiseEventTraverse : ITraverse
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Execute(IInteractive target, RoutedEventArgs e)
{
((Interactive)target).RaiseEventImpl(e);
}
}
/// <summary>
/// Traverses interactive hierarchy allowing for raising events.
/// </summary>
/// <typeparam name="TPreTraverse">Called before parent is traversed.</typeparam>
/// <typeparam name="TPostTraverse">Called after parent has been traversed.</typeparam>
private struct HierarchyTraverser<TPreTraverse, TPostTraverse>
where TPreTraverse : struct, ITraverse
where TPostTraverse : struct, ITraverse
{
private TPreTraverse _preTraverse;
private TPostTraverse _postTraverse;
private readonly RoutedEventArgs _args;
private HierarchyTraverser(TPreTraverse preTraverse, TPostTraverse postTraverse, RoutedEventArgs args)
{
_preTraverse = preTraverse;
_postTraverse = postTraverse;
_args = args;
}
public static HierarchyTraverser<TPreTraverse, TPostTraverse> Create(RoutedEventArgs args)
{
return new HierarchyTraverser<TPreTraverse, TPostTraverse>(new TPreTraverse(), new TPostTraverse(), args);
}
public void Traverse(IInteractive target)
{
_preTraverse.Execute(target, _args);
IInteractive parent = target.InteractiveParent;
if (parent != null)
{
Traverse(parent);
}
_postTraverse.Execute(target, _args);
}
}
}
}

24
src/Avalonia.Interactivity/InteractiveExtensions.cs

@ -36,29 +36,5 @@ namespace Avalonia.Interactivity
routes,
handledEventsToo));
}
/// <summary>
/// Gets the route for bubbling events from the specified interactive.
/// </summary>
/// <param name="interactive">The interactive.</param>
/// <returns>The event route.</returns>
internal static IEnumerable<IInteractive> GetBubbleEventRoute(this IInteractive interactive)
{
while (interactive != null)
{
yield return interactive;
interactive = interactive.InteractiveParent;
}
}
/// <summary>
/// Gets the route for tunneling events from the specified interactive.
/// </summary>
/// <param name="interactive">The interactive.</param>
/// <returns>The event route.</returns>
internal static IEnumerable<IInteractive> GetTunnelEventRoute(this IInteractive interactive)
{
return interactive.GetBubbleEventRoute().Reverse();
}
}
}

Loading…
Cancel
Save