From 8351932bf6635b8075c8a9be69de8f3da6d439c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Sat, 24 Sep 2022 14:39:44 +0200 Subject: [PATCH 1/5] Set control adorner from xaml --- samples/ControlCatalog/MainView.xaml | 3 + .../Pages/AdornerLayerPage.xaml | 30 ++++++++ .../Pages/AdornerLayerPage.xaml.cs | 19 +++++ .../Primitives/AdornerLayer.cs | 72 +++++++++++++++++++ 4 files changed, 124 insertions(+) create mode 100644 samples/ControlCatalog/Pages/AdornerLayerPage.xaml create mode 100644 samples/ControlCatalog/Pages/AdornerLayerPage.xaml.cs diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml index 7f5a191519..ec198c6bba 100644 --- a/samples/ControlCatalog/MainView.xaml +++ b/samples/ControlCatalog/MainView.xaml @@ -19,6 +19,9 @@ + + + diff --git a/samples/ControlCatalog/Pages/AdornerLayerPage.xaml b/samples/ControlCatalog/Pages/AdornerLayerPage.xaml new file mode 100644 index 0000000000..853bae4695 --- /dev/null +++ b/samples/ControlCatalog/Pages/AdornerLayerPage.xaml @@ -0,0 +1,30 @@ + + + + + diff --git a/samples/ControlCatalog/Pages/AdornerLayerPage.xaml.cs b/samples/ControlCatalog/Pages/AdornerLayerPage.xaml.cs new file mode 100644 index 0000000000..2a9e5bf9ba --- /dev/null +++ b/samples/ControlCatalog/Pages/AdornerLayerPage.xaml.cs @@ -0,0 +1,19 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace ControlCatalog.Pages +{ + public class AdornerLayerPage : UserControl + { + public AdornerLayerPage() + { + this.InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + } +} diff --git a/src/Avalonia.Controls/Primitives/AdornerLayer.cs b/src/Avalonia.Controls/Primitives/AdornerLayer.cs index 57fb7226e8..51975ccd1a 100644 --- a/src/Avalonia.Controls/Primitives/AdornerLayer.cs +++ b/src/Avalonia.Controls/Primitives/AdornerLayer.cs @@ -27,6 +27,12 @@ namespace Avalonia.Controls.Primitives public static readonly AttachedProperty IsClipEnabledProperty = AvaloniaProperty.RegisterAttached("IsClipEnabled", true); + /// + /// Allows for getting and setting of the adorner for control. + /// + public static readonly AttachedProperty AdornerProperty = + AvaloniaProperty.RegisterAttached("Adorner"); + private static readonly AttachedProperty s_adornedElementInfoProperty = AvaloniaProperty.RegisterAttached("AdornedElementInfo"); @@ -65,6 +71,72 @@ namespace Avalonia.Controls.Primitives adorner.SetValue(IsClipEnabledProperty, isClipEnabled); } + public static Control? GetAdorner(Visual visual) + { + return visual.GetValue(AdornerProperty); + } + + public static void SetAdorner(Visual visual, Control? adorner) + { + visual.SetValue(AdornerProperty, adorner); + + SetVisualAdorner(visual, adorner); + } + + private static void SetVisualAdorner(Visual visual, Control? adorner) + { + var layer = default(AdornerLayer); + + visual.AttachedToVisualTree += (_, _) => + { + layer = AddVisualAdorner(visual, adorner); + }; + + visual.DetachedFromVisualTree += (_, _) => + { + RemoveVisualAdorner(visual, adorner, layer); + }; + } + + private static AdornerLayer? AddVisualAdorner(Visual visual, Control? adorner) + { + if (adorner is null) + { + return null; + } + + var layer = AdornerLayer.GetAdornerLayer(visual); + if (layer == null || layer.Children.Contains(adorner)) + { + return layer; + } + + AdornerLayer.SetAdornedElement(adorner, visual); + AdornerLayer.SetIsClipEnabled(adorner, false); + + ((ISetLogicalParent) adorner).SetParent(visual); + layer.Children.Add(adorner); + + return layer; + } + + private static void RemoveVisualAdorner(Visual visual, Control? adorner, AdornerLayer? layer) + { + if (adorner is null) + { + return; + } + + // var layer = AdornerLayer.GetAdornerLayer(visual); + if (layer is null || !layer.Children.Contains(adorner)) + { + return; + } + + layer.Children.Remove(adorner); + ((ISetLogicalParent) adorner).SetParent(null); + } + protected override Size MeasureOverride(Size availableSize) { foreach (var child in Children) From db35037dfb0ce9fe46b311b97635186ea7bc3601 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Sat, 24 Sep 2022 14:48:23 +0200 Subject: [PATCH 2/5] Add LayoutTransformControl --- .../Pages/AdornerLayerPage.xaml | 66 +++++++++++++------ 1 file changed, 45 insertions(+), 21 deletions(-) diff --git a/samples/ControlCatalog/Pages/AdornerLayerPage.xaml b/samples/ControlCatalog/Pages/AdornerLayerPage.xaml index 853bae4695..8bf948c58d 100644 --- a/samples/ControlCatalog/Pages/AdornerLayerPage.xaml +++ b/samples/ControlCatalog/Pages/AdornerLayerPage.xaml @@ -6,25 +6,49 @@ d:DesignHeight="800" d:DesignWidth="400" mc:Ignorable="d"> - - - + + + + Rotation + + + + + + + + + + + + + + + + + + + + From 82aebeeb34846ddf1f3df578b1b208b0992a2de6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Sun, 25 Sep 2022 13:09:04 +0200 Subject: [PATCH 3/5] Handler Adorner property changes --- .../Primitives/AdornerLayer.cs | 89 +++++++++++++------ 1 file changed, 64 insertions(+), 25 deletions(-) diff --git a/src/Avalonia.Controls/Primitives/AdornerLayer.cs b/src/Avalonia.Controls/Primitives/AdornerLayer.cs index 51975ccd1a..d557424fbb 100644 --- a/src/Avalonia.Controls/Primitives/AdornerLayer.cs +++ b/src/Avalonia.Controls/Primitives/AdornerLayer.cs @@ -36,9 +36,13 @@ namespace Avalonia.Controls.Primitives private static readonly AttachedProperty s_adornedElementInfoProperty = AvaloniaProperty.RegisterAttached("AdornedElementInfo"); + private static readonly AttachedProperty s_savedAdornerLayerProperty = + AvaloniaProperty.RegisterAttached("SavedAdornerLayer"); + static AdornerLayer() { AdornedElementProperty.Changed.Subscribe(AdornedElementChanged); + AdornerProperty.Changed.Subscribe(AdornerChanged); } public AdornerLayer() @@ -79,36 +83,79 @@ namespace Avalonia.Controls.Primitives public static void SetAdorner(Visual visual, Control? adorner) { visual.SetValue(AdornerProperty, adorner); - - SetVisualAdorner(visual, adorner); } - private static void SetVisualAdorner(Visual visual, Control? adorner) + private static void AdornerChanged(AvaloniaPropertyChangedEventArgs e) { - var layer = default(AdornerLayer); - - visual.AttachedToVisualTree += (_, _) => + if (e.Sender is Visual visual) { - layer = AddVisualAdorner(visual, adorner); - }; + var oldAdorner = e.OldValue.GetValueOrDefault(); + var newAdorner = e.NewValue.GetValueOrDefault(); + + if (Equals(oldAdorner, newAdorner)) + { + return; + } + + if (oldAdorner is { }) + { + visual.AttachedToVisualTree -= VisualOnAttachedToVisualTree; + visual.DetachedFromVisualTree -= VisualOnDetachedFromVisualTree; + Detach(visual, oldAdorner); + } - visual.DetachedFromVisualTree += (_, _) => + if (newAdorner is { }) + { + visual.AttachedToVisualTree += VisualOnAttachedToVisualTree; + visual.DetachedFromVisualTree += VisualOnDetachedFromVisualTree; + Attach(visual, newAdorner); + } + } + } + + private static void VisualOnAttachedToVisualTree(object? sender, VisualTreeAttachmentEventArgs e) + { + if (sender is Visual visual) { - RemoveVisualAdorner(visual, adorner, layer); - }; + var adorner = GetAdorner(visual); + if (adorner is { }) + { + Attach(visual, adorner); + } + } } - private static AdornerLayer? AddVisualAdorner(Visual visual, Control? adorner) + private static void VisualOnDetachedFromVisualTree(object? sender, VisualTreeAttachmentEventArgs e) { - if (adorner is null) + if (sender is Visual visual) { - return null; + var adorner = GetAdorner(visual); + if (adorner is { }) + { + Detach(visual, adorner); + } } + } + private static void Attach(Visual visual, Control adorner) + { var layer = AdornerLayer.GetAdornerLayer(visual); - if (layer == null || layer.Children.Contains(adorner)) + AddVisualAdorner(visual, adorner, layer); + visual.SetValue(s_savedAdornerLayerProperty, layer); + } + + private static void Detach(Visual visual, Control adorner) + { + var layer = visual.GetValue(s_savedAdornerLayerProperty); + RemoveVisualAdorner(visual, adorner, layer); + visual.ClearValue(s_savedAdornerLayerProperty); + } + + private static void AddVisualAdorner(Visual visual, Control? adorner, AdornerLayer? layer) + { + if (adorner is null || layer == null || layer.Children.Contains(adorner)) { - return layer; + return; } AdornerLayer.SetAdornedElement(adorner, visual); @@ -116,19 +163,11 @@ namespace Avalonia.Controls.Primitives ((ISetLogicalParent) adorner).SetParent(visual); layer.Children.Add(adorner); - - return layer; } private static void RemoveVisualAdorner(Visual visual, Control? adorner, AdornerLayer? layer) { - if (adorner is null) - { - return; - } - - // var layer = AdornerLayer.GetAdornerLayer(visual); - if (layer is null || !layer.Children.Contains(adorner)) + if (adorner is null || layer is null || !layer.Children.Contains(adorner)) { return; } From 272775a3d908e7740f9938985b62d253a4faf89d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Sun, 25 Sep 2022 13:09:29 +0200 Subject: [PATCH 4/5] Format xaml --- .../Pages/AdornerLayerPage.xaml | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/samples/ControlCatalog/Pages/AdornerLayerPage.xaml b/samples/ControlCatalog/Pages/AdornerLayerPage.xaml index 8bf948c58d..7ddbbbfcf1 100644 --- a/samples/ControlCatalog/Pages/AdornerLayerPage.xaml +++ b/samples/ControlCatalog/Pages/AdornerLayerPage.xaml @@ -27,25 +27,25 @@ - + From 4b31690b12c55368181c1726d2975386936f29d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Sun, 25 Sep 2022 13:30:16 +0200 Subject: [PATCH 5/5] Add add / remove adorner buttons for testing --- .../Pages/AdornerLayerPage.xaml | 14 +++++++- .../Pages/AdornerLayerPage.xaml.cs | 33 +++++++++++++++++-- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/samples/ControlCatalog/Pages/AdornerLayerPage.xaml b/samples/ControlCatalog/Pages/AdornerLayerPage.xaml index 7ddbbbfcf1..598844d695 100644 --- a/samples/ControlCatalog/Pages/AdornerLayerPage.xaml +++ b/samples/ControlCatalog/Pages/AdornerLayerPage.xaml @@ -13,6 +13,17 @@ + +