microsoft / microsoft/microsoft-ui-xaml

ListView with non-virtualizing ItemsPanel mishandles multi-item CollectionChanged and later crashes

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

Description

### Describe the bug

When a collection raises a valid multi-item NotifyCollectionChangedAction.Add notification, a bound WinUI 3 ListView using a StackPanel as its ItemsPanel processes only one insertion.

The source collection contains four items, but the ListView displays only the first. A subsequent removal at index 1 throws E_INVALIDARG because the ListView and source collection have become desynchronized.

The notification includes multiple NewItems and a valid NewStartingIndex of 0. Using the ListView's default ItemsPanel works correctly.

### Why is this important?

The range addition silently leaves the UI inconsistent with its source collection. A later, otherwise valid collection removal can then terminate the application with an unhandled E_INVALIDARG.

Range-capable observable collections are commonly used to reduce notification and layout overhead. The initial problem can also be difficult to diagnose because the crash happens during a later collection operation.

### Steps to reproduce the bug

1. Build and run the attached minimal project: [WinUIRangeCollectionChanged.zip](https://github.com/user-attachments/files/30167488/WinUIRangeCollectionChanged.zip)
2. Click "1. Add four items".
3. Observe that the source count is 4, but the ListView displays only "one".
4. Click "2. Remove item at index 1".
5. The application crashes with E_INVALIDARG.

The collection raises this notification:
```
OnCollectionChanged(new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Add,
(IList)items,
index));
```

### Actual behavior

After the multi-item Add notification, the source collection contains four items but the ListView displays only the first item.

Removing the source item at index 1 then throws:

```
System.ArgumentException: The parameter is incorrect. (0x80070057)
at WinRT.ExceptionHelpers.g__Throw|41_0(Int32)
at ABI.System.Collections.Specialized.NotifyCollectionChangedEventHandler.NativeDelegateWrapper.Invoke(Object, NotifyCollectionChangedEventArgs)
at System.Collections.ObjectModel.ObservableCollection`1.OnCollectionChanged(NotifyCollectionChangedEventArgs)
at System.Collections.ObjectModel.ObservableCollection`1.RemoveItem(Int32)

```

### Expected behavior

The ListView should process every item contained in NewItems, display all four items, and remain synchronized with the source collection so that the later removal succeeds.

### Screenshots

_No response_

### NuGet package version

Microsoft.WindowsAppSDK.WinUI 2.3.0

### Windows version

Windows 11 (25H2): Build 26200

### Additional context

Reproduced with:

- Windows 11 25H2, build 26200.8894
- .NET 10.0.9
- Microsoft.WindowsAppSDK.WinUI 2.3.0
- Microsoft.WindowsAppSDK.Runtime 2.3.1
- Microsoft.WindowsAppSDK.Foundation 2.3.5
- Microsoft.WindowsAppSDK.InteractiveExperiences 2.1.3
- Microsoft.Windows.CsWinRT 2.3.0-prerelease.251115.2
- Unpackaged x64 application

The problem occurs when ListView uses a non-virtualizing StackPanel as its ItemsPanel. Using the default ItemsPanel works correctly.

Workarounds are to raise one Add notification per item or to raise NotifyCollectionChangedAction.Reset.

Related issues:
https://github.com/microsoft/microsoft-ui-xaml/issues/7993
https://github.com/dotnet/runtime/issues/18087

The Add handling appears to forward one ItemInserted notification without accounting for NewItems.Count:
https://github.com/microsoft/microsoft-ui-xaml/blob/main/dxaml/xcp/dxaml/lib/BindableObservableVectorWrapper.cpp#L198-L228

Contributor guide

Open the contributing guide

Research direction

Start with dxaml/xcp/dxaml/lib/BindableObservableVectorWrapper.cpp at lines 198-228 and reproduce the attached project using a StackPanel ItemsPanel and a multi-item Add notification. Trace how NewItems and NewStartingIndex are handled, then verify that all four items appear and the later removal at index 1 succeeds without E_INVALIDARG.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
desktop
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
58/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.