Skip to content

fix issue 11243 TreeNodeCollection.AddRange has been broken in .NET 8 and no longer results in TreeNodes being drawn at the correct location - #11253

Merged
Tanya-Solyanik merged 10 commits into
dotnet:mainfrom
Epica3055:Issue_11243_2
May 9, 2024
Merged

Conversation

@Epica3055

@Epica3055 Epica3055 commented Apr 23, 2024

Copy link
Copy Markdown
Member

Fixes #11243

Screenshots

Before

image

After

image

Test methodology

  • manually

Test environment(s)

9.0.0-preview.4.24219.3

… and no longer results in TreeNodes being drawn at the correct location
@Epica3055
Epica3055 requested a review from a team as a code owner April 23, 2024 10:17
@Epica3055
Epica3055 marked this pull request as draft April 23, 2024 10:18
@dotnet-policy-service dotnet-policy-service Bot added the draft draft PR label Apr 23, 2024
internal int _index; // our index into our parents child array
internal List<TreeNode> _childNodes = [];
internal int _childCount;
internal TreeNode[] _children;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

error CS8618: Non-nullable field '_children' must contain a non-null value when exiting constructor. Consider declaring the field as nullable

@Tanya-Solyanik

Copy link
Copy Markdown
Contributor

@Epica3055 , is this a straight revert of the #9078 PR? It would be good to understand what specific change introduced the regression. Once we know it, it will be easier to decide on the direction of the fix.

Comment thread src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeNode.cs Outdated
Comment thread src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeNode.cs Outdated
}

if (sorter.Compare(_childNodes[j] /*previous*/, _childNodes[min] /*current*/) <= 0)
if (sorter.Compare(_children[j] /*previous*/, _children[min] /*current*/) <= 0)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (sorter.Compare(_children[j] /*previous*/, _children[min] /*current*/) <= 0)
if (sorter.Compare(previous: _children[j], current: _children[min]) <= 0)

(if these are indeed the parameter names)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually they are not.

Comment thread src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeNode.cs Outdated
@Epica3055
Epica3055 marked this pull request as ready for review April 28, 2024 08:05
@Epica3055 Epica3055 removed the draft draft PR label Apr 28, 2024
@codecov

codecov Bot commented Apr 29, 2024

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 82.84024% with 29 lines in your changes are missing coverage. Please review.

Project coverage is 74.24623%. Comparing base (be78cbb) to head (f0ccdfa).
Report is 44 commits behind head on main.

Additional details and impacted files
@@                 Coverage Diff                 @@
##                main      #11253         +/-   ##
===================================================
- Coverage   74.32424%   74.24623%   -0.07802%     
===================================================
  Files           3011        3023         +12     
  Lines         625742      626382        +640     
  Branches       46547       46711        +164     
===================================================
- Hits          465078      465065         -13     
- Misses        157265      157917        +652     
- Partials        3399        3400          +1     
Flag Coverage Δ
Debug 74.24623% <82.84024%> (-0.07802%) ⬇️
integration 18.27645% <27.55906%> (-0.04969%) ⬇️
production 46.92204% <77.16535%> (-0.03560%) ⬇️
test 97.03764% <100.00000%> (-0.00375%) ⬇️
unit 43.87918% <77.16535%> (-0.02061%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

@Tanya-Solyanik

Copy link
Copy Markdown
Contributor

Please add a dedicated test for this scenario - call AddRange twice

@Tanya-Solyanik Tanya-Solyanik added the waiting-author-feedback The team requires more information from the author label Apr 29, 2024
@gpetrou

gpetrou commented May 1, 2024

Copy link
Copy Markdown
Contributor

Please check #11243 (comment). Also, even if there is still a problem, can't we still use a List instead of an array?

@Tanya-Solyanik

Copy link
Copy Markdown
Contributor

Please check #11243 (comment). Also, even if there is still a problem, can't we still use a List instead of an array?

Yes, this is a stable repro, when you call AddRange after the native tree view has been populated.

This code references a perf optimization for cases when we add large ranges to the treeview, and it seems that the workaround is to insert after the "fixed" node - the last node as previously populated treeview, as opposed to appending after the actual last node. To preserve this workaround as is, we would be inserting into the managed collection of child nodes at the "fixed index" as well, instead of appending, this seems complicated and an array is better suited for such use. To re-do this optimization, we need the specific scenario, Epica has experimented with large ranges and didn't see any difference with or without this perf optimization, I guess that scenario requires image lists, or other complications. But with no understanding of what this code is optimizing, it's risky to remove or modify it.

@Tanya-Solyanik Tanya-Solyanik left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added some minor comments, and please address the previous set of comments


form.Load += (s, e) =>
{
treeView.Nodes[0].Nodes.AddRange(treeNode1, treeNode2, treeNode3);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use rootNode local variable instead of the item accessor.

};
form.Show();

TreeNode childNode1 = treeView.Nodes[0].Nodes[0];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verify that treeView.Nodes[0] is still the rootNode and then use rootNode local variable instead of the collection item accessor


form.Load += (s, e) =>
{
treeView.Nodes[0].Nodes.AddRange(treeNode1, treeNode2, treeNode3);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add 4 nodes to force collection resize, as far as I remember initial size is 4, and we are adding exactly 4 nodes conting child

@Tanya-Solyanik Tanya-Solyanik added the waiting-author-feedback The team requires more information from the author label May 7, 2024
@dotnet-policy-service dotnet-policy-service Bot removed the waiting-author-feedback The team requires more information from the author label May 8, 2024

@Tanya-Solyanik Tanya-Solyanik left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

@Tanya-Solyanik Tanya-Solyanik added the ready-to-merge PRs that are ready to merge but worth notifying the internal team. label May 8, 2024
@Tanya-Solyanik
Tanya-Solyanik merged commit b76827c into dotnet:main May 9, 2024
@dotnet-policy-service dotnet-policy-service Bot added this to the 9.0 Preview5 milestone May 9, 2024
@dotnet-policy-service dotnet-policy-service Bot removed the ready-to-merge PRs that are ready to merge but worth notifying the internal team. label May 9, 2024
@Epica3055

Copy link
Copy Markdown
Member Author

/backport to release/8.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/8.0: https://github.com/dotnet/winforms/actions/runs/9040166498

@github-actions

Copy link
Copy Markdown
Contributor

@Epica3055 backporting to release/8.0 failed, the patch most likely resulted in conflicts:

$ git am --3way --ignore-whitespace --keep-non-patch changes.patch

Applying: fix issue 11243 TreeNodeCollection.AddRange has been broken in .NET 8 and no longer results in TreeNodes being drawn at the correct location
Using index info to reconstruct a base tree...
A	src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeNode.cs
A	src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeNodeCollection.cs
Falling back to patching base and 3-way merge...
Auto-merging src/System.Windows.Forms/src/System/Windows/Forms/TreeNodeCollection.cs
CONFLICT (content): Merge conflict in src/System.Windows.Forms/src/System/Windows/Forms/TreeNodeCollection.cs
Auto-merging src/System.Windows.Forms/src/System/Windows/Forms/TreeNode.cs
CONFLICT (content): Merge conflict in src/System.Windows.Forms/src/System/Windows/Forms/TreeNode.cs
error: Failed to merge in the changes.
hint: Use 'git am --show-current-patch=diff' to see the failed patch
Patch failed at 0001 fix issue 11243 TreeNodeCollection.AddRange has been broken in .NET 8 and no longer results in TreeNodes being drawn at the correct location
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".
Error: The process '/usr/bin/git' failed with exit code 128

Please backport manually!

@github-actions github-actions Bot locked and limited conversation to collaborators Jun 11, 2024
@Epica3055
Epica3055 deleted the Issue_11243_2 branch January 8, 2025 08:31
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TreeNodeCollection.AddRange has been broken in .NET 8 and no longer results in TreeNodes being drawn at the correct location

4 participants