From 67a223dc53b9b2ed2f8c65ac611dbc80d4dc1a64 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Mon, 6 Oct 2025 08:57:18 -0700 Subject: [PATCH] Make ScreenBase impl more reliable (#19762) * Make ScreenBase impl more reliable * Don't copy list on netcore * Add Dispatcher.UIThread.VerifyAccess to be extra safe * Simplify code by only using List --- src/Avalonia.Controls/Platform/IScreenImpl.cs | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/Avalonia.Controls/Platform/IScreenImpl.cs b/src/Avalonia.Controls/Platform/IScreenImpl.cs index 5574c8170b..b072893f3a 100644 --- a/src/Avalonia.Controls/Platform/IScreenImpl.cs +++ b/src/Avalonia.Controls/Platform/IScreenImpl.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; +using System.Linq; using System.Threading.Tasks; using Avalonia.Metadata; using Avalonia.Threading; @@ -42,7 +43,7 @@ namespace Avalonia.Platform private readonly Dictionary _allScreensByKey = screenKeyComparer is not null ? new Dictionary(screenKeyComparer) : new Dictionary(); - private TScreen[]? _allScreens; + private IReadOnlyList? _allScreens; private int? _screenCount; private bool? _screenDetailsRequestGranted; private DispatcherOperation? _onChangeOperation; @@ -134,12 +135,18 @@ namespace Avalonia.Platform if (_allScreens is not null) return; + // We don't synchronize this method, as it is expected to be called on UI thread only. + Dispatcher.UIThread.VerifyAccess(); + var screens = GetAllScreenKeys(); var screensSet = new HashSet(screens, screenKeyComparer); - _allScreens = new TScreen[screens.Count]; - + // .ToList() is only necessary for .NET Framework apps. +#if NET foreach (var oldScreenKey in _allScreensByKey.Keys) +#else + foreach (var oldScreenKey in _allScreensByKey.Keys.ToList()) +#endif { if (!screensSet.Contains(oldScreenKey)) { @@ -151,24 +158,24 @@ namespace Avalonia.Platform } } - int i = 0; + var tempScreens = new List(screens.Count); foreach (var newScreenKey in screens) { if (_allScreensByKey.TryGetValue(newScreenKey, out var oldScreen)) { ScreenChanged(oldScreen); - _allScreens[i] = oldScreen; + tempScreens.Add(oldScreen); } else { var newScreen = CreateScreenFromKey(newScreenKey); ScreenAdded(newScreen); _allScreensByKey[newScreenKey] = newScreen; - _allScreens[i] = newScreen; + tempScreens.Add(newScreen); } - - i++; } + + _allScreens = tempScreens; } } }