diff --git a/samples/Sandbox/DrawnDecorationsPresenter.cs b/samples/Sandbox/DrawnDecorationsPresenter.cs new file mode 100644 index 0000000000..104c64a36e --- /dev/null +++ b/samples/Sandbox/DrawnDecorationsPresenter.cs @@ -0,0 +1,161 @@ +using System; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.Metadata; +using Avalonia.Controls.Primitives; +using Avalonia.Controls.Templates; +using Avalonia.LogicalTree; +using Avalonia.Markup.Xaml.Templates; +using Avalonia.Metadata; +using Avalonia.Styling; + +[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Sandbox.Controls")] +namespace Sandbox.Controls; + +public class DrawnDecorationsPresenter : Control +{ + class Wrapper : Control + { + public Control? Inner + { + get=>field; + set + { + if (field == value) + return; + if (field != null) + VisualChildren.Remove(field); + field = value; + if (field != null) + VisualChildren.Add(field); + } + } + } + + private WindowDrawnDecorations _decorations = new WindowDrawnDecorations(); + private Grid _grid = new Grid(); + private Wrapper _overlay = new Wrapper(), _underlay = new Wrapper(); + public DrawnDecorationsPresenter() + { + LogicalChildren.Add(_decorations); + ((ISetLogicalParent)_decorations).SetParent(this); + VisualChildren.Add(_grid); + _grid.Children.Add(_underlay); + _grid.Children.Add(_overlay); + } + + public override void ApplyTemplate() + { + _decorations.ApplyTemplate(); + _overlay.Inner = _decorations.Content?.Overlay; + _underlay.Inner = _decorations.Content?.Underlay; + + base.ApplyTemplate(); + } +} + +[ControlTemplateScope] +public class WindowDrawnDecorationsTemplate : ITemplate +{ + [Content] + [TemplateContent(TemplateResultType = typeof(WindowDrawnDecorationsContent))] + public object? Content { get; set; } + + public TemplateResult Build() => + TemplateContent.Load(Content) ?? throw new InvalidOperationException(); + + object? ITemplate.Build() => Build(); + +} + +public class WindowDrawnDecorationsContent : StyledElement +{ + public Control? Overlay + { + get => field; + set => HandleLogicalChild(ref field, value); + } + + public Control? Underlay + { + get => field; + set => HandleLogicalChild(ref field, value); + } + + void HandleLogicalChild(ref Control? field, Control? value) + { + if (field == value) + return; + if (field != null) + { + LogicalChildren.Remove(field); + ((ISetLogicalParent)field).SetParent(null); + } + + field = value; + if (field != null) + { + LogicalChildren.Add(field); + ((ISetLogicalParent)field).SetParent(this); + } + } +} + +[PseudoClasses(":test")] +public class WindowDrawnDecorations : StyledElement +{ + public WindowDrawnDecorations() + { + PseudoClasses.Add(":test"); + } + + public static readonly StyledProperty TemplateProperty = AvaloniaProperty.Register( + "Template"); + + public WindowDrawnDecorationsTemplate Template + { + get => GetValue(TemplateProperty); + set => SetValue(TemplateProperty, value); + } + + public static readonly StyledProperty TitleBarHeightProperty = AvaloniaProperty.Register( + "TitleBarHeight"); + + public double TitleBarHeight + { + get => GetValue(TitleBarHeightProperty); + set => SetValue(TitleBarHeightProperty, value); + } + + public WindowDrawnDecorationsContent? Content { get; private set; } + + private WindowDrawnDecorationsTemplate? _appliedTemplate; + public void ApplyTemplate() + { + if (Template == _appliedTemplate) + return; + if (Content != null) + { + LogicalChildren.Remove(Content); + ((ISetLogicalParent)Content).SetParent(null); + Content = null; + } + + var res = Template.Build(); + Content = res.Result; + if (Content != null) + { + TemplatedControl.ApplyTemplatedParent(Content, this); + LogicalChildren.Add(Content); + ((ISetLogicalParent)Content).SetParent(this); + } + } +} + +class TestTest : Border +{ + protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e) + { + base.OnAttachedToLogicalTree(e); + } +} \ No newline at end of file diff --git a/samples/Sandbox/MainWindow.axaml b/samples/Sandbox/MainWindow.axaml index 6929f192c7..c7841e6b4d 100644 --- a/samples/Sandbox/MainWindow.axaml +++ b/samples/Sandbox/MainWindow.axaml @@ -1,4 +1,44 @@ + xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' + xmlns:sandbox="clr-namespace:Sandbox" + x:Class="Sandbox.MainWindow"> + + + + + + + + + + + TITLEBAR + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Base/Avalonia.Base.csproj b/src/Avalonia.Base/Avalonia.Base.csproj index ea1dfd766b..d1f91b6523 100644 --- a/src/Avalonia.Base/Avalonia.Base.csproj +++ b/src/Avalonia.Base/Avalonia.Base.csproj @@ -25,6 +25,7 @@ + diff --git a/src/Avalonia.Controls/Avalonia.Controls.csproj b/src/Avalonia.Controls/Avalonia.Controls.csproj index 6e3f40892a..d15e198f36 100644 --- a/src/Avalonia.Controls/Avalonia.Controls.csproj +++ b/src/Avalonia.Controls/Avalonia.Controls.csproj @@ -11,6 +11,7 @@ + diff --git a/src/Avalonia.Controls/Primitives/TemplatedControl.cs b/src/Avalonia.Controls/Primitives/TemplatedControl.cs index d8ecfa99e8..69aa3f7a16 100644 --- a/src/Avalonia.Controls/Primitives/TemplatedControl.cs +++ b/src/Avalonia.Controls/Primitives/TemplatedControl.cs @@ -422,7 +422,7 @@ namespace Avalonia.Controls.Primitives /// /// The control. /// The templated parent to apply. - internal static void ApplyTemplatedParent(StyledElement control, AvaloniaObject? templatedParent) + public static void ApplyTemplatedParent(StyledElement control, AvaloniaObject? templatedParent) { control.TemplatedParent = templatedParent;