Skip to content

Commit 6bb2ba1

Browse files
authored
[release/8.0] Fix Clear and Remove after Sort in TreeView (#10398)
Cherry pick 172405c
1 parent 32ceec8 commit 6bb2ba1

2 files changed

Lines changed: 117 additions & 11 deletions

File tree

src/System.Windows.Forms/src/System/Windows/Forms/TreeNode.cs

Lines changed: 71 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ internal TreeNodeImageIndexer StateImageIndexer
9393
}
9494

9595
internal int index; // our index into our parents child array
96-
internal readonly List<TreeNode> childNodes = new();
96+
internal List<TreeNode> childNodes = new();
9797
internal TreeNode parent;
9898
internal TreeView treeView;
9999
private bool expandOnRealization;
@@ -1249,23 +1249,83 @@ public static TreeNode FromHandle(TreeView tree, IntPtr handle)
12491249

12501250
private void SortChildren(TreeView parentTreeView)
12511251
{
1252-
var nodeCount = childNodes.Count;
1253-
if (nodeCount > 0)
1252+
if (childNodes.Count <= 0)
12541253
{
1255-
List<TreeNode> newOrder = new(nodeCount);
1256-
if (parentTreeView?.TreeViewNodeSorter is null)
1257-
{
1258-
childNodes.Sort((x, y) => Application.CurrentCulture.CompareInfo.Compare(x.Text, y.Text, CompareOptions.None));
1259-
}
1260-
else
1254+
return;
1255+
}
1256+
1257+
List<TreeNode> newOrder = new(childNodes.Count);
1258+
if (parentTreeView is null || parentTreeView.TreeViewNodeSorter is null)
1259+
{
1260+
CompareInfo compare = Application.CurrentCulture.CompareInfo;
1261+
for (int i = 0; i < childNodes.Count; i++)
12611262
{
1262-
childNodes.Sort(parentTreeView.TreeViewNodeSorter.Compare);
1263+
newOrder.Add(childNodes[i]);
1264+
1265+
int min = -1;
1266+
for (int j = 0; j < childNodes.Count; j++)
1267+
{
1268+
if (childNodes[j] is null)
1269+
{
1270+
continue;
1271+
}
1272+
1273+
if (min == -1)
1274+
{
1275+
min = j;
1276+
continue;
1277+
}
1278+
1279+
if (compare.Compare(childNodes[j].Text, childNodes[min].Text) <= 0)
1280+
{
1281+
min = j;
1282+
}
1283+
}
1284+
1285+
Debug.Assert(min != -1, "Bad sorting");
1286+
newOrder[i] = childNodes[min];
1287+
childNodes[min] = null!;
1288+
newOrder[i].index = i;
1289+
newOrder[i].SortChildren(parentTreeView);
12631290
}
12641291

1292+
childNodes = newOrder;
1293+
}
1294+
else
1295+
{
1296+
IComparer sorter = parentTreeView.TreeViewNodeSorter;
12651297
for (int i = 0; i < childNodes.Count; i++)
12661298
{
1267-
childNodes[i].SortChildren(parentTreeView);
1299+
newOrder.Add(childNodes[i]);
1300+
1301+
int min = -1;
1302+
for (int j = 0; j < childNodes.Count; j++)
1303+
{
1304+
if (childNodes[j] is null)
1305+
{
1306+
continue;
1307+
}
1308+
1309+
if (min == -1)
1310+
{
1311+
min = j;
1312+
continue;
1313+
}
1314+
1315+
if (sorter.Compare(childNodes[j] /*previous*/, childNodes[min] /*current*/) <= 0)
1316+
{
1317+
min = j;
1318+
}
1319+
}
1320+
1321+
Debug.Assert(min != -1, "Bad sorting");
1322+
newOrder[i] = childNodes[min];
1323+
childNodes[min] = null!;
1324+
newOrder[i].index = i;
1325+
newOrder[i].SortChildren(parentTreeView);
12681326
}
1327+
1328+
childNodes = newOrder;
12691329
}
12701330
}
12711331

src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/TreeViewTests.cs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7114,6 +7114,52 @@ public void TreeView_TreeViewNodeSorter_ComparesTreeNodes()
71147114
treeView.TreeViewNodeSorter = treeSorter;
71157115
}
71167116

7117+
[WinFormsTheory]
7118+
[InlineData("A", "B")]
7119+
[InlineData("A", "A")]
7120+
[InlineData("B", "A")]
7121+
public void Clear_AfterSort_ShouldNotGetStuck(string firstNodeText, string secondNodeText)
7122+
{
7123+
using TreeView treeView = new();
7124+
TreeNode parent = new("Parent");
7125+
treeView.Nodes.Add(parent);
7126+
7127+
TreeNode firstNode = new(firstNodeText);
7128+
parent.Nodes.Add(firstNode);
7129+
TreeNode secondNode = new(secondNodeText);
7130+
parent.Nodes.Add(secondNode);
7131+
7132+
treeView.Sort();
7133+
7134+
Stopwatch timer = new();
7135+
timer.Start();
7136+
parent.Nodes.Clear();
7137+
timer.Stop();
7138+
Assert.True(timer.ElapsedMilliseconds <= 500);
7139+
}
7140+
7141+
[WinFormsTheory]
7142+
[InlineData("A", "B")]
7143+
[InlineData("A", "A")]
7144+
[InlineData("B", "A")]
7145+
public void Remove_AfterSort_ShouldNotThrowException(string firstNodeText, string secondNodeText)
7146+
{
7147+
using TreeView treeView = new();
7148+
TreeNode parent = new("Parent");
7149+
treeView.Nodes.Add(parent);
7150+
7151+
TreeNode firstNode = new(firstNodeText);
7152+
parent.Nodes.Add(firstNode);
7153+
TreeNode secondNode = new(secondNodeText);
7154+
parent.Nodes.Add(secondNode);
7155+
7156+
treeView.Sort();
7157+
7158+
parent.Nodes.Remove(firstNode);
7159+
7160+
parent.Nodes.Remove(secondNode);
7161+
}
7162+
71177163
private class SubTreeView : TreeView
71187164
{
71197165
public new bool CanEnableIme => base.CanEnableIme;

0 commit comments

Comments
 (0)