chore: separated System.Windows.Interactivity code

This commit is contained in:
NaBian committed 2022-03-13 21:40:09 +08:00
1 parent 0da2875641
commit ef4226ddf9
26 files changed
+54 -20

No files matched your search

@@ -1,167 +0,0 @@
using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Globalization;
using System.Windows;
namespace HandyControl.Interactivity;
public abstract class AttachableCollection<T> : FreezableCollection<T>, IAttachedObject
where T : DependencyObject, IAttachedObject
{
private DependencyObject _associatedObject;
private Collection<T> _snapshot;
internal AttachableCollection()
{
INotifyCollectionChanged changed = this;
changed.CollectionChanged += OnCollectionChanged;
_snapshot = new Collection<T>();
}
public DependencyObject AssociatedObject
{
get
{
ReadPreamble();
return _associatedObject;
}
}
DependencyObject IAttachedObject.AssociatedObject => AssociatedObject;
public void Attach(DependencyObject dependencyObject)
{
if (Equals(dependencyObject, AssociatedObject))
return;
if (AssociatedObject != null)
throw new InvalidOperationException();
if (Interaction.ShouldRunInDesignMode || !(bool) GetValue(DesignerProperties.IsInDesignModeProperty))
{
WritePreamble();
_associatedObject = dependencyObject;
WritePostscript();
}
OnAttached();
}
public void Detach()
{
OnDetaching();
WritePreamble();
_associatedObject = null;
WritePostscript();
}
protected abstract void OnAttached();
protected abstract void OnDetaching();
internal abstract void ItemAdded(T item);
internal abstract void ItemRemoved(T item);
private void VerifyAdd(T item)
{
if (item == null) throw new ArgumentNullException(nameof(item));
if (_snapshot.Contains(item))
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture,
ExceptionStringTable.DuplicateItemInCollectionExceptionMessage, new object[]
{
typeof(T).Name,
GetType().Name
}));
}
private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
var enumerator1 = e.NewItems.GetEnumerator();
try
{
while (enumerator1.MoveNext())
{
var current = (T) enumerator1.Current;
try
{
VerifyAdd(current);
ItemAdded(current);
}
finally
{
_snapshot.Insert(IndexOf(current), current);
}
}
break;
}
finally
{
if (enumerator1 is IDisposable disposable)
disposable.Dispose();
}
case NotifyCollectionChangedAction.Remove:
var enumerator2 = e.OldItems.GetEnumerator();
try
{
while (enumerator2.MoveNext())
{
var current = (T) enumerator2.Current;
ItemRemoved(current);
_snapshot.Remove(current);
}
break;
}
finally
{
if (enumerator2 is IDisposable disposable)
disposable.Dispose();
}
case NotifyCollectionChangedAction.Replace:
foreach (T oldItem in e.OldItems)
{
ItemRemoved(oldItem);
_snapshot.Remove(oldItem);
}
var enumerator3 = e.NewItems.GetEnumerator();
try
{
while (enumerator3.MoveNext())
{
var current = (T) enumerator3.Current;
try
{
VerifyAdd(current);
ItemAdded(current);
}
finally
{
_snapshot.Insert(IndexOf(current), current);
}
}
break;
}
finally
{
if (enumerator3 is IDisposable disposable)
disposable.Dispose();
}
case NotifyCollectionChangedAction.Reset:
foreach (var obj in _snapshot)
ItemRemoved(obj);
_snapshot = new Collection<T>();
using (var enumerator4 = GetEnumerator())
{
while (enumerator4.MoveNext())
{
var current = enumerator4.Current;
VerifyAdd(current);
ItemAdded(current);
}
break;
}
}
}
}
@@ -1,86 +0,0 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Media.Animation;
namespace HandyControl.Interactivity;
public abstract class Behavior : Animatable, IAttachedObject
{
private DependencyObject _associatedObject;
private readonly Type _associatedType;
internal Behavior(Type associatedType)
{
_associatedType = associatedType;
}
protected DependencyObject AssociatedObject
{
get
{
ReadPreamble();
return _associatedObject;
}
}
protected Type AssociatedType
{
get
{
ReadPreamble();
return _associatedType;
}
}
public void Attach(DependencyObject dependencyObject)
{
if (!Equals(dependencyObject, AssociatedObject))
{
if (AssociatedObject != null)
throw new InvalidOperationException(ExceptionStringTable
.CannotHostBehaviorMultipleTimesExceptionMessage);
if (dependencyObject != null && !AssociatedType.IsInstanceOfType(dependencyObject))
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture,
ExceptionStringTable.TypeConstraintViolatedExceptionMessage,
new object[] { GetType().Name, dependencyObject.GetType().Name, AssociatedType.Name }));
WritePreamble();
_associatedObject = dependencyObject;
WritePostscript();
OnAssociatedObjectChanged();
OnAttached();
}
}
public void Detach()
{
OnDetaching();
WritePreamble();
_associatedObject = null;
WritePostscript();
OnAssociatedObjectChanged();
}
DependencyObject IAttachedObject.AssociatedObject =>
AssociatedObject;
internal event EventHandler AssociatedObjectChanged;
protected override Freezable CreateInstanceCore()
{
return (Freezable) Activator.CreateInstance(GetType());
}
private void OnAssociatedObjectChanged()
{
AssociatedObjectChanged?.Invoke(this, new EventArgs());
}
protected virtual void OnAttached()
{
}
protected virtual void OnDetaching()
{
}
}
@@ -1,41 +0,0 @@
using System.Windows;
namespace HandyControl.Interactivity;
public sealed class BehaviorCollection : AttachableCollection<Behavior>
{
internal BehaviorCollection()
{
}
protected override void OnAttached()
{
foreach (var behavior in this)
behavior.Attach(AssociatedObject);
}
protected override void OnDetaching()
{
foreach (var behavior in this)
behavior.Detach();
}
internal override void ItemAdded(Behavior item)
{
if (item == null || AssociatedObject == null)
return;
item.Attach(AssociatedObject);
}
internal override void ItemRemoved(Behavior item)
{
if (((IAttachedObject) item)?.AssociatedObject == null)
return;
item.Detach();
}
protected override Freezable CreateInstanceCore()
{
return new BehaviorCollection();
}
}
@@ -1,12 +0,0 @@
using System.Windows;
namespace HandyControl.Interactivity;
public abstract class Behavior<T> : Behavior where T : DependencyObject
{
protected Behavior() : base(typeof(T))
{
}
protected new T AssociatedObject => (T) base.AssociatedObject;
}
@@ -1,48 +0,0 @@
using System;
using System.Collections;
using System.Globalization;
namespace HandyControl.Interactivity;
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, AllowMultiple = true)]
public sealed class DefaultTriggerAttribute : Attribute
{
private readonly object[] _parameters;
public DefaultTriggerAttribute(Type targetType, Type triggerType, object parameter) : this(targetType,
triggerType, new[] { parameter })
{
}
public DefaultTriggerAttribute(Type targetType, Type triggerType, params object[] parameters)
{
if (!typeof(TriggerBase).IsAssignableFrom(triggerType))
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
ExceptionStringTable.DefaultTriggerAttributeInvalidTriggerTypeSpecifiedExceptionMessage,
new object[] { triggerType.Name }));
TargetType = targetType;
TriggerType = triggerType;
_parameters = parameters;
}
public IEnumerable Parameters =>
_parameters;
public Type TargetType { get; }
public Type TriggerType { get; }
public TriggerBase Instantiate()
{
object obj2 = null;
try
{
obj2 = Activator.CreateInstance(TriggerType, _parameters);
}
catch
{
// ignored
}
return (TriggerBase) obj2;
}
}
@@ -1,28 +0,0 @@
using System.Windows;
namespace HandyControl.Interactivity;
public class EventTrigger : EventTriggerBase<object>
{
public static readonly DependencyProperty EventNameProperty = DependencyProperty.Register("EventName", typeof(string), typeof(EventTrigger), new FrameworkPropertyMetadata("Loaded", OnEventNameChanged));
public EventTrigger()
{
}
public EventTrigger(string eventName) => EventName = eventName;
protected override string GetEventName() => EventName;
private static void OnEventNameChanged(object sender, DependencyPropertyChangedEventArgs args)
{
((EventTrigger) sender).OnEventNameChanged((string) args.OldValue, (string) args.NewValue);
}
public string EventName
{
get => (string) GetValue(EventNameProperty);
set => SetValue(EventNameProperty, value);
}
}
@@ -1,312 +0,0 @@
using System;
using System.ComponentModel;
using System.Globalization;
using System.Reflection;
using System.Windows;
namespace HandyControl.Interactivity;
public abstract class EventTriggerBase : TriggerBase
{
public static readonly DependencyProperty SourceNameProperty = DependencyProperty.Register("SourceName",
typeof(string), typeof(EventTriggerBase), new PropertyMetadata(OnSourceNameChanged));
public static readonly DependencyProperty SourceObjectProperty = DependencyProperty.Register("SourceObject",
typeof(object), typeof(EventTriggerBase), new PropertyMetadata(OnSourceObjectChanged));
private MethodInfo _eventHandlerMethodInfo;
internal EventTriggerBase(Type sourceTypeConstraint) : base(typeof(DependencyObject))
{
SourceTypeConstraint = sourceTypeConstraint;
SourceNameResolver = new NameResolver();
RegisterSourceChanged();
}
protected sealed override Type AssociatedObjectTypeConstraint
{
get
{
if (TypeDescriptor.GetAttributes(GetType())[typeof(TypeConstraintAttribute)] is TypeConstraintAttribute attribute)
return attribute.Constraint;
return typeof(DependencyObject);
}
}
private bool IsLoadedRegistered { get; set; }
private bool IsSourceChangedRegistered { get; set; }
private bool IsSourceNameSet
{
get
{
if (string.IsNullOrEmpty(SourceName))
return ReadLocalValue(SourceNameProperty) != DependencyProperty.UnsetValue;
return true;
}
}
public object Source
{
get
{
object associatedObject = AssociatedObject;
if (SourceObject != null)
return SourceObject;
if (IsSourceNameSet)
{
associatedObject = SourceNameResolver.Object;
if (associatedObject != null && !SourceTypeConstraint.IsInstanceOfType(associatedObject))
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture,
ExceptionStringTable.RetargetedTypeConstraintViolatedExceptionMessage, GetType().Name,
associatedObject.GetType(), SourceTypeConstraint, "Source"));
}
return associatedObject;
}
}
public string SourceName
{
get =>
(string) GetValue(SourceNameProperty);
set => SetValue(SourceNameProperty, value);
}
private NameResolver SourceNameResolver { get; }
public object SourceObject
{
get =>
GetValue(SourceObjectProperty);
set => SetValue(SourceObjectProperty, value);
}
protected Type SourceTypeConstraint { get; }
protected abstract string GetEventName();
private static bool IsValidEvent(EventInfo eventInfo)
{
var eventHandlerType = eventInfo.EventHandlerType;
if (!typeof(Delegate).IsAssignableFrom(eventInfo.EventHandlerType))
return false;
var parameters = eventHandlerType.GetMethod("Invoke")?.GetParameters();
return parameters != null && parameters.Length == 2 && typeof(object).IsAssignableFrom(parameters[0].ParameterType) && typeof(EventArgs).IsAssignableFrom(parameters[1].ParameterType);
}
protected override void OnAttached()
{
base.OnAttached();
var associatedObject = AssociatedObject;
var behavior = associatedObject as Behavior;
var element = associatedObject as FrameworkElement;
RegisterSourceChanged();
if (behavior != null)
{
behavior.AssociatedObjectChanged += OnBehaviorHostChanged;
}
else if (SourceObject != null || element == null)
{
try
{
OnSourceChanged(null, Source);
}
catch (InvalidOperationException)
{
}
}
else
{
SourceNameResolver.NameScopeReferenceElement = element;
}
if (string.Compare(GetEventName(), "Loaded", StringComparison.Ordinal) == 0 && element != null &&
!Interaction.IsElementLoaded(element))
RegisterLoaded(element);
}
private void OnBehaviorHostChanged(object sender, EventArgs e)
{
SourceNameResolver.NameScopeReferenceElement =
((IAttachedObject) sender).AssociatedObject as FrameworkElement;
}
protected override void OnDetaching()
{
base.OnDetaching();
var associatedObject = AssociatedObject as Behavior;
var associatedElement = AssociatedObject as FrameworkElement;
try
{
OnSourceChanged(Source, null);
}
catch (InvalidOperationException)
{
}
UnregisterSourceChanged();
if (associatedObject != null)
associatedObject.AssociatedObjectChanged -= OnBehaviorHostChanged;
SourceNameResolver.NameScopeReferenceElement = null;
if (string.Compare(GetEventName(), "Loaded", StringComparison.Ordinal) == 0 && associatedElement != null)
UnregisterLoaded(associatedElement);
}
protected virtual void OnEvent(EventArgs eventArgs)
{
InvokeActions(eventArgs);
}
private void OnEventImpl(object sender, EventArgs eventArgs)
{
OnEvent(eventArgs);
}
internal void OnEventNameChanged(string oldEventName, string newEventName)
{
if (AssociatedObject != null)
{
var source = Source as FrameworkElement;
if (source != null && string.Compare(oldEventName, "Loaded", StringComparison.Ordinal) == 0)
UnregisterLoaded(source);
else if (!string.IsNullOrEmpty(oldEventName))
UnregisterEvent(Source, oldEventName);
if (source != null && string.Compare(newEventName, "Loaded", StringComparison.Ordinal) == 0)
RegisterLoaded(source);
else if (!string.IsNullOrEmpty(newEventName))
RegisterEvent(Source, newEventName);
}
}
private void OnSourceChanged(object oldSource, object newSource)
{
if (AssociatedObject != null)
OnSourceChangedImpl(oldSource, newSource);
}
internal virtual void OnSourceChangedImpl(object oldSource, object newSource)
{
if (!string.IsNullOrEmpty(GetEventName()) &&
string.Compare(GetEventName(), "Loaded", StringComparison.Ordinal) != 0)
{
if (oldSource != null && SourceTypeConstraint.IsInstanceOfType(oldSource))
UnregisterEvent(oldSource, GetEventName());
if (newSource != null && SourceTypeConstraint.IsInstanceOfType(newSource))
RegisterEvent(newSource, GetEventName());
}
}
private static void OnSourceNameChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
var base2 = (EventTriggerBase) obj;
base2.SourceNameResolver.Name = (string) args.NewValue;
}
private void OnSourceNameResolverElementChanged(object sender, NameResolvedEventArgs e)
{
if (SourceObject == null)
OnSourceChanged(e.OldObject, e.NewObject);
}
private static void OnSourceObjectChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
var base2 = (EventTriggerBase) obj;
object newSource = base2.SourceNameResolver.Object;
if (args.NewValue == null)
{
base2.OnSourceChanged(args.OldValue, newSource);
}
else
{
if (args.OldValue == null && newSource != null)
base2.UnregisterEvent(newSource, base2.GetEventName());
base2.OnSourceChanged(args.OldValue, args.NewValue);
}
}
private void RegisterEvent(object obj, string eventName)
{
var eventInfo = obj.GetType().GetEvent(eventName);
if (eventInfo == null)
{
if (SourceObject != null)
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
ExceptionStringTable.EventTriggerCannotFindEventNameExceptionMessage,
new object[] { eventName, obj.GetType().Name }));
}
else if (!IsValidEvent(eventInfo))
{
if (SourceObject != null)
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
ExceptionStringTable.EventTriggerBaseInvalidEventExceptionMessage,
new object[] { eventName, obj.GetType().Name }));
}
else
{
_eventHandlerMethodInfo =
typeof(EventTriggerBase).GetMethod("OnEventImpl", BindingFlags.NonPublic | BindingFlags.Instance);
eventInfo.AddEventHandler(obj,
Delegate.CreateDelegate(eventInfo.EventHandlerType, this, _eventHandlerMethodInfo ?? throw new InvalidOperationException()));
}
}
private void RegisterLoaded(FrameworkElement associatedElement)
{
if (!IsLoadedRegistered && associatedElement != null)
{
associatedElement.Loaded += OnEventImpl;
IsLoadedRegistered = true;
}
}
private void RegisterSourceChanged()
{
if (!IsSourceChangedRegistered)
{
SourceNameResolver.ResolvedElementChanged += OnSourceNameResolverElementChanged;
IsSourceChangedRegistered = true;
}
}
private void UnregisterEvent(object obj, string eventName)
{
if (string.Compare(eventName, "Loaded", StringComparison.Ordinal) == 0)
{
if (obj is FrameworkElement associatedElement)
UnregisterLoaded(associatedElement);
}
else
{
UnregisterEventImpl(obj, eventName);
}
}
private void UnregisterEventImpl(object obj, string eventName)
{
var type = obj.GetType();
if (_eventHandlerMethodInfo != null)
{
var info = type.GetEvent(eventName);
info.RemoveEventHandler(obj,
Delegate.CreateDelegate(info.EventHandlerType, this, _eventHandlerMethodInfo));
_eventHandlerMethodInfo = null;
}
}
private void UnregisterLoaded(FrameworkElement associatedElement)
{
if (IsLoadedRegistered && associatedElement != null)
{
associatedElement.Loaded -= OnEventImpl;
IsLoadedRegistered = false;
}
}
private void UnregisterSourceChanged()
{
if (IsSourceChangedRegistered)
{
SourceNameResolver.ResolvedElementChanged -= OnSourceNameResolverElementChanged;
IsSourceChangedRegistered = false;
}
}
}
@@ -1,20 +0,0 @@
namespace HandyControl.Interactivity;
public abstract class EventTriggerBase<T> : EventTriggerBase where T : class
{
protected EventTriggerBase() : base(typeof(T))
{
}
protected virtual void OnSourceChanged(T oldSource, T newSource)
{
}
internal sealed override void OnSourceChangedImpl(object oldSource, object newSource)
{
base.OnSourceChangedImpl(oldSource, newSource);
OnSourceChanged(oldSource as T, newSource as T);
}
public new T Source => (T) base.Source;
}
@@ -1,11 +0,0 @@
using System.Windows;
namespace HandyControl.Interactivity;
public interface IAttachedObject
{
void Attach(DependencyObject dependencyObject);
void Detach();
DependencyObject AssociatedObject { get; }
}
@@ -1,76 +0,0 @@
using System;
using System.Windows;
namespace HandyControl.Interactivity;
public static class Interaction
{
private static readonly DependencyProperty TriggersProperty =
DependencyProperty.RegisterAttached("ShadowTriggers", typeof(TriggerCollection), typeof(Interaction),
new FrameworkPropertyMetadata(OnTriggersChanged));
private static readonly DependencyProperty BehaviorsProperty =
DependencyProperty.RegisterAttached("ShadowBehaviors", typeof(BehaviorCollection), typeof(Interaction),
new FrameworkPropertyMetadata(OnBehaviorsChanged));
internal static bool ShouldRunInDesignMode { get; set; }
public static TriggerCollection GetTriggers(DependencyObject obj)
{
var triggerCollection = (TriggerCollection) obj.GetValue(TriggersProperty);
if (triggerCollection == null)
{
triggerCollection = new TriggerCollection();
obj.SetValue(TriggersProperty, triggerCollection);
}
return triggerCollection;
}
public static BehaviorCollection GetBehaviors(DependencyObject obj)
{
var behaviorCollection = (BehaviorCollection) obj.GetValue(BehaviorsProperty);
if (behaviorCollection == null)
{
behaviorCollection = new BehaviorCollection();
obj.SetValue(BehaviorsProperty, behaviorCollection);
}
return behaviorCollection;
}
private static void OnBehaviorsChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
var oldValue = (BehaviorCollection) args.OldValue;
var newValue = (BehaviorCollection) args.NewValue;
if (Equals(oldValue, newValue))
return;
if (oldValue?.AssociatedObject != null)
oldValue.Detach();
if (newValue == null || obj == null)
return;
if (newValue.AssociatedObject != null)
throw new InvalidOperationException(ExceptionStringTable
.CannotHostBehaviorCollectionMultipleTimesExceptionMessage);
newValue.Attach(obj);
}
private static void OnTriggersChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
var oldValue = args.OldValue as TriggerCollection;
var newValue = args.NewValue as TriggerCollection;
if (Equals(oldValue, newValue))
return;
if (oldValue?.AssociatedObject != null)
oldValue.Detach();
if (newValue == null || obj == null)
return;
if (newValue.AssociatedObject != null)
throw new InvalidOperationException(ExceptionStringTable
.CannotHostTriggerCollectionMultipleTimesExceptionMessage);
newValue.Attach(obj);
}
internal static bool IsElementLoaded(FrameworkElement element)
{
return element.IsLoaded;
}
}
@@ -1,71 +0,0 @@
using System;
using System.Reflection;
using System.Windows;
using System.Windows.Input;
namespace HandyControl.Interactivity;
public sealed class InvokeCommandAction : TriggerAction<DependencyObject>
{
public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register(nameof(Command), typeof(ICommand), typeof(InvokeCommandAction), null);
public static readonly DependencyProperty CommandParameterProperty =
DependencyProperty.Register(nameof(CommandParameter), typeof(object), typeof(InvokeCommandAction),
null);
private string _commandName;
public string CommandName
{
get
{
ReadPreamble();
return _commandName;
}
set
{
if (CommandName == value)
return;
WritePreamble();
_commandName = value;
WritePostscript();
}
}
public ICommand Command
{
get => (ICommand) GetValue(CommandProperty);
set => SetValue(CommandProperty, value);
}
public object CommandParameter
{
get => GetValue(CommandParameterProperty);
set => SetValue(CommandParameterProperty, value);
}
protected override void Invoke(object parameter)
{
if (AssociatedObject == null)
return;
var command = ResolveCommand();
if (command == null || !command.CanExecute(CommandParameter))
return;
command.Execute(CommandParameter);
}
private ICommand ResolveCommand()
{
var command = (ICommand) null;
if (Command != null)
command = Command;
else if (AssociatedObject != null)
foreach (var property in AssociatedObject.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public))
if (typeof(ICommand).IsAssignableFrom(property.PropertyType) &&
string.Equals(property.Name, CommandName, StringComparison.Ordinal))
command = (ICommand) property.GetValue(AssociatedObject, null);
return command;
}
}
@@ -1,16 +0,0 @@
using System;
namespace HandyControl.Interactivity;
internal sealed class NameResolvedEventArgs : EventArgs
{
public NameResolvedEventArgs(object oldObject, object newObject)
{
OldObject = oldObject;
NewObject = newObject;
}
public object NewObject { get; }
public object OldObject { get; }
}
@@ -1,123 +0,0 @@
using System;
using System.Windows;
namespace HandyControl.Interactivity;
internal sealed class NameResolver
{
private string _name;
private FrameworkElement _nameScopeReferenceElement;
private FrameworkElement ActualNameScopeReferenceElement
{
get
{
if (NameScopeReferenceElement != null && Interaction.IsElementLoaded(NameScopeReferenceElement))
return GetActualNameScopeReference(NameScopeReferenceElement);
return null;
}
}
private bool HasAttempedResolve { get; set; }
public string Name
{
get =>
_name;
set
{
var oldObject = Object;
_name = value;
UpdateObjectFromName(oldObject);
}
}
public FrameworkElement NameScopeReferenceElement
{
get =>
_nameScopeReferenceElement;
set
{
var nameScopeReferenceElement = NameScopeReferenceElement;
_nameScopeReferenceElement = value;
OnNameScopeReferenceElementChanged(nameScopeReferenceElement);
}
}
public DependencyObject Object
{
get
{
if (string.IsNullOrEmpty(Name) && HasAttempedResolve)
return NameScopeReferenceElement;
return ResolvedObject;
}
}
private bool PendingReferenceElementLoad { get; set; }
private DependencyObject ResolvedObject { get; set; }
public event EventHandler<NameResolvedEventArgs> ResolvedElementChanged;
private FrameworkElement GetActualNameScopeReference(FrameworkElement initialReferenceElement)
{
var element = initialReferenceElement;
if (!IsNameScope(initialReferenceElement))
return element;
return initialReferenceElement.Parent as FrameworkElement ?? element;
}
private bool IsNameScope(FrameworkElement frameworkElement)
{
return frameworkElement.Parent is FrameworkElement parent && parent.FindName(Name) != null;
}
private void OnNameScopeReferenceElementChanged(FrameworkElement oldNameScopeReference)
{
if (PendingReferenceElementLoad)
{
oldNameScopeReference.Loaded -= OnNameScopeReferenceLoaded;
PendingReferenceElementLoad = false;
}
HasAttempedResolve = false;
UpdateObjectFromName(Object);
}
private void OnNameScopeReferenceLoaded(object sender, RoutedEventArgs e)
{
PendingReferenceElementLoad = false;
NameScopeReferenceElement.Loaded -= OnNameScopeReferenceLoaded;
UpdateObjectFromName(Object);
}
private void OnObjectChanged(DependencyObject oldTarget, DependencyObject newTarget)
{
ResolvedElementChanged?.Invoke(this, new NameResolvedEventArgs(oldTarget, newTarget));
}
private void UpdateObjectFromName(DependencyObject oldObject)
{
DependencyObject obj2 = null;
ResolvedObject = null;
if (NameScopeReferenceElement != null)
{
if (!Interaction.IsElementLoaded(NameScopeReferenceElement))
{
NameScopeReferenceElement.Loaded += OnNameScopeReferenceLoaded;
PendingReferenceElementLoad = true;
return;
}
if (!string.IsNullOrEmpty(Name))
{
var actualNameScopeReferenceElement = ActualNameScopeReferenceElement;
if (actualNameScopeReferenceElement != null)
obj2 = actualNameScopeReferenceElement.FindName(Name) as DependencyObject;
}
}
HasAttempedResolve = true;
ResolvedObject = obj2;
if (!Equals(oldObject, Object))
OnObjectChanged(oldObject, Object);
}
}
@@ -1,8 +0,0 @@
using System;
namespace HandyControl.Interactivity;
public class PreviewInvokeEventArgs : EventArgs
{
public bool Cancelling { get; set; }
}
@@ -1,117 +0,0 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Media.Animation;
using HandyControl.Data;
namespace HandyControl.Interactivity;
[DefaultTrigger(typeof(UIElement), typeof(EventTrigger), "MouseLeftButtonDown")]
[DefaultTrigger(typeof(ButtonBase), typeof(EventTrigger), "Click")]
public abstract class TriggerAction : Animatable, IAttachedObject
{
public static readonly DependencyProperty IsEnabledProperty = DependencyProperty.Register("IsEnabled",
typeof(bool), typeof(TriggerAction), new FrameworkPropertyMetadata(ValueBoxes.TrueBox));
private readonly Type _associatedObjectTypeConstraint;
private DependencyObject _associatedObject;
private bool _isHosted;
internal TriggerAction(Type associatedObjectTypeConstraint)
{
_associatedObjectTypeConstraint = associatedObjectTypeConstraint;
}
protected DependencyObject AssociatedObject
{
get
{
ReadPreamble();
return _associatedObject;
}
}
protected virtual Type AssociatedObjectTypeConstraint
{
get
{
ReadPreamble();
return _associatedObjectTypeConstraint;
}
}
public bool IsEnabled
{
get => (bool) GetValue(IsEnabledProperty);
set => SetValue(IsEnabledProperty, ValueBoxes.BooleanBox(value));
}
internal bool IsHosted
{
get
{
ReadPreamble();
return _isHosted;
}
set
{
WritePreamble();
_isHosted = value;
WritePostscript();
}
}
public void Attach(DependencyObject dependencyObject)
{
if (!Equals(dependencyObject, AssociatedObject))
{
if (AssociatedObject != null)
throw new InvalidOperationException(ExceptionStringTable
.CannotHostTriggerActionMultipleTimesExceptionMessage);
if (dependencyObject != null &&
!AssociatedObjectTypeConstraint.IsInstanceOfType(dependencyObject))
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture,
ExceptionStringTable.TypeConstraintViolatedExceptionMessage,
new object[]
{GetType().Name, dependencyObject.GetType().Name, AssociatedObjectTypeConstraint.Name}));
WritePreamble();
_associatedObject = dependencyObject;
WritePostscript();
OnAttached();
}
}
public void Detach()
{
OnDetaching();
WritePreamble();
_associatedObject = null;
WritePostscript();
}
DependencyObject IAttachedObject.AssociatedObject =>
AssociatedObject;
internal void CallInvoke(object parameter)
{
if (IsEnabled)
Invoke(parameter);
}
protected override Freezable CreateInstanceCore()
{
return (Freezable) Activator.CreateInstance(GetType());
}
protected abstract void Invoke(object parameter);
protected virtual void OnAttached()
{
}
protected virtual void OnDetaching()
{
}
}
@@ -1,45 +0,0 @@
using System;
using System.Windows;
namespace HandyControl.Interactivity;
public class TriggerActionCollection : AttachableCollection<TriggerAction>
{
internal TriggerActionCollection()
{
}
protected override Freezable CreateInstanceCore()
{
return new TriggerActionCollection();
}
internal override void ItemAdded(TriggerAction item)
{
if (item.IsHosted)
throw new InvalidOperationException(ExceptionStringTable
.CannotHostTriggerActionMultipleTimesExceptionMessage);
if (AssociatedObject != null)
item.Attach(AssociatedObject);
item.IsHosted = true;
}
internal override void ItemRemoved(TriggerAction item)
{
if (((IAttachedObject) item).AssociatedObject != null)
item.Detach();
item.IsHosted = false;
}
protected override void OnAttached()
{
foreach (var action in this)
action.Attach(AssociatedObject);
}
protected override void OnDetaching()
{
foreach (var action in this)
action.Detach();
}
}
@@ -1,18 +0,0 @@
using System;
using System.Windows;
namespace HandyControl.Interactivity;
public abstract class TriggerAction<T> : TriggerAction where T : DependencyObject
{
protected TriggerAction() : base(typeof(T))
{
}
#pragma warning disable 108,114
protected T AssociatedObject => (T) base.AssociatedObject;
#pragma warning restore 108,114
protected sealed override Type AssociatedObjectTypeConstraint =>
base.AssociatedObjectTypeConstraint;
}
@@ -1,109 +0,0 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Markup;
using System.Windows.Media.Animation;
namespace HandyControl.Interactivity;
[ContentProperty("Actions")]
public abstract class TriggerBase : Animatable, IAttachedObject
{
private static readonly DependencyPropertyKey ActionsPropertyKey =
DependencyProperty.RegisterReadOnly("Actions", typeof(TriggerActionCollection), typeof(TriggerBase),
new FrameworkPropertyMetadata());
public static readonly DependencyProperty ActionsProperty = ActionsPropertyKey.DependencyProperty;
private DependencyObject _associatedObject;
private readonly Type _associatedObjectTypeConstraint;
internal TriggerBase(Type associatedObjectTypeConstraint)
{
_associatedObjectTypeConstraint = associatedObjectTypeConstraint;
var actions = new TriggerActionCollection();
SetValue(ActionsPropertyKey, actions);
}
public TriggerActionCollection Actions =>
(TriggerActionCollection) GetValue(ActionsProperty);
protected DependencyObject AssociatedObject
{
get
{
ReadPreamble();
return _associatedObject;
}
}
protected virtual Type AssociatedObjectTypeConstraint
{
get
{
ReadPreamble();
return _associatedObjectTypeConstraint;
}
}
public void Attach(DependencyObject dependencyObject)
{
if (!Equals(dependencyObject, AssociatedObject))
{
if (AssociatedObject != null)
throw new InvalidOperationException(ExceptionStringTable
.CannotHostTriggerMultipleTimesExceptionMessage);
if (dependencyObject != null &&
!AssociatedObjectTypeConstraint.IsInstanceOfType(dependencyObject))
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture,
ExceptionStringTable.TypeConstraintViolatedExceptionMessage,
new object[]
{GetType().Name, dependencyObject.GetType().Name, AssociatedObjectTypeConstraint.Name}));
WritePreamble();
_associatedObject = dependencyObject;
WritePostscript();
Actions.Attach(dependencyObject);
OnAttached();
}
}
public void Detach()
{
OnDetaching();
WritePreamble();
_associatedObject = null;
WritePostscript();
Actions.Detach();
}
DependencyObject IAttachedObject.AssociatedObject =>
AssociatedObject;
public event EventHandler<PreviewInvokeEventArgs> PreviewInvoke;
protected override Freezable CreateInstanceCore()
{
return (Freezable) Activator.CreateInstance(GetType());
}
protected void InvokeActions(object parameter)
{
if (PreviewInvoke != null)
{
var e = new PreviewInvokeEventArgs();
PreviewInvoke(this, e);
if (e.Cancelling)
return;
}
foreach (var action in Actions)
action.CallInvoke(parameter);
}
protected virtual void OnAttached()
{
}
protected virtual void OnDetaching()
{
}
}
@@ -1,41 +0,0 @@
using System.Windows;
namespace HandyControl.Interactivity;
public sealed class TriggerCollection : AttachableCollection<TriggerBase>
{
internal TriggerCollection()
{
}
protected override void OnAttached()
{
foreach (var triggerBase in this)
triggerBase.Attach(AssociatedObject);
}
protected override void OnDetaching()
{
foreach (var triggerBase in this)
triggerBase.Detach();
}
internal override void ItemAdded(TriggerBase item)
{
if (AssociatedObject == null)
return;
item.Attach(AssociatedObject);
}
internal override void ItemRemoved(TriggerBase item)
{
if (((IAttachedObject) item).AssociatedObject == null)
return;
item.Detach();
}
protected override Freezable CreateInstanceCore()
{
return new TriggerCollection();
}
}
@@ -1,14 +0,0 @@
using System;
namespace HandyControl.Interactivity;
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public sealed class TypeConstraintAttribute : Attribute
{
public TypeConstraintAttribute(Type constraint)
{
Constraint = constraint;
}
public Type Constraint { get; }
}