Skip to content

Layout rounding can cause DataGrid to hang #9944

Open
@cwensley

Description

@cwensley

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
  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:

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<object> 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions