|
|
@@ -1,7 +1,9 @@
|
|
|
+using System;
|
|
|
+using System.Collections.Generic;
|
|
|
using Avalonia.Controls.Platform;
|
|
|
-using Avalonia.LogicalTree;
|
|
|
using Avalonia.Platform;
|
|
|
using Avalonia.Threading;
|
|
|
+using Avalonia.VisualTree;
|
|
|
|
|
|
namespace Avalonia.Controls
|
|
|
{
|
|
|
@@ -12,14 +14,18 @@ namespace Avalonia.Controls
|
|
|
private INativeControlHostControlTopLevelAttachment _attachment;
|
|
|
private IPlatformHandle _nativeControlHandle;
|
|
|
private bool _queuedForDestruction;
|
|
|
+ private bool _queuedForMoveResize;
|
|
|
+ private readonly List<Visual> _propertyChangedSubscriptions = new List<Visual>();
|
|
|
+ private readonly EventHandler<AvaloniaPropertyChangedEventArgs> _propertyChangedHandler;
|
|
|
static NativeControlHost()
|
|
|
{
|
|
|
IsVisibleProperty.Changed.AddClassHandler<NativeControlHost>(OnVisibleChanged);
|
|
|
- TransformedBoundsProperty.Changed.AddClassHandler<NativeControlHost>(OnBoundsChanged);
|
|
|
}
|
|
|
|
|
|
- private static void OnBoundsChanged(NativeControlHost host, AvaloniaPropertyChangedEventArgs arg2)
|
|
|
- => host.UpdateHost();
|
|
|
+ public NativeControlHost()
|
|
|
+ {
|
|
|
+ _propertyChangedHandler = PropertyChangedHandler;
|
|
|
+ }
|
|
|
|
|
|
private static void OnVisibleChanged(NativeControlHost host, AvaloniaPropertyChangedEventArgs arg2)
|
|
|
=> host.UpdateHost();
|
|
|
@@ -27,21 +33,46 @@ namespace Avalonia.Controls
|
|
|
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
|
|
|
{
|
|
|
_currentRoot = e.Root as TopLevel;
|
|
|
+ var visual = (IVisual)this;
|
|
|
+ while (visual != _currentRoot)
|
|
|
+ {
|
|
|
+
|
|
|
+ if (visual is Visual v)
|
|
|
+ {
|
|
|
+ v.PropertyChanged += _propertyChangedHandler;
|
|
|
+ _propertyChangedSubscriptions.Add(v);
|
|
|
+ }
|
|
|
+
|
|
|
+ visual = visual.GetVisualParent();
|
|
|
+ }
|
|
|
+
|
|
|
UpdateHost();
|
|
|
}
|
|
|
|
|
|
+ private void PropertyChangedHandler(object sender, AvaloniaPropertyChangedEventArgs e)
|
|
|
+ {
|
|
|
+ if (e.IsEffectiveValueChange && e.Property == BoundsProperty)
|
|
|
+ EnqueueForMoveResize();
|
|
|
+ }
|
|
|
+
|
|
|
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
|
|
|
{
|
|
|
_currentRoot = null;
|
|
|
+ if (_propertyChangedSubscriptions != null)
|
|
|
+ {
|
|
|
+ foreach (var v in _propertyChangedSubscriptions)
|
|
|
+ v.PropertyChanged -= _propertyChangedHandler;
|
|
|
+ _propertyChangedSubscriptions.Clear();
|
|
|
+ }
|
|
|
UpdateHost();
|
|
|
}
|
|
|
|
|
|
|
|
|
- void UpdateHost()
|
|
|
+ private void UpdateHost()
|
|
|
{
|
|
|
+ _queuedForMoveResize = false;
|
|
|
_currentHost = (_currentRoot?.PlatformImpl as ITopLevelImplWithNativeControlHost)?.NativeControlHost;
|
|
|
var needsAttachment = _currentHost != null;
|
|
|
- var needsShow = needsAttachment && IsEffectivelyVisible && TransformedBounds.HasValue;
|
|
|
|
|
|
if (needsAttachment)
|
|
|
{
|
|
|
@@ -93,22 +124,46 @@ namespace Avalonia.Controls
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (needsShow)
|
|
|
- _attachment?.ShowInBounds(TransformedBounds.Value);
|
|
|
- else if (needsAttachment)
|
|
|
- _attachment?.Hide();
|
|
|
+ if (_attachment?.AttachedTo != _currentHost)
|
|
|
+ return;
|
|
|
+
|
|
|
+ TryUpdateNativeControlPosition();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private Rect? GetAbsoluteBounds()
|
|
|
+ {
|
|
|
+ var bounds = Bounds;
|
|
|
+ var position = this.TranslatePoint(bounds.Position, _currentRoot);
|
|
|
+ if (position == null)
|
|
|
+ return null;
|
|
|
+ return new Rect(position.Value, bounds.Size);
|
|
|
+ }
|
|
|
+
|
|
|
+ void EnqueueForMoveResize()
|
|
|
+ {
|
|
|
+ if(_queuedForMoveResize)
|
|
|
+ return;
|
|
|
+ _queuedForMoveResize = true;
|
|
|
+ Dispatcher.UIThread.Post(UpdateHost, DispatcherPriority.Render);
|
|
|
}
|
|
|
|
|
|
public bool TryUpdateNativeControlPosition()
|
|
|
{
|
|
|
- var needsShow = _currentHost != null && IsEffectivelyVisible && TransformedBounds.HasValue;
|
|
|
+ if (_currentHost == null)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ var bounds = GetAbsoluteBounds();
|
|
|
+ var needsShow = IsEffectivelyVisible && bounds.HasValue;
|
|
|
|
|
|
- if(needsShow)
|
|
|
- _attachment?.ShowInBounds(TransformedBounds.Value);
|
|
|
- return needsShow;
|
|
|
+ if (needsShow)
|
|
|
+ _attachment?.ShowInBounds(bounds.Value);
|
|
|
+ else
|
|
|
+ _attachment?.HideWithSize(Bounds.Size);
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
- void CheckDestruction()
|
|
|
+ private void CheckDestruction()
|
|
|
{
|
|
|
_queuedForDestruction = false;
|
|
|
if (_currentRoot == null)
|
|
|
@@ -117,10 +172,12 @@ namespace Avalonia.Controls
|
|
|
|
|
|
protected virtual IPlatformHandle CreateNativeControlCore(IPlatformHandle parent)
|
|
|
{
|
|
|
+ if (_currentHost == null)
|
|
|
+ throw new InvalidOperationException();
|
|
|
return _currentHost.CreateDefaultChild(parent);
|
|
|
}
|
|
|
|
|
|
- void DestroyNativeControl()
|
|
|
+ private void DestroyNativeControl()
|
|
|
{
|
|
|
if (_nativeControlHandle != null)
|
|
|
{
|