diff --git a/Directory.Build.targets b/Directory.Build.targets new file mode 100644 index 0000000..bafae10 --- /dev/null +++ b/Directory.Build.targets @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/samples/AtomUI.Demo.Desktop/AtomUI.Demo.Desktop.csproj b/samples/AtomUI.Demo.Desktop/AtomUI.Demo.Desktop.csproj index 1ed8be0..ea36139 100644 --- a/samples/AtomUI.Demo.Desktop/AtomUI.Demo.Desktop.csproj +++ b/samples/AtomUI.Demo.Desktop/AtomUI.Demo.Desktop.csproj @@ -33,16 +33,5 @@ - - - - - - - - - DropdownButtonShowCase.axaml - - diff --git a/src/AtomUI.Controls/Primitives/AtomLayer/AtomLayer.cs b/src/AtomUI.Controls/Primitives/AtomLayer/AtomLayer.cs index 1b2b7cf..67f476e 100644 --- a/src/AtomUI.Controls/Primitives/AtomLayer/AtomLayer.cs +++ b/src/AtomUI.Controls/Primitives/AtomLayer/AtomLayer.cs @@ -1,6 +1,7 @@ using Avalonia; using Avalonia.Controls; using Avalonia.Threading; +using Rect = Avalonia.Rect; // ReSharper disable SuggestBaseTypeForParameter @@ -25,25 +26,36 @@ namespace AtomUI.Controls.Primitives } public static readonly AttachedProperty TargetProperty = AvaloniaProperty .RegisterAttached("Target"); - - public static Rect GetTargetRect(Control adorner) - { - return adorner.GetValue(TargetRectProperty); - } - private static void SetTargetRect(Control adorner, Rect value) - { - adorner.SetValue(TargetRectProperty, value); - } - public static readonly AttachedProperty TargetRectProperty = AvaloniaProperty - .RegisterAttached("TargetRect"); #endregion + + public Visual? Host + { + get => GetValue(HostProperty); + set => SetValue(HostProperty, value); + } + public static readonly StyledProperty HostProperty = AvaloniaProperty + .Register(nameof(Host)); + + public Vector HostOffset + { + get => GetValue(HostOffsetProperty); + set => SetValue(HostOffsetProperty, value); + } + public static readonly StyledProperty HostOffsetProperty = AvaloniaProperty + .Register(nameof(HostOffset)); private readonly IList> _detachedAdorners = new List>(); - internal Visual? ParentHost { get; set; } + static AtomLayer() + { + HostOffsetProperty.Changed.AddClassHandler((layer, args) => + { + layer.Measure(); + }); + } internal AtomLayer() { } @@ -74,7 +86,19 @@ namespace AtomUI.Controls.Primitives SetTarget(adorner, target); Children.Add(adorner); - Locate(target, adorner); + UpdateLocation(target, adorner); + Arrange(); + } + + private void Measure() + { + Measure(new Size()); + Arrange(); + } + + private void Arrange() + { + Arrange(new Rect(new Point(HostOffset.X, -HostOffset.Y), new Size())); } private void TargetOnPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e) @@ -89,52 +113,47 @@ namespace AtomUI.Controls.Primitives return; } - // Child element's bounds will be updated first. + // Child element's bounds will be updated before it's ancestors do. Dispatcher.UIThread.Post(() => { foreach (var adorner in GetAdorners(target)) { - Locate(target, adorner); + UpdateLocation(target, adorner); } }, DispatcherPriority.Send); } - private void Locate(Visual target, Control adorner) + private void UpdateLocation(Visual target, Control adorner) { - if (this.ParentHost is Control { IsLoaded: false }) + if (this.Host is Control { IsLoaded: false }) { - this.ParentHost.PropertyChanged -= ParentHostOnPropertyChanged; - this.ParentHost.PropertyChanged += ParentHostOnPropertyChanged; + this.Host.PropertyChanged -= ParentHostOnPropertyChanged; + this.Host.PropertyChanged += ParentHostOnPropertyChanged; } else { - LocateCore(target, adorner); + UpdateLocationCore(target, adorner); } return; void ParentHostOnPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e) { - this.ParentHost.PropertyChanged -= ParentHostOnPropertyChanged; - LocateCore(target, adorner); + this.Host.PropertyChanged -= ParentHostOnPropertyChanged; + UpdateLocationCore(target, adorner); } } - private void LocateCore(Visual target, Control adorner) + private void UpdateLocationCore(Visual target, Control adorner) { var matrix = target.TransformToVisual(this)!; var x = matrix.Value.M31; var y = matrix.Value.M32; - var rect = new Rect(x, y, target.Bounds.Width, target.Bounds.Height); - SetTargetRect(adorner, rect); SetLeft(adorner, x); SetTop(adorner, y); adorner.Width = target.Bounds.Width; adorner.Height = target.Bounds.Height; - - adorner.Measure(target.Bounds.Size); - adorner.Arrange(rect); } private void OnTargetOnAttachedToVisualTree(object? sender, VisualTreeAttachmentEventArgs args) diff --git a/src/AtomUI.Controls/Primitives/AtomLayer/AtomLayerExtension.cs b/src/AtomUI.Controls/Primitives/AtomLayer/AtomLayerExtension.cs index 4722e9c..fc21ee6 100644 --- a/src/AtomUI.Controls/Primitives/AtomLayer/AtomLayerExtension.cs +++ b/src/AtomUI.Controls/Primitives/AtomLayer/AtomLayerExtension.cs @@ -15,7 +15,7 @@ public static class AtomLayerExtension return null; } - var host = visual.FindAncestorOfType(true)?.Content as Visual + var host = visual.FindAncestorOfType() as Visual ?? TopLevel.GetTopLevel(visual); if (host == null) @@ -69,7 +69,12 @@ public static class AtomLayerExtension } visualChildren.Add(layer); - layer.ParentHost = host; + layer.Host = host; + + if (host is ScrollContentPresenter presenter) + { + layer[!AtomLayer.HostOffsetProperty] = presenter[!ScrollContentPresenter.OffsetProperty]; + } return true; }