using System;
using System.Collections.Generic;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.LogicalTree;
using Avalonia.Reactive;
namespace Avalonia.Xaml.Interactivity;
///
/// Defines a attached property and provides a method for executing an .
///
public class Interaction
{
static Interaction()
{
BehaviorsProperty.Changed.Subscribe(
new AnonymousObserver>(BehaviorsChanged));
}
///
/// Gets or sets the associated with a specified object.
///
public static readonly AttachedProperty BehaviorsProperty =
AvaloniaProperty.RegisterAttached("Behaviors");
///
/// Gets the associated with a specified object.
///
/// The from which to retrieve the .
/// A containing the behaviors associated with the specified object.
public static BehaviorCollection GetBehaviors(AvaloniaObject obj)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
var behaviorCollection = obj.GetValue(BehaviorsProperty);
if (behaviorCollection is null)
{
behaviorCollection = [];
obj.SetValue(BehaviorsProperty, behaviorCollection);
SetVisualTreeEventHandlersFromGetter(obj);
}
return behaviorCollection;
}
///
/// Sets the associated with a specified object.
///
/// The on which to set the .
/// The associated with the object.
public static void SetBehaviors(AvaloniaObject obj, BehaviorCollection? value)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
obj.SetValue(BehaviorsProperty, value);
}
///
/// Executes all actions in the and returns their results.
///
/// The which will be passed on to the action.
/// The set of actions to execute.
/// The value of this parameter is determined by the calling behavior.
/// Returns the results of the actions.
public static IEnumerable ExecuteActions(object? sender, ActionCollection? actions, object? parameter)
{
if (actions is null)
{
return [];
}
var results = new List();
foreach (var avaloniaObject in actions)
{
if (avaloniaObject is not IAction action)
{
continue;
}
var result = action.Execute(sender, parameter);
if (result is not null)
{
results.Add(result);
}
}
return results;
}
private static void BehaviorsChanged(AvaloniaPropertyChangedEventArgs e)
{
var oldCollection = e.OldValue.GetValueOrDefault();
var newCollection = e.NewValue.GetValueOrDefault();
if (oldCollection == newCollection)
{
return;
}
if (oldCollection is { AssociatedObject: not null })
{
oldCollection.Detach();
}
if (newCollection is not null)
{
newCollection.Attach(e.Sender);
SetVisualTreeEventHandlersFromChangedEvent(e.Sender);
}
}
private static void SetVisualTreeEventHandlersFromGetter(AvaloniaObject obj)
{
if (obj is not Control control)
{
return;
}
// AttachedToVisualTree / DetachedFromVisualTree
control.AttachedToVisualTree -= Control_AttachedToVisualTreeFromChangedEvent;
control.DetachedFromVisualTree -= Control_DetachedFromVisualTreeFromChangedEvent;
control.AttachedToVisualTree -= Control_AttachedToVisualTreeFromGetter;
control.AttachedToVisualTree += Control_AttachedToVisualTreeFromGetter;
control.DetachedFromVisualTree -= Control_DetachedFromVisualTreeFromGetter;
control.DetachedFromVisualTree += Control_DetachedFromVisualTreeFromGetter;
// AttachedToLogicalTree / DetachedFromLogicalTree
control.AttachedToLogicalTree -= Control_AttachedToLogicalTreeFromChangedEvent;
control.DetachedFromLogicalTree -= Control_DetachedFromLogicalTreeFromChangedEvent;
control.AttachedToLogicalTree -= Control_AttachedToLogicalTreeFromGetter;
control.AttachedToLogicalTree += Control_AttachedToLogicalTreeFromGetter;
control.DetachedFromLogicalTree -= Control_DetachedFromLogicalTreeFromGetter;
control.DetachedFromLogicalTree += Control_DetachedFromLogicalTreeFromGetter;
// Loaded / Unloaded
control.Loaded -= Control_LoadedFromChangedEvent;
control.Unloaded -= Control_UnloadedFromChangedEvent;
control.Loaded -= Control_LoadedFromGetter;
control.Loaded += Control_LoadedFromGetter;
control.Unloaded -= Control_UnloadedFromGetter;
control.Unloaded += Control_UnloadedFromGetter;
}
private static void SetVisualTreeEventHandlersFromChangedEvent(AvaloniaObject obj)
{
if (obj is not Control control)
{
return;
}
// AttachedToVisualTree / DetachedFromVisualTree
control.AttachedToVisualTree -= Control_AttachedToVisualTreeFromGetter;
control.DetachedFromVisualTree -= Control_DetachedFromVisualTreeFromGetter;
control.AttachedToVisualTree -= Control_AttachedToVisualTreeFromChangedEvent;
control.AttachedToVisualTree += Control_AttachedToVisualTreeFromChangedEvent;
control.DetachedFromVisualTree -= Control_DetachedFromVisualTreeFromChangedEvent;
control.DetachedFromVisualTree += Control_DetachedFromVisualTreeFromChangedEvent;
// AttachedToLogicalTree / DetachedFromLogicalTree
control.AttachedToLogicalTree -= Control_AttachedToLogicalTreeFromGetter;
control.DetachedFromLogicalTree -= Control_DetachedFromLogicalTreeFromGetter;
control.AttachedToLogicalTree -= Control_AttachedToLogicalTreeFromChangedEvent;
control.AttachedToLogicalTree += Control_AttachedToLogicalTreeFromChangedEvent;
control.DetachedFromLogicalTree -= Control_DetachedFromLogicalTreeFromChangedEvent;
control.DetachedFromLogicalTree += Control_DetachedFromLogicalTreeFromChangedEvent;
// Loaded / Unloaded
control.Loaded -= Control_LoadedFromGetter;
control.Unloaded -= Control_UnloadedFromGetter;
control.Loaded -= Control_LoadedFromChangedEvent;
control.Loaded += Control_LoadedFromChangedEvent;
control.Unloaded -= Control_UnloadedFromChangedEvent;
control.Unloaded += Control_UnloadedFromChangedEvent;
}
// AttachedToVisualTree / DetachedFromVisualTree
private static void Control_AttachedToVisualTreeFromGetter(object? sender, VisualTreeAttachmentEventArgs e)
{
if (sender is not AvaloniaObject d)
{
return;
}
GetBehaviors(d).Attach(d);
GetBehaviors(d).AttachedToVisualTree();
}
private static void Control_DetachedFromVisualTreeFromGetter(object? sender, VisualTreeAttachmentEventArgs e)
{
if (sender is not AvaloniaObject d)
{
return;
}
GetBehaviors(d).DetachedFromVisualTree();
GetBehaviors(d).Detach();
}
private static void Control_AttachedToVisualTreeFromChangedEvent(object? sender, VisualTreeAttachmentEventArgs e)
{
if (sender is not AvaloniaObject d)
{
return;
}
GetBehaviors(d).AttachedToVisualTree();
}
private static void Control_DetachedFromVisualTreeFromChangedEvent(object? sender, VisualTreeAttachmentEventArgs e)
{
if (sender is not AvaloniaObject d)
{
return;
}
GetBehaviors(d).DetachedFromVisualTree();
}
// AttachedToLogicalTree / DetachedFromLogicalTree
private static void Control_AttachedToLogicalTreeFromGetter(object? sender, LogicalTreeAttachmentEventArgs e)
{
if (sender is not AvaloniaObject d)
{
return;
}
GetBehaviors(d).AttachedToLogicalTree();
}
private static void Control_DetachedFromLogicalTreeFromGetter(object? sender, LogicalTreeAttachmentEventArgs e)
{
if (sender is not AvaloniaObject d)
{
return;
}
GetBehaviors(d).DetachedFromLogicalTree();
}
private static void Control_AttachedToLogicalTreeFromChangedEvent(object? sender, LogicalTreeAttachmentEventArgs e)
{
if (sender is not AvaloniaObject d)
{
return;
}
GetBehaviors(d).AttachedToLogicalTree();
}
private static void Control_DetachedFromLogicalTreeFromChangedEvent(object? sender, LogicalTreeAttachmentEventArgs e)
{
if (sender is not AvaloniaObject d)
{
return;
}
GetBehaviors(d).DetachedFromLogicalTree();
}
// Loaded / Unloaded
private static void Control_LoadedFromGetter(object? sender, RoutedEventArgs e)
{
if (sender is not AvaloniaObject d)
{
return;
}
GetBehaviors(d).Loaded();
}
private static void Control_UnloadedFromGetter(object? sender, RoutedEventArgs e)
{
if (sender is not AvaloniaObject d)
{
return;
}
GetBehaviors(d).Unloaded();
}
private static void Control_LoadedFromChangedEvent(object? sender, RoutedEventArgs e)
{
if (sender is not AvaloniaObject d)
{
return;
}
GetBehaviors(d).Loaded();
}
private static void Control_UnloadedFromChangedEvent(object? sender, RoutedEventArgs e)
{
if (sender is not AvaloniaObject d)
{
return;
}
GetBehaviors(d).Unloaded();
}
}