Skip to content

Demo: reproduce TreeView AddRange sort-order reversal (and verify AppContext switch)#27

Draft
Rick-Xu-WTG wants to merge 1 commit into
masterfrom
RX/WI01088201-Treeview-node-order-is-reversed-after-reopen
Draft

Demo: reproduce TreeView AddRange sort-order reversal (and verify AppContext switch)#27
Rick-Xu-WTG wants to merge 1 commit into
masterfrom
RX/WI01088201-Treeview-node-order-is-reversed-after-reopen

Conversation

@Rick-Xu-WTG

@Rick-Xu-WTG Rick-Xu-WTG commented Jun 17, 2026

Copy link
Copy Markdown

⚡ Quick start (run the demo)

  • From the repo root (e.g. C:\git\GitHub\WiseTechGlobal\winforms) - build the demo app
    ..dotnet\dotnet.exe build src\test\integration\WinformsControlsTest\WinformsControlsTest.csproj -c Debug

  • GUI: run the built app, then click "TreeView AddRange Order"
    e.g. C:\git\GitHub\WiseTechGlobal\winforms\artifacts\bin\WinformsControlsTest\Debug\net10.0\WinFormsControlsTest.exe

WinFormsControlsTest.exe is a Windows-subsystem app. If & $exe ... shows no output in your shell, capture it via a redirected System.Diagnostics.Process (the in-app "Compare switch ON / OFF" button does exactly this). Expected headless line: ... result=[Pallet 5, Pallet 4, ...] reversed=True.


What

Adds a minimal, self-contained repro to the WinForms demo app (WinformsControlsTest) that demonstrates a TreeView sort-order regression: TreeNodeCollection.AddRange reverses the order of equal-comparing nodes when TreeView.Sorted == true.

This proves the issue is a framework/WinForms behavior, not application logic. Demo only — no product code is changed.

Scenario

  • TreeView.Sorted = true with a custom TreeViewNodeSorter whose Compare always returns 0 (i.e. several identically described items, e.g. empty pallets).
  • Nodes added in one shot via TreeNodeCollection.AddRange in input order Pallet 1 .. Pallet 5.
  • Expected: Pallet 1, Pallet 2, Pallet 3, Pallet 4, Pallet 5 (stable).
  • Observed (.NET 9+): Pallet 5, Pallet 4, Pallet 3, Pallet 2, Pallet 1 (reversed).

How to reproduce

GUI: run WinformsControlsTest → click "TreeView AddRange Order". The form shows the input order, the result order, and whether it reversed. Add()-in-a-loop is provided as a stable contrast.

Headless / scriptable:

WinFormsControlsTest.exe --treeview-addrange-report
WinFormsControlsTest.exe --treeview-addrange-report --switch:true
WinFormsControlsTest.exe --treeview-addrange-report --switch:false

The "Compare switch ON / OFF (child processes)" button runs all three in separate child processes and shows the captured output.

Does the AppContext switch fix it?

The System.Windows.Forms.TreeNodeCollectionAddRangeRespectsSortOrder switch (dotnet#11423) was suggested as a way to restore the old behavior. Empirically, in this exact build:

Config Input Result Reversed?
baseline (default true) Pallet 1..5 Pallet 5..1 Yes
--switch:true Pallet 1..5 Pallet 5..1 Yes
--switch:false Pallet 1..5 Pallet 5..1 Yes

The switch does not restore the order for the empty-parent + equal-nodes case: it only gates whether FixedIndex is set, while AddRange always iterates the input array backwards. The reversal therefore needs an implementation-level fix (forward iteration on the sorted path), not just a runtime switch.

Notes

  • One enum value (TreeViewAddRangeOrderButton) is appended to MainFormControlsTabOrder to register the demo button.

…r reversal

Adds a minimal, self-contained repro to the WinForms demo app (WinformsControlsTest)
showing that TreeNodeCollection.AddRange reverses the order of equal-comparing nodes
when TreeView.Sorted is true. This is a framework-level behavior change vs .NET 8 /
.NET Framework, independent of any application logic.

The demo can also run headlessly and flip the
System.Windows.Forms.TreeNodeCollectionAddRangeRespectsSortOrder AppContext switch
(PR dotnet#11423), so the switch's effect can be verified empirically.

Demo only - no product code is changed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
return true;
}

// A sorter that treats every node as equal, like several identically described items.

@Rick-Xu-WTG Rick-Xu-WTG Jun 17, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

The three key elements that trigger defects ----- 1:
Corresponding to CargoWise's PkgPackageComparer, it returns 0 for an empty Pallet.
https://github.com/WiseTechGlobal/CargoWise/blob/71b809691cfb365b052e73648708f4ee6abf85d0/Enterprise/Product/Operations/Packing/Packing.Business/PkgPackage/PkgPackageComparer.cs

This is why the problem only arises when we add Pallets with same name.

return $"[{arguments}] error: {ex.Message}";
}
}

@Rick-Xu-WTG Rick-Xu-WTG Jun 17, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Create nodes with sequential numbers.

AppContext.SetSwitch(SwitchName, switchValue);
}

TreeNode[] nodes = CreatePalletNodes(PalletCount);

@Rick-Xu-WTG Rick-Xu-WTG Jun 17, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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


TreeNode[] nodes = CreatePalletNodes(PalletCount);
using TreeView treeView = new() { Sorted = true, TreeViewNodeSorter = new AlwaysEqualComparer() };
treeView.CreateControl();

@Rick-Xu-WTG Rick-Xu-WTG Jun 17, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

The three key elements that trigger defects ----- 3:
AddRange would add nodes with increasing sequence, and trigger net10 reverse traversal
for (int i = nodes.Length - 1; i >= 0; i--) { AddInternal(nodes[i], delta: i); }

string switchArg = args.FirstOrDefault(a => a.StartsWith("--switch:", StringComparison.OrdinalIgnoreCase));
if (switchArg is not null && bool.TryParse(switchArg["--switch:".Length..], out bool switchValue))
{
// Must be set before the first time the switch is read (first sorted AddRange).

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

We can set switch maunally in demo button:

Image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant