Add tests for ListBox selection synchronization (item→SelectedIndex and SelectedIndex→IsSelected)#163
Conversation
…ex and SelectedIndex→IsSelected paths Co-authored-by: tedd <493224+tedd@users.noreply.github.com>
77795f0
into
forge-listbox-parity-5850515012165907113
There was a problem hiding this comment.
Pull request overview
Adds unit test coverage around ListBox selection synchronization (between SelectedIndex on the ListBox and IsSelected / routed selection events on ListBoxItem containers), helping ensure correct selector behavior as the TUI control set evolves.
Changes:
- Add tests verifying
ListBoxItem.IsSelected = true(andSelectedEvent) updatesListBox.SelectedIndex. - Add tests verifying
ListBox.SelectedIndexchanges update/deselect the correspondingListBoxItem.IsSelectedstates, including clearing selection with-1.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // ItemsPanelRoot is populated after items are added (via OnItemsCollectionChanged → PopulatePanel) | ||
| Assert.NotNull(listBox.ItemsPanelRoot); | ||
| var container1 = listBox.ItemsPanelRoot!.Children[1] as ListBoxItem; |
There was a problem hiding this comment.
The comment implies ItemsPanelRoot is created/populated only after items are added. In the current implementation, ListBox applies its Template in the constructor (via Control.Template DP), and ItemsPresenter.OnTemplatedParentChanged() creates ItemsPanelRoot immediately; adding items just repopulates it. Updating this comment (or explicitly calling listBox.ApplyTemplate() in the test) would make the test intent clearer and less coupled to the current initialization order.
| Assert.NotNull(container2); | ||
|
|
||
| // Act: raise SelectedEvent directly on the third container | ||
| container2!.RaiseEvent(new RoutedEventArgs(ListBoxItem.SelectedEvent, container2)); |
There was a problem hiding this comment.
RaiseEvent always overwrites RoutedEventArgs.Source with this, so passing container2 into the RoutedEventArgs(routedEvent, source) constructor here is redundant and can be misleading. Consider using the single-argument RoutedEventArgs(ListBoxItem.SelectedEvent) constructor for clarity.
| container2!.RaiseEvent(new RoutedEventArgs(ListBoxItem.SelectedEvent, container2)); | |
| container2!.RaiseEvent(new RoutedEventArgs(ListBoxItem.SelectedEvent)); |
The
OnItemSelectedhandler (bubbledSelectedEvent→SelectedIndex) andOnSelectionChangedoverride (containerIsSelectedsync) had no test coverage.New tests in
ListBoxTestsItemIsSelected_ViaIsSelectedProperty_UpdatesListBoxSelectedIndex— setscontainer.IsSelected = true, asserts theSelectedEventbubbles toListBoxand updatesSelectedIndexItemSelectedEvent_RaisedOnContainer_UpdatesListBoxSelectedIndex— raisesSelectedEventdirectly on a container, assertsOnItemSelectedresolves the correct panel indexSelectedIndex_Change_Updates_ContainersIsSelected— setsSelectedIndex, asserts exactly that container hasIsSelected = true, all othersfalseSelectedIndex_Change_Deselects_PreviousContainer— moves selection between indices, asserts old container deselects and new one selectsSelectedIndex_MinusOne_Deselects_AllContainers— clears selection, asserts all containers deselected🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.