124 lines
4.1 KiB
C#
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);
|
|
}
|
|
}
|
|
} |