From 11c1543b5a53301cc6d6ff9ae2c74085242566a5 Mon Sep 17 00:00:00 2001 From: Lubomir Tetak Date: Mon, 22 Nov 2021 10:53:25 +0100 Subject: [PATCH 01/34] Handle default actions to prevent beeping sounds --- samples/ControlCatalog/Pages/DialogsPage.xaml.cs | 3 ++- src/Avalonia.Controls/Button.cs | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/samples/ControlCatalog/Pages/DialogsPage.xaml.cs b/samples/ControlCatalog/Pages/DialogsPage.xaml.cs index 49921fb7f6..cc1b8e4f5a 100644 --- a/samples/ControlCatalog/Pages/DialogsPage.xaml.cs +++ b/samples/ControlCatalog/Pages/DialogsPage.xaml.cs @@ -128,7 +128,8 @@ namespace ControlCatalog.Pages (button = new Button { HorizontalAlignment = HorizontalAlignment.Center, - Content = "Click to close" + Content = "Click to close", + IsDefault = true }) } }, diff --git a/src/Avalonia.Controls/Button.cs b/src/Avalonia.Controls/Button.cs index 8b22cdd4ec..34180225e0 100644 --- a/src/Avalonia.Controls/Button.cs +++ b/src/Avalonia.Controls/Button.cs @@ -547,6 +547,7 @@ namespace Avalonia.Controls if (e.Key == Key.Enter && IsVisible && IsEnabled) { OnClick(); + e.Handled = true; } } @@ -560,6 +561,7 @@ namespace Avalonia.Controls if (e.Key == Key.Escape && IsVisible && IsEnabled) { OnClick(); + e.Handled = true; } } From ccbd277e8bf46f31efeeb7c8a9b428b4a9a9eaf6 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Wed, 24 Nov 2021 10:23:18 +0100 Subject: [PATCH 02/34] 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 03/34] 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 ad9b7c1027f50f11e89f9117fcecda2cbdb85377 Mon Sep 17 00:00:00 2001 From: Tim U Date: Fri, 11 Mar 2022 12:47:07 +0100 Subject: [PATCH 04/34] Switch disposing order for TwoWayBindingDisposable --- src/Avalonia.Base/Data/BindingOperations.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Base/Data/BindingOperations.cs b/src/Avalonia.Base/Data/BindingOperations.cs index 5353e8175d..0c38f78c83 100644 --- a/src/Avalonia.Base/Data/BindingOperations.cs +++ b/src/Avalonia.Base/Data/BindingOperations.cs @@ -116,8 +116,8 @@ namespace Avalonia.Data return; } - _first.Dispose(); _second.Dispose(); + _first.Dispose(); _isDisposed = true; } 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 05/34] 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 06/34] 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); From 3d0a13d2ba2a5fb733d0d0c6fd9337d435bf1e97 Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 4 Mar 2022 22:04:48 +0100 Subject: [PATCH 07/34] Add TransitioningContentControl-DemoPage --- samples/ControlCatalog/ControlCatalog.csproj | 6 + samples/ControlCatalog/MainView.xaml | 3 + .../TransitioningContentControlPage.axaml | 35 ++++++ .../TransitioningContentControlPage.axaml.cs | 19 +++ ...ransitioningContentControlPageViewModel.cs | 110 ++++++++++++++++++ 5 files changed, 173 insertions(+) create mode 100644 samples/ControlCatalog/Pages/TransitioningContentControlPage.axaml create mode 100644 samples/ControlCatalog/Pages/TransitioningContentControlPage.axaml.cs create mode 100644 samples/ControlCatalog/ViewModels/TransitioningContentControlPageViewModel.cs diff --git a/samples/ControlCatalog/ControlCatalog.csproj b/samples/ControlCatalog/ControlCatalog.csproj index c0e24357ca..117a9fad61 100644 --- a/samples/ControlCatalog/ControlCatalog.csproj +++ b/samples/ControlCatalog/ControlCatalog.csproj @@ -28,5 +28,11 @@ + + + TransitioningContentControlPage.axaml + + + diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml index facce2aa82..f3b52428ca 100644 --- a/samples/ControlCatalog/MainView.xaml +++ b/samples/ControlCatalog/MainView.xaml @@ -145,6 +145,9 @@ + + + diff --git a/samples/ControlCatalog/Pages/TransitioningContentControlPage.axaml b/samples/ControlCatalog/Pages/TransitioningContentControlPage.axaml new file mode 100644 index 0000000000..20cd78abd3 --- /dev/null +++ b/samples/ControlCatalog/Pages/TransitioningContentControlPage.axaml @@ -0,0 +1,35 @@ + + + + + + + + The TransitioningContentControl control allows you to show a page transition whenever the Content changes. + + + + Select a transition + + + + +