Browse Source

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
pull/19753/head
Max Katz 4 months ago
committed by GitHub
parent
commit
67a223dc53
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 23
      src/Avalonia.Controls/Platform/IScreenImpl.cs

23
src/Avalonia.Controls/Platform/IScreenImpl.cs

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Avalonia.Metadata; using Avalonia.Metadata;
using Avalonia.Threading; using Avalonia.Threading;
@ -42,7 +43,7 @@ namespace Avalonia.Platform
private readonly Dictionary<TKey, TScreen> _allScreensByKey = screenKeyComparer is not null ? private readonly Dictionary<TKey, TScreen> _allScreensByKey = screenKeyComparer is not null ?
new Dictionary<TKey, TScreen>(screenKeyComparer) : new Dictionary<TKey, TScreen>(screenKeyComparer) :
new Dictionary<TKey, TScreen>(); new Dictionary<TKey, TScreen>();
private TScreen[]? _allScreens; private IReadOnlyList<TScreen>? _allScreens;
private int? _screenCount; private int? _screenCount;
private bool? _screenDetailsRequestGranted; private bool? _screenDetailsRequestGranted;
private DispatcherOperation? _onChangeOperation; private DispatcherOperation? _onChangeOperation;
@ -134,12 +135,18 @@ namespace Avalonia.Platform
if (_allScreens is not null) if (_allScreens is not null)
return; 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 screens = GetAllScreenKeys();
var screensSet = new HashSet<TKey>(screens, screenKeyComparer); var screensSet = new HashSet<TKey>(screens, screenKeyComparer);
_allScreens = new TScreen[screens.Count]; // .ToList() is only necessary for .NET Framework apps.
#if NET
foreach (var oldScreenKey in _allScreensByKey.Keys) foreach (var oldScreenKey in _allScreensByKey.Keys)
#else
foreach (var oldScreenKey in _allScreensByKey.Keys.ToList())
#endif
{ {
if (!screensSet.Contains(oldScreenKey)) if (!screensSet.Contains(oldScreenKey))
{ {
@ -151,24 +158,24 @@ namespace Avalonia.Platform
} }
} }
int i = 0; var tempScreens = new List<TScreen>(screens.Count);
foreach (var newScreenKey in screens) foreach (var newScreenKey in screens)
{ {
if (_allScreensByKey.TryGetValue(newScreenKey, out var oldScreen)) if (_allScreensByKey.TryGetValue(newScreenKey, out var oldScreen))
{ {
ScreenChanged(oldScreen); ScreenChanged(oldScreen);
_allScreens[i] = oldScreen; tempScreens.Add(oldScreen);
} }
else else
{ {
var newScreen = CreateScreenFromKey(newScreenKey); var newScreen = CreateScreenFromKey(newScreenKey);
ScreenAdded(newScreen); ScreenAdded(newScreen);
_allScreensByKey[newScreenKey] = newScreen; _allScreensByKey[newScreenKey] = newScreen;
_allScreens[i] = newScreen; tempScreens.Add(newScreen);
} }
i++;
} }
_allScreens = tempScreens;
} }
} }
} }

Loading…
Cancel
Save