From fe1f9d4c77ba5e3f723e5b3ee6e44bc425332b85 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 23 Mar 2023 09:43:30 +0000 Subject: [PATCH 1/4] add a failing unit test. --- .../TreeViewTests.cs | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs b/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs index 4f533c2f78..fbcfd99743 100644 --- a/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs @@ -1091,6 +1091,46 @@ namespace Avalonia.Controls.UnitTests Assert.True(called); } } + + [Fact] + public void SelectedItem_Should_Be_Valid_When_SelectedItemChanged_Event_Raised() + { + using (Application()) + { + var tree = CreateTestTreeData(); + var target = new TreeView + { + Template = CreateTreeViewTemplate(), + ItemsSource = tree, + }; + + var visualRoot = new TestRoot(); + visualRoot.Child = target; + + CreateNodeDataTemplate(target); + ApplyTemplates(target); + ExpandAll(target); + + var item = tree[0].Children[1].Children[0]; + var container = (TreeViewItem)target.TreeContainerFromItem(item); + + Assert.NotNull(container); + + var called = false; + target.SelectionChanged += (s, e) => + { + Assert.Same(item, e.AddedItems[0]); + Assert.Same(item, target.SelectedItem); + called = true; + }; + + _mouse.Click(container); + + Assert.Equal(item, target.SelectedItem); + Assert.True(container.IsSelected); + Assert.True(called); + } + } [Fact] public void Bound_SelectedItem_Should_Not_Be_Cleared_when_Changing_Selection() From e77de043b6286ffbe19b85fede130f693e54f483 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 23 Mar 2023 09:46:11 +0000 Subject: [PATCH 2/4] [TreeView] ensure SelectedItem field is set before Adding items to SelectedItems --- src/Avalonia.Controls/TreeView.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/TreeView.cs b/src/Avalonia.Controls/TreeView.cs index 8f2636a783..194ba37671 100644 --- a/src/Avalonia.Controls/TreeView.cs +++ b/src/Avalonia.Controls/TreeView.cs @@ -303,12 +303,14 @@ namespace Avalonia.Controls private void SelectSingleItem(object item) { + var oldValue = _selectedItem; _syncingSelectedItems = true; - SelectedItems.Clear(); + SelectedItems.Clear(); + _selectedItem = item; SelectedItems.Add(item); _syncingSelectedItems = false; - SetAndRaise(SelectedItemProperty, ref _selectedItem, item); + RaisePropertyChanged(SelectedItemProperty, oldValue, _selectedItem); } /// From faf1d8395006ddc29850dae9cb86a7999ac311f2 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Tue, 28 Mar 2023 08:18:03 +0200 Subject: [PATCH 3/4] Fix merge error. --- .../TreeViewTests.cs | 51 +++++++------------ 1 file changed, 19 insertions(+), 32 deletions(-) diff --git a/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs b/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs index a9b43a0d64..3ca70f96cc 100644 --- a/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs @@ -721,45 +721,32 @@ namespace Avalonia.Controls.UnitTests target.SelectedItem = item; Assert.True(called); } - + [Fact] public void SelectedItem_Should_Be_Valid_When_SelectedItemChanged_Event_Raised() { - using (Application()) - { - var tree = CreateTestTreeData(); - var target = new TreeView - { - Template = CreateTreeViewTemplate(), - ItemsSource = tree, - }; - - var visualRoot = new TestRoot(); - visualRoot.Child = target; + using var app = Start(); + var data = CreateTestTreeData(); + var target = CreateTarget(data: data); - CreateNodeDataTemplate(target); - ApplyTemplates(target); - ExpandAll(target); + var item = data[0].Children[1].Children[0]; + var container = Assert.IsType(target.TreeContainerFromItem(item)); - var item = tree[0].Children[1].Children[0]; - var container = (TreeViewItem)target.TreeContainerFromItem(item); + Assert.NotNull(container); - Assert.NotNull(container); - - var called = false; - target.SelectionChanged += (s, e) => - { - Assert.Same(item, e.AddedItems[0]); - Assert.Same(item, target.SelectedItem); - called = true; - }; + var called = false; + target.SelectionChanged += (s, e) => + { + Assert.Same(item, e.AddedItems[0]); + Assert.Same(item, target.SelectedItem); + called = true; + }; - _mouse.Click(container); + _mouse.Click(container); - Assert.Equal(item, target.SelectedItem); - Assert.True(container.IsSelected); - Assert.True(called); - } + Assert.Equal(item, target.SelectedItem); + Assert.True(container.IsSelected); + Assert.True(called); } [Fact] @@ -796,7 +783,7 @@ namespace Avalonia.Controls.UnitTests using var app = Start(); var data = CreateTestTreeData(); var target = CreateTarget(data: data, expandAll: false); - + target.SelectedItem = data[0].Children[1]; var rootItem = Assert.IsType(target.ContainerFromIndex(0)); From 8b881f01b9d2210638065214ae0fbe0055a831d1 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Wed, 29 Mar 2023 14:38:00 +0600 Subject: [PATCH 4/4] Writable composition properties --- .../CompositionGenerator/Generator.cs | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/tools/DevGenerators/CompositionGenerator/Generator.cs b/src/tools/DevGenerators/CompositionGenerator/Generator.cs index dfc8b45579..ced2cb369c 100644 --- a/src/tools/DevGenerators/CompositionGenerator/Generator.cs +++ b/src/tools/DevGenerators/CompositionGenerator/Generator.cs @@ -170,21 +170,26 @@ namespace Avalonia.SourceGenerator.CompositionGenerator if (manual.ServerName != null) serverPropertyType = manual.ServerName + (isNullable ? "?" : ""); } - if (animatedServer) server = server.AddMembers( DeclareField(serverPropertyType, fieldName), PropertyDeclaration(ParseTypeName(serverPropertyType), prop.Name) .AddModifiers(SyntaxKind.PublicKeyword) - .WithExpressionBody(ArrowExpressionClause( - InvocationExpression(IdentifierName("GetAnimatedValue"), - ArgumentList(SeparatedList(new[]{ - Argument(IdentifierName(CompositionPropertyField(prop))), - Argument(null, Token(SyntaxKind.RefKeyword), IdentifierName(fieldName)) - } - ))))) - .WithSemicolonToken(Semicolon()) - ); + .AddAccessorListAccessors( + AccessorDeclaration(SyntaxKind.GetAccessorDeclaration).WithExpressionBody( + ArrowExpressionClause( + InvocationExpression(IdentifierName("GetAnimatedValue"), + ArgumentList(SeparatedList(new[] + { + Argument(IdentifierName(CompositionPropertyField(prop))), + Argument(null, Token(SyntaxKind.RefKeyword), + IdentifierName(fieldName)) + } + ))))).WithSemicolonToken(Semicolon()), + AccessorDeclaration(SyntaxKind.SetAccessorDeclaration) + .WithExpressionBody(ArrowExpressionClause( + ParseExpression($"SetAnimatedValue({CompositionPropertyField(prop)}, out {PropertyBackingFieldName(prop)}, value)"))) + .WithSemicolonToken(Semicolon()))); else { server = server @@ -508,9 +513,7 @@ var changed = reader.Read<{ChangedFieldsTypeName(cl)}>(); code += $@" if((changed & {changedFieldsType}.{prop.Name}) == {changedFieldsType}.{prop.Name}) "; - if (prop.Animated) - code += $"SetAnimatedValue({CompositionPropertyField(prop)}, out {PropertyBackingFieldName(prop)}, {readValueCode});"; - else code += $"{prop.Name} = {readValueCode};"; + code += $"{prop.Name} = {readValueCode};"; return body.AddStatements(ParseStatement(code)); }