diff --git a/src/Avalonia.Visuals/Rendering/DirtyVisuals.cs b/src/Avalonia.Visuals/Rendering/DirtyVisuals.cs index f14f5bc912..00bc236b9c 100644 --- a/src/Avalonia.Visuals/Rendering/DirtyVisuals.cs +++ b/src/Avalonia.Visuals/Rendering/DirtyVisuals.cs @@ -17,6 +17,8 @@ namespace Avalonia.Rendering { private SortedDictionary> _inner = new SortedDictionary>(); private Dictionary _index = new Dictionary(); + private List _deferredChanges = new List(); + private int _deferring; /// /// Gets the number of dirty visuals. @@ -29,10 +31,15 @@ namespace Avalonia.Rendering /// The dirty visual. public void Add(IVisual visual) { + if (_deferring > 0) + { + _deferredChanges.Add(visual); + return; + } + var distance = visual.CalculateDistanceFromAncestor(visual.VisualRoot); - int existingDistance; - if (_index.TryGetValue(visual, out existingDistance)) + if (_index.TryGetValue(visual, out var existingDistance)) { if (distance == existingDistance) { @@ -43,9 +50,7 @@ namespace Avalonia.Rendering _index.Remove(visual); } - List list; - - if (!_inner.TryGetValue(distance, out list)) + if (!_inner.TryGetValue(distance, out var list)) { list = new List(); _inner.Add(distance, list); @@ -60,27 +65,13 @@ namespace Avalonia.Rendering /// public void Clear() { - _inner.Clear(); - _index.Clear(); - } - - /// - /// Removes a visual from the dirty list. - /// - /// The visual. - /// True if the visual was present in the list; otherwise false. - public bool Remove(IVisual visual) - { - int distance; - - if (_index.TryGetValue(visual, out distance)) + if (_deferring > 0) { - _inner[distance].Remove(visual); - _index.Remove(visual); - return true; + throw new InvalidOperationException("Cannot clear while enumerating"); } - return false; + _inner.Clear(); + _index.Clear(); } /// @@ -89,13 +80,38 @@ namespace Avalonia.Rendering /// A collection of visuals. public IEnumerator GetEnumerator() { - foreach (var i in _inner) + BeginDefer(); + try { - foreach (var j in i.Value) + foreach (var i in _inner) { - yield return j; + foreach (var j in i.Value) + { + yield return j; + } } } + finally + { + EndDefer(); + } + } + + private void BeginDefer() + { + ++_deferring; + } + + private void EndDefer() + { + if (--_deferring > 0) return; + + foreach (var visual in _deferredChanges) + { + Add(visual); + } + + _deferredChanges.Clear(); } ///