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