From ccbd277e8bf46f31efeeb7c8a9b428b4a9a9eaf6 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Wed, 24 Nov 2021 10:23:18 +0100 Subject: [PATCH 1/4] feat(ContentPresenter): Content of ContentPresenter should become DataContext of the subtree whenever ContentTemplate is not null --- .../Presenters/ContentPresenter.cs | 53 +++++++++++++++---- 1 file changed, 42 insertions(+), 11 deletions(-) diff --git a/src/Avalonia.Controls/Presenters/ContentPresenter.cs b/src/Avalonia.Controls/Presenters/ContentPresenter.cs index 9886dd913a..93acd88fb1 100644 --- a/src/Avalonia.Controls/Presenters/ContentPresenter.cs +++ b/src/Avalonia.Controls/Presenters/ContentPresenter.cs @@ -107,9 +107,6 @@ namespace Avalonia.Controls.Presenters AffectsRender(BackgroundProperty, BorderBrushProperty, BorderThicknessProperty, CornerRadiusProperty); AffectsArrange(HorizontalContentAlignmentProperty, VerticalContentAlignmentProperty); AffectsMeasure(BorderThicknessProperty, PaddingProperty); - ContentProperty.Changed.AddClassHandler((x, e) => x.ContentChanged(e)); - ContentTemplateProperty.Changed.AddClassHandler((x, e) => x.ContentChanged(e)); - TemplatedParentProperty.Changed.AddClassHandler((x, e) => x.TemplatedParentChanged(e)); } public ContentPresenter() @@ -240,6 +237,21 @@ namespace Avalonia.Controls.Presenters } } + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + switch (change.Property.Name) + { + case nameof(Content): + case nameof(ContentTemplate): + ContentChanged(change); + break; + case nameof(TemplatedParent): + TemplatedParentChanged(change); + break; + } + } + /// /// Updates the control based on the control's . /// @@ -254,8 +266,14 @@ namespace Avalonia.Controls.Presenters public void UpdateChild() { var content = Content; + UpdateChild(content); + } + + private void UpdateChild(object? content) + { + var contentTemplate = ContentTemplate; var oldChild = Child; - var newChild = CreateChild(); + var newChild = CreateChild(content, oldChild, contentTemplate); var logicalChildren = Host?.LogicalChildren ?? LogicalChildren; // Remove the old child if we're not recycling it. @@ -271,7 +289,7 @@ namespace Avalonia.Controls.Presenters } // Set the DataContext if the data isn't a control. - if (!(content is IControl)) + if (contentTemplate is { } || !(content is IControl)) { DataContext = content; } @@ -299,6 +317,7 @@ namespace Avalonia.Controls.Presenters } _createdChild = true; + } /// @@ -325,18 +344,23 @@ namespace Avalonia.Controls.Presenters { var content = Content; var oldChild = Child; + return CreateChild(content, oldChild, ContentTemplate); + } + + private IControl? CreateChild(object? content, IControl? oldChild, IDataTemplate? template) + { var newChild = content as IControl; // We want to allow creating Child from the Template, if Content is null. // But it's important to not use DataTemplates, otherwise we will break content presenters in many places, // otherwise it will blow up every ContentPresenter without Content set. - if (newChild == null - && (content != null || ContentTemplate != null)) + if ((newChild == null + && (content != null || template != null)) || (newChild is { } && template is { })) { - var dataTemplate = this.FindDataTemplate(content, ContentTemplate) ?? + var dataTemplate = this.FindDataTemplate(content, template) ?? ( - RecognizesAccessKey - ? FuncDataTemplate.Access + RecognizesAccessKey + ? FuncDataTemplate.Access : FuncDataTemplate.Default ); @@ -446,7 +470,14 @@ namespace Avalonia.Controls.Presenters if (((ILogical)this).IsAttachedToLogicalTree) { - UpdateChild(); + if (e.Property.Name == nameof(Content)) + { + UpdateChild(e.NewValue); + } + else + { + UpdateChild(); + } } else if (Child != null) { From e2e3eba71d8e74574c7bd9416832f4b30e620b54 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Thu, 10 Mar 2022 18:35:22 +0100 Subject: [PATCH 2/4] add test --- .../ContentPresenterTests_InTemplate.cs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_InTemplate.cs b/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_InTemplate.cs index a579e869b0..76a47ea3d1 100644 --- a/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_InTemplate.cs +++ b/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_InTemplate.cs @@ -353,6 +353,30 @@ namespace Avalonia.Controls.UnitTests.Presenters Assert.Null(target.Host); } + [Fact] + public void Content_Should_Become_Datacontext_When_ControlTemplate_Is_Not_Null() + { + var (target, _) = CreateTarget(); + + var textBlock = new TextBlock + { + [!TextBlock.TextProperty] = new Binding("Name"), + }; + + var canvas = new Canvas() + { + Name ="Canvas", + }; + + target.ContentTemplate = new FuncDataTemplate((_, __) => textBlock); + target.Content = canvas; + + Assert.NotNull(target.DataContext); + Assert.Equal(canvas, target.DataContext); + Assert.Equal("Canvas", textBlock.Text); + } + + (ContentPresenter presenter, ContentControl templatedParent) CreateTarget() { var templatedParent = new ContentControl From ed85fb770ef2d0eb63244a1f765ec20243daf9e9 Mon Sep 17 00:00:00 2001 From: Jumar Macato <16554748+jmacato@users.noreply.github.com> Date: Fri, 11 Mar 2022 22:10:35 +0800 Subject: [PATCH 3/4] Update ContentPresenterTests_InTemplate.cs --- .../Presenters/ContentPresenterTests_InTemplate.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_InTemplate.cs b/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_InTemplate.cs index 76a47ea3d1..c0d475842a 100644 --- a/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_InTemplate.cs +++ b/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_InTemplate.cs @@ -376,7 +376,6 @@ namespace Avalonia.Controls.UnitTests.Presenters Assert.Equal("Canvas", textBlock.Text); } - (ContentPresenter presenter, ContentControl templatedParent) CreateTarget() { var templatedParent = new ContentControl From 6e8c5f9927222605879b65c715cff7da4b0c80f2 Mon Sep 17 00:00:00 2001 From: Jumar Macato <16554748+jmacato@users.noreply.github.com> Date: Fri, 11 Mar 2022 22:11:18 +0800 Subject: [PATCH 4/4] Update ContentPresenterTests_InTemplate.cs --- .../Presenters/ContentPresenterTests_InTemplate.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_InTemplate.cs b/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_InTemplate.cs index c0d475842a..6d20c72674 100644 --- a/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_InTemplate.cs +++ b/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_InTemplate.cs @@ -354,7 +354,7 @@ namespace Avalonia.Controls.UnitTests.Presenters } [Fact] - public void Content_Should_Become_Datacontext_When_ControlTemplate_Is_Not_Null() + public void Content_Should_Become_DataContext_When_ControlTemplate_Is_Not_Null() { var (target, _) = CreateTarget(); @@ -365,7 +365,7 @@ namespace Avalonia.Controls.UnitTests.Presenters var canvas = new Canvas() { - Name ="Canvas", + Name = "Canvas" }; target.ContentTemplate = new FuncDataTemplate((_, __) => textBlock);