* 调整AtomLayer,对Adorner提供Bounds;

This commit is contained in:
zeroone 2024-09-07 13:32:40 +08:00
parent 0e379e0d3c
commit 60e232ff43
4 changed files with 62 additions and 41 deletions

8
Directory.Build.targets Normal file
View File

@ -0,0 +1,8 @@
<Project>
<!-- https://github.com/dotnet/sdk/issues/22515-->
<ItemGroup>
<None Remove="*.csproj.DotSettings" />
</ItemGroup>
</Project>

View File

@ -34,15 +34,4 @@
<ProjectReference Include="..\..\src\AtomUI.Theme\AtomUI.Theme.csproj" />
</ItemGroup>
<ItemGroup>
<AdditionalFiles Include="ShowCase\ButtonSpinnerShowCase.axaml" />
<AdditionalFiles Include="ShowCase\GroupBoxShowCase.axaml" />
</ItemGroup>
<ItemGroup>
<Compile Update="ShowCase\DropdownButtonShowCase.axaml.cs">
<DependentUpon>DropdownButtonShowCase.axaml</DependentUpon>
</Compile>
</ItemGroup>
</Project>

View File

@ -1,6 +1,7 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Threading;
using Rect = Avalonia.Rect;
// ReSharper disable SuggestBaseTypeForParameter
@ -26,24 +27,35 @@ namespace AtomUI.Controls.Primitives
public static readonly AttachedProperty<Visual> TargetProperty = AvaloniaProperty
.RegisterAttached<AtomLayer, Control, Visual>("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<Rect> TargetRectProperty = AvaloniaProperty
.RegisterAttached<AtomLayer, Control, Rect>("TargetRect");
#endregion
public Visual? Host
{
get => GetValue(HostProperty);
set => SetValue(HostProperty, value);
}
public static readonly StyledProperty<Visual?> HostProperty = AvaloniaProperty
.Register<AtomLayer, Visual?>(nameof(Host));
public Vector HostOffset
{
get => GetValue(HostOffsetProperty);
set => SetValue(HostOffsetProperty, value);
}
public static readonly StyledProperty<Vector> HostOffsetProperty = AvaloniaProperty
.Register<AtomLayer, Vector>(nameof(HostOffset));
private readonly IList<WeakReference<Control>> _detachedAdorners = new List<WeakReference<Control>>();
internal Visual? ParentHost { get; set; }
static AtomLayer()
{
HostOffsetProperty.Changed.AddClassHandler<AtomLayer>((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)

View File

@ -15,7 +15,7 @@ public static class AtomLayerExtension
return null;
}
var host = visual.FindAncestorOfType<ScrollContentPresenter>(true)?.Content as Visual
var host = visual.FindAncestorOfType<ScrollContentPresenter>() 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;
}