Files
HandyControl/Net35/HandyControl_Net35/Interactivity/NameResolver.cs
T
2019-01-21 00:43:10 +08:00

124 lines
4.1 KiB
C#

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