diff --git a/src/Avalonia.Styling/LogicalTree/ControlLocator.cs b/src/Avalonia.Styling/LogicalTree/ControlLocator.cs
index 2858d11d9d..7186143bf9 100644
--- a/src/Avalonia.Styling/LogicalTree/ControlLocator.cs
+++ b/src/Avalonia.Styling/LogicalTree/ControlLocator.cs
@@ -6,6 +6,7 @@ using System.Linq;
using System.Reactive.Linq;
using System.Reflection;
using Avalonia.Controls;
+using Avalonia.Reactive;
namespace Avalonia.LogicalTree
{
@@ -23,75 +24,122 @@ namespace Avalonia.LogicalTree
/// The name of the control to find.
public static IObservable Track(ILogical relativeTo, string name)
{
- var attached = Observable.FromEventPattern(
- x => relativeTo.AttachedToLogicalTree += x,
- x => relativeTo.AttachedToLogicalTree -= x)
- .Select(x => ((ILogical)x.Sender).FindNameScope())
- .StartWith(relativeTo.FindNameScope());
-
- var detached = Observable.FromEventPattern(
- x => relativeTo.DetachedFromLogicalTree += x,
- x => relativeTo.DetachedFromLogicalTree -= x)
- .Select(x => (INameScope)null);
-
- return attached.Merge(detached).Select(nameScope =>
+ return new ControlTracker(relativeTo, name);
+ }
+
+ public static IObservable Track(ILogical relativeTo, int ancestorLevel, Type ancestorType = null)
+ {
+ return new ControlTracker(relativeTo, ancestorLevel, ancestorType);
+ }
+
+ private class ControlTracker : LightweightObservableBase
+ {
+ private readonly ILogical _relativeTo;
+ private readonly string _name;
+ private readonly int _ancestorLevel;
+ private readonly Type _ancestorType;
+ INameScope _nameScope;
+ ILogical _value;
+
+ public ControlTracker(ILogical relativeTo, string name)
+ {
+ _relativeTo = relativeTo;
+ _name = name;
+ }
+
+ public ControlTracker(ILogical relativeTo, int ancestorLevel, Type ancestorType)
{
- if (nameScope != null)
+ _relativeTo = relativeTo;
+ _ancestorLevel = ancestorLevel;
+ _ancestorType = ancestorType;
+ }
+
+ protected override void Initialize()
+ {
+ Update();
+ _relativeTo.AttachedToLogicalTree += Attached;
+ _relativeTo.DetachedFromLogicalTree += Detached;
+ }
+
+ protected override void Deinitialize()
+ {
+ _relativeTo.AttachedToLogicalTree -= Attached;
+ _relativeTo.DetachedFromLogicalTree -= Detached;
+
+ if (_nameScope != null)
{
- var registered = Observable.FromEventPattern(
- x => nameScope.Registered += x,
- x => nameScope.Registered -= x)
- .Where(x => x.EventArgs.Name == name)
- .Select(x => x.EventArgs.Element)
- .OfType();
- var unregistered = Observable.FromEventPattern(
- x => nameScope.Unregistered += x,
- x => nameScope.Unregistered -= x)
- .Where(x => x.EventArgs.Name == name)
- .Select(_ => (ILogical)null);
- return registered
- .StartWith(nameScope.Find(name))
- .Merge(unregistered);
+ _nameScope.Registered -= Registered;
+ _nameScope.Unregistered -= Unregistered;
}
- else
+
+ _value = null;
+ }
+
+ protected override void Subscribed(IObserver observer, bool first)
+ {
+ observer.OnNext(_value);
+ }
+
+ private void Attached(object sender, LogicalTreeAttachmentEventArgs e)
+ {
+ Update();
+ PublishNext(_value);
+ }
+
+ private void Detached(object sender, LogicalTreeAttachmentEventArgs e)
+ {
+ if (_nameScope != null)
{
- return Observable.Return(null);
+ _nameScope.Registered -= Registered;
+ _nameScope.Unregistered -= Unregistered;
}
- }).Switch();
- }
- public static IObservable Track(ILogical relativeTo, int ancestorLevel, Type ancestorType = null)
- {
- return TrackAttachmentToTree(relativeTo).Select(isAttachedToTree =>
+ _value = null;
+ PublishNext(null);
+ }
+
+ private void Registered(object sender, NameScopeEventArgs e)
{
- if (isAttachedToTree)
+ if (e.Name == _name && e.Element is ILogical logical)
{
- return relativeTo.GetLogicalAncestors()
- .Where(x => ancestorType?.GetTypeInfo().IsAssignableFrom(x.GetType().GetTypeInfo()) ?? true)
- .ElementAtOrDefault(ancestorLevel);
+ _value = logical;
+ PublishNext(logical);
}
- else
+ }
+
+ private void Unregistered(object sender, NameScopeEventArgs e)
+ {
+ if (e.Name == _name)
{
- return null;
+ _value = null;
+ PublishNext(null);
}
- });
- }
+ }
- private static IObservable TrackAttachmentToTree(ILogical relativeTo)
- {
- var attached = Observable.FromEventPattern(
- x => relativeTo.AttachedToLogicalTree += x,
- x => relativeTo.AttachedToLogicalTree -= x)
- .Select(x => true)
- .StartWith(relativeTo.IsAttachedToLogicalTree);
-
- var detached = Observable.FromEventPattern(
- x => relativeTo.DetachedFromLogicalTree += x,
- x => relativeTo.DetachedFromLogicalTree -= x)
- .Select(x => false);
-
- var attachmentStatus = attached.Merge(detached);
- return attachmentStatus;
+ private void Update()
+ {
+ if (_name != null)
+ {
+ _nameScope = _relativeTo.FindNameScope();
+
+ if (_nameScope != null)
+ {
+ _nameScope.Registered += Registered;
+ _nameScope.Unregistered += Unregistered;
+ _value = _nameScope.Find(_name);
+ }
+ else
+ {
+ _value = null;
+ }
+ }
+ else
+ {
+ _value = _relativeTo.GetLogicalAncestors()
+ .Where(x => _ancestorType?.GetTypeInfo().IsAssignableFrom(x.GetType().GetTypeInfo()) ?? true)
+ .ElementAtOrDefault(_ancestorLevel);
+ }
+ }
}
}
}
diff --git a/src/Avalonia.Visuals/VisualTree/VisualLocator.cs b/src/Avalonia.Visuals/VisualTree/VisualLocator.cs
index 6fcb6c0db1..eaca9ed9d7 100644
--- a/src/Avalonia.Visuals/VisualTree/VisualLocator.cs
+++ b/src/Avalonia.Visuals/VisualTree/VisualLocator.cs
@@ -1,9 +1,8 @@
using System;
-using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Reflection;
-using System.Text;
+using Avalonia.Reactive;
namespace Avalonia.VisualTree
{
@@ -11,36 +10,54 @@ namespace Avalonia.VisualTree
{
public static IObservable Track(IVisual relativeTo, int ancestorLevel, Type ancestorType = null)
{
- return TrackAttachmentToTree(relativeTo).Select(isAttachedToTree =>
+ return new VisualTracker(relativeTo, ancestorLevel, ancestorType);
+ }
+
+ private class VisualTracker : LightweightObservableBase
+ {
+ private readonly IVisual _relativeTo;
+ private readonly int _ancestorLevel;
+ private readonly Type _ancestorType;
+
+ public VisualTracker(IVisual relativeTo, int ancestorLevel, Type ancestorType)
+ {
+ _relativeTo = relativeTo;
+ _ancestorLevel = ancestorLevel;
+ _ancestorType = ancestorType;
+ }
+
+ protected override void Initialize()
+ {
+ _relativeTo.AttachedToVisualTree += AttachedDetached;
+ _relativeTo.DetachedFromVisualTree += AttachedDetached;
+ }
+
+ protected override void Deinitialize()
{
- if (isAttachedToTree)
+ _relativeTo.AttachedToVisualTree -= AttachedDetached;
+ _relativeTo.DetachedFromVisualTree -= AttachedDetached;
+ }
+
+ protected override void Subscribed(IObserver observer, bool first)
+ {
+ observer.OnNext(GetResult());
+ }
+
+ private void AttachedDetached(object sender, VisualTreeAttachmentEventArgs e) => PublishNext(GetResult());
+
+ private IVisual GetResult()
+ {
+ if (_relativeTo.IsAttachedToVisualTree)
{
- return relativeTo.GetVisualAncestors()
- .Where(x => ancestorType?.GetTypeInfo().IsAssignableFrom(x.GetType().GetTypeInfo()) ?? true)
- .ElementAtOrDefault(ancestorLevel);
+ return _relativeTo.GetVisualAncestors()
+ .Where(x => _ancestorType?.GetTypeInfo().IsAssignableFrom(x.GetType().GetTypeInfo()) ?? true)
+ .ElementAtOrDefault(_ancestorLevel);
}
else
{
return null;
}
- });
- }
-
- private static IObservable TrackAttachmentToTree(IVisual relativeTo)
- {
- var attached = Observable.FromEventPattern(
- x => relativeTo.AttachedToVisualTree += x,
- x => relativeTo.AttachedToVisualTree -= x)
- .Select(x => true)
- .StartWith(relativeTo.IsAttachedToVisualTree);
-
- var detached = Observable.FromEventPattern(
- x => relativeTo.DetachedFromVisualTree += x,
- x => relativeTo.DetachedFromVisualTree -= x)
- .Select(x => false);
-
- var attachmentStatus = attached.Merge(detached);
- return attachmentStatus;
+ }
}
}
}