Browse Source
Fix System.InvalidOperationException Dispatcher job loop detected (#20310)
pull/20322/head
Wiesław Šoltés
2 months ago
committed by
GitHub
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with
43 additions and
7 deletions
-
src/Headless/Avalonia.Headless/HeadlessWindowExtensions.cs
-
tests/Avalonia.Headless.UnitTests/InputTests.cs
|
|
|
@ -142,20 +142,25 @@ public static class HeadlessWindowExtensions |
|
|
|
action(GetImpl(topLevel)); |
|
|
|
RunJobsAndRender(); |
|
|
|
|
|
|
|
void RunJobsAndRender() |
|
|
|
static void RunJobsAndRender() |
|
|
|
{ |
|
|
|
var count = 0; |
|
|
|
var dispatcher = Dispatcher.UIThread; |
|
|
|
|
|
|
|
while (dispatcher.HasJobsWithPriority(DispatcherPriority.MinimumActiveValue)) |
|
|
|
// Run jobs and render frames until everything is stable.
|
|
|
|
// We use a simple approach: run jobs, render, and repeat until
|
|
|
|
// there are no more pending jobs. The render timer tick can schedule
|
|
|
|
// new jobs, so we loop until stable.
|
|
|
|
for (var i = 0; i < 10; i++) |
|
|
|
{ |
|
|
|
if (count >= 10) |
|
|
|
throw new InvalidOperationException("Dispatcher job loop detected"); |
|
|
|
|
|
|
|
dispatcher.RunJobs(); |
|
|
|
AvaloniaHeadlessPlatform.ForceRenderTimerTick(); |
|
|
|
++count; |
|
|
|
|
|
|
|
if (!dispatcher.HasJobsWithPriority(DispatcherPriority.MinimumActiveValue)) |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// Final attempt: run remaining jobs without rendering
|
|
|
|
dispatcher.RunJobs(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -72,6 +72,37 @@ public class InputTests |
|
|
|
Assert.True(_window.Position == newWindowPosition); |
|
|
|
} |
|
|
|
|
|
|
|
#if NUNIT
|
|
|
|
[AvaloniaTest, Timeout(10000)] |
|
|
|
#elif XUNIT
|
|
|
|
[AvaloniaFact] |
|
|
|
#endif
|
|
|
|
public void Should_Click_Button_After_Explicit_RunJobs() |
|
|
|
{ |
|
|
|
// Regression test for https://github.com/AvaloniaUI/Avalonia/issues/20309
|
|
|
|
// Ensure that calling Dispatcher.UIThread.RunJobs() before MouseDown does not throw
|
|
|
|
var button = new Button { Content = "Test content" }; |
|
|
|
_window.Content = button; |
|
|
|
_window.Show(); |
|
|
|
|
|
|
|
Dispatcher.UIThread.RunJobs(); |
|
|
|
|
|
|
|
var clickCount = 0; |
|
|
|
button.Click += (_, _) => clickCount++; |
|
|
|
|
|
|
|
var point = new Point(button.Bounds.Width / 2, button.Bounds.Height / 2); |
|
|
|
var translatePoint = button.TranslatePoint(point, _window); |
|
|
|
|
|
|
|
// Move
|
|
|
|
_window.MouseMove(translatePoint!.Value, RawInputModifiers.None); |
|
|
|
|
|
|
|
// Click
|
|
|
|
_window.MouseDown(translatePoint.Value, MouseButton.Left, RawInputModifiers.None); |
|
|
|
_window.MouseUp(translatePoint.Value, MouseButton.Left, RawInputModifiers.None); |
|
|
|
|
|
|
|
Assert.True(clickCount == 1); |
|
|
|
} |
|
|
|
|
|
|
|
#if NUNIT
|
|
|
|
[TearDown] |
|
|
|
public void TearDown() |
|
|
|
|