diff --git a/src/Avalonia.Visuals/Rendering/RenderLoop.cs b/src/Avalonia.Visuals/Rendering/RenderLoop.cs index d0d5b2250d..df32d9eec1 100644 --- a/src/Avalonia.Visuals/Rendering/RenderLoop.cs +++ b/src/Avalonia.Visuals/Rendering/RenderLoop.cs @@ -19,7 +19,8 @@ namespace Avalonia.Rendering private readonly IDispatcher _dispatcher; private List _items = new List(); private IRenderTimer _timer; - private int inTick; + private int _inTick; + private int _inUpdate; /// /// Initializes a new instance of the class. @@ -84,21 +85,36 @@ namespace Avalonia.Rendering } } - private async void TimerTick(TimeSpan time) + private void TimerTick(TimeSpan time) { - if (Interlocked.CompareExchange(ref inTick, 1, 0) == 0) + if (Interlocked.CompareExchange(ref _inTick, 1, 0) == 0) { try { - if (_items.Any(item => item.NeedsUpdate)) + if (_items.Any(item => item.NeedsUpdate) && + Interlocked.CompareExchange(ref _inUpdate, 1, 0) == 0) { - await _dispatcher.InvokeAsync(() => + _dispatcher.Post(() => { - foreach (var i in _items) + for (var i = 0; i < _items.Count; ++i) { - i.Update(time); + var item = _items[i]; + + if (item.NeedsUpdate) + { + try + { + item.Update(time); + } + catch (Exception ex) + { + Logger.Error(LogArea.Visual, this, "Exception in render update: {Error}", ex); + } + } } - }, DispatcherPriority.Render).ConfigureAwait(false); + + Interlocked.Exchange(ref _inUpdate, 0); + }, DispatcherPriority.Render); } foreach (var i in _items) @@ -112,7 +128,7 @@ namespace Avalonia.Rendering } finally { - Interlocked.Exchange(ref inTick, 0); + Interlocked.Exchange(ref _inTick, 0); } } } diff --git a/tests/Avalonia.Visuals.UnitTests/Rendering/RenderLoopTests.cs b/tests/Avalonia.Visuals.UnitTests/Rendering/RenderLoopTests.cs index 16c2d3ee18..e9aefc46e6 100644 --- a/tests/Avalonia.Visuals.UnitTests/Rendering/RenderLoopTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/Rendering/RenderLoopTests.cs @@ -19,14 +19,13 @@ namespace Avalonia.Visuals.UnitTests.Rendering bool inDispatcher = false; dispatcher.Setup( - d => d.InvokeAsync(It.IsAny(), DispatcherPriority.Render)) + d => d.Post(It.IsAny(), DispatcherPriority.Render)) .Callback((Action a, DispatcherPriority _) => { inDispatcher = true; a(); inDispatcher = false; - }) - .Returns(Task.CompletedTask); + }); var timer = new Mock(); @@ -71,14 +70,13 @@ namespace Avalonia.Visuals.UnitTests.Rendering var dispatcher = new Mock(); bool inDispatcher = false; dispatcher.Setup( - d => d.InvokeAsync(It.IsAny(), DispatcherPriority.Render)) + d => d.Post(It.IsAny(), DispatcherPriority.Render)) .Callback((Action a, DispatcherPriority _) => { inDispatcher = true; a(); inDispatcher = false; - }) - .Returns(Task.CompletedTask); + }); var timer = new Mock(); var loop = new RenderLoop(timer.Object, dispatcher.Object); @@ -100,9 +98,8 @@ namespace Avalonia.Visuals.UnitTests.Rendering { var dispatcher = new Mock(); dispatcher.Setup( - d => d.InvokeAsync(It.IsAny(), DispatcherPriority.Render)) - .Callback((Action a, DispatcherPriority _) => a()) - .Returns(Task.CompletedTask); + d => d.Post(It.IsAny(), DispatcherPriority.Render)) + .Callback((Action a, DispatcherPriority _) => a()); var timer = new Mock(); var loop = new RenderLoop(timer.Object, dispatcher.Object);