microsoft / microsoft/microsoft-ui-xaml

Bug Report: ItemsRepeater.TryGetElement() returns null for oldIndex after ObservableCollection.Move

Open
#11,570 0 comments 0 reactions 0 assignees View on GitHub
area-ItemsRepeater bug team-Controls
Dominant language
C++
Stars
8.4k
Forks
942
Avg merge
2d 7h
Merged PRs (30d)
105

Description

### Describe the bug

When an `ItemsRepeater` is bound to an `ObservableCollection` and an item within the `ObservableCollection` are moved with `ObservableCollection.Move(oldIndex, newIndex)`, then `ItemsRepeater.TryGetElement(int index)` returns `null` for `index = oldIndex`.

### Why is this important?

Resolving this bug is important because it affects both correctness and trust in the UI layer.
If `ItemsRepeater` returns the wrong element (or fails to return one) after a move operation, features that depend on item lookup can behave unpredictably—selection, focus, keyboard navigation, automation, and event routing may target the wrong item. That can produce user-visible glitches, intermittent failures, and hard-to-reproduce regressions.
Fixing it provides three concrete benefits:

- Reliability: item-to-UI mapping stays correct after collection changes.
- Stability: reduces downstream null/invalid-state errors in app code.
- Maintainability: prevents fragile workarounds and lowers long-term support cost.

In short, this bug is not only a functional defect; it creates risk across interaction, accessibility, and developer confidence.

### Steps to reproduce the bug

### Reproduction steps:
1. Build and run the project available [here](https://github.com/engltom/ItemsRepeater_Bug.git)
2. Initially, the App shows as follows:
Image
The two boxes displaying "Item 0" and "Item 1" are `ItemsRepeater`s that use two separate `ObservableCollection\`
3. Click "Swap items 0 and 1". This executes `ObservableCollection\.Move(0, 1);` for the `ItemsSource` of the upper `ItemsRepeater` and `ObservableCollection\.RemoveAt(0); ObservableCollection\.Insert(1, txt);` for the `ItemsSource of the lower `ItemsRepeater`.
4. After that for the upper `ItemsRepeater`, calling `ItemsRepeater.TryGetElement(0)` returns `null`, which results in the app displaying
Image
5. Clicking on "Force update" Causes the texts on the right hand side to be updated. During the update, `ItemsRepeater.TryGetElement(0)` is called to generate the text "Text at index 0: ...". In case `ItemsRepeater.TryGetElement(0)` does not return a `TextBlock`, the text ends with *\{null\}*. Otherwise it displays the text of the `TextBlock` returned by `ItemsRepeater.TryGetElement(0)`. The "Text at index1: ..." is likewise created by calling `ItemsRepeater.TryGetElement(1)`. The update does not result in a different result.

### Relevant Code Locations
ItemsRepeaterBug/MainWindow.xaml
MoveTestRepeater
RemoveAndAddTestRepeater
Buttons: Swap items 0 and 1, Force update
ItemsRepeaterBug/MainWindow.xaml.cs
SetMoveInfo() uses MoveTestRepeater.TryGetElement(0/1)
Swap_Click() calls TestStringMove.Move(0, 1)

### Actual behavior

`ItemsRepeater.TryGetElement()` does not return the correct UIElement after NotifyCollectionChanged with Move.

### Expected behavior

`ItemsRepeater.TryGetElement()` returns the correct UIElement after NotifyCollectionChanged with Move.

### Screenshots

Image
Image

### NuGet package version

Microsoft.WindowsAppSDK 2.4.0, Microsoft.Windows.SDK.BuildTools 10.0.29648.1000-preview

### Windows version

_No response_

### Additional context

App type: WinUI desktop app
Target framework: net10.0-windows10.0.22000.0 (.NET 10)
IDE: Visual Studio Professional 2026 (18.9.1)
Key packages:
Microsoft.WindowsAppSDK 2.4.0
Microsoft.Windows.SDK.BuildTools 10.0.29648.1000-preview

Contributor guide

Open the contributing guide

Research direction

Start by running the linked reproduction and inspect ItemsRepeaterBug/MainWindow.xaml and MainWindow.xaml.cs. Exercise the Swap items 0 and 1 and Force update buttons, comparing the Move path with the remove-and-insert path and the TryGetElement(0/1) results. Done means TryGetElement returns the correct UIElement after an ObservableCollection move.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, csharp
Domain
desktop, frontend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.