dotnet / dotnet/wpf

Layout rounding can cause DataGrid to hang

Open
#9,944 4 comments 1 reaction 0 assignees View on GitHub
:construction: work in progress Investigate
Dominant language
C#
Stars
7.7k
Forks
1.3k
Avg merge
1d 11h
Merged PRs (30d)
61

Description

### Description

When `UseLayoutRounding=true`, the `DataGrid` can hang in an endless loop trying to get a cell into view after resetting the data then setting `DataGrid.CurrentCell`.

It appears to happen particularly when the column expands beyond the width of the DataGrid, and only on certain screen scales.

### Reproduction Steps

1. Set screen scale to 125% in System > Display Settings
2. Open and run this project: [TestWpfColumnFreeze.zip](https://github.com/user-attachments/files/17346648/TestWpfColumnFreeze.zip)
3. Double click on one of the cells that says "Double click on me"

### Expected behavior

Should not hang at any screen scale or layout rounding setting

### Actual behavior

The application hangs and does not respond to input.

The offending method appears to be in `DataGridCellsPanel.BringIndexIntoView`, where it gets stuck in [this loop](https://github.com/dotnet/wpf/blob/934a82731d7c35d639f221fa818a26ab4518425e/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/DataGridCellsPanel.cs#L2189-L2196):

```c#
while (!IsChildInView(index, out newHorizontalOffset) && !DoubleUtil.AreClose(value, newHorizontalOffset))
{
retryRequested = true;
scrollInfo.SetHorizontalOffset(newHorizontalOffset);
UpdateLayout();
value = newHorizontalOffset;
}
```

Stack Trace:
```
System.Private.CoreLib.dll!System.Threading.Monitor.Enter(object obj, ref bool lockTaken) Unknown
PresentationCore.dll!System.Windows.Media.Visual.GetDpi() Unknown
PresentationCore.dll!System.Windows.UIElement.Arrange(System.Windows.Rect finalRect) Unknown
PresentationFramework.dll!System.Windows.Controls.Primitives.DataGridColumnHeadersPresenter.ArrangeOverride(System.Windows.Size finalSize) Line 168 C#
PresentationFramework.dll!System.Windows.FrameworkElement.ArrangeCore(System.Windows.Rect finalRect) Line 3718 C#
PresentationCore.dll!System.Windows.UIElement.Arrange(System.Windows.Rect finalRect) Unknown
PresentationCore.dll!System.Windows.ContextLayoutManager.UpdateLayout() Unknown
> PresentationFramework.dll!System.Windows.Controls.DataGridCellsPanel.BringIndexIntoView(int index) Line 1580 C#
[Native to Managed Transition]
[Managed to Native Transition]
System.Private.CoreLib.dll!System.Reflection.MethodBaseInvoker.InvokeDirectByRefWithFewArgs(object obj, System.Span copyOfArgs, System.Reflection.BindingFlags invokeAttr) Unknown
System.Private.CoreLib.dll!System.Reflection.MethodBaseInvoker.InvokeWithOneArg(object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, object[] parameters, System.Globalization.CultureInfo culture) Unknown
System.Private.CoreLib.dll!System.Delegate.DynamicInvokeImpl(object[] args) Unknown
WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate callback, object args, int numArgs) Line 83 C#
WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.TryCatchWhen(object source, System.Delegate callback, object args, int numArgs, System.Delegate catchHandler) Line 24 C#
WindowsBase.dll!System.Windows.Threading.DispatcherOperation.InvokeImpl() Line 424 C#
WindowsBase.dll!MS.Internal.CulturePreservingExecutionContext.CallbackWrapper(object obj) Line 99 C#
System.Private.CoreLib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) Unknown
WindowsBase.dll!MS.Internal.CulturePreservingExecutionContext.Run(MS.Internal.CulturePreservingExecutionContext executionContext, System.Threading.ContextCallback callback, object state) Line 85 C#
WindowsBase.dll!System.Windows.Threading.DispatcherOperation.Invoke() Line 350 C#
WindowsBase.dll!System.Windows.Threading.Dispatcher.ProcessQueue() Line 1250 C#
WindowsBase.dll!System.Windows.Threading.Dispatcher.WndProcHook(nint hwnd, int msg, nint wParam, nint lParam, ref bool handled) Line 1367 C#
WindowsBase.dll!MS.Win32.HwndWrapper.WndProc(nint hwnd, int msg, nint wParam, nint lParam, ref bool handled) Line 192 C#
WindowsBase.dll!MS.Win32.HwndSubclass.DispatcherCallbackOperation(object o) Line 223 C#
WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate callback, object args, int numArgs) Line 73 C#
WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.TryCatchWhen(object source, System.Delegate callback, object args, int numArgs, System.Delegate catchHandler) Line 24 C#
WindowsBase.dll!System.Windows.Threading.Dispatcher.LegacyInvokeImpl(System.Windows.Threading.DispatcherPriority priority, System.TimeSpan timeout, System.Delegate method, object args, int numArgs) Line 990 C#
WindowsBase.dll!MS.Win32.HwndSubclass.SubclassWndProc(nint hwnd, int msg, nint wParam, nint lParam) Line 180 C#
[Native to Managed Transition]
[Managed to Native Transition]
WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame frame) Line 1281 C#
PresentationFramework.dll!System.Windows.Application.RunDispatcher(object ignore) C#
PresentationFramework.dll!System.Windows.Application.RunInternal(System.Windows.Window window) C#
TestWpfColumnFreeze.dll!TestWpfColumnFreeze.App.Main() Unknown
```

### Regression?

Also happens with latest .NET Framework, not sure about earlier versions.

### Known Workarounds

Turning off layout rounding for the DataGridRow appears to avoid the issue.

### Impact

_No response_

### Configuration

Running on Windows 11 23H2, .NET runtime 8.0.8 or 7.0.0

Reproducible on both x64 and ARM64 architectures.

### Other information

_No response_

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.