From b515f7a30e6901c54b4e4e1aa1fcbef9f917ca9e Mon Sep 17 00:00:00 2001 From: ahopper Date: Fri, 2 Nov 2018 17:09:08 +0000 Subject: [PATCH 01/10] allow for pointerover control being removed from visual tree --- src/Avalonia.Input/MouseDevice.cs | 54 +++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/src/Avalonia.Input/MouseDevice.cs b/src/Avalonia.Input/MouseDevice.cs index e581772978..893ffe491f 100644 --- a/src/Avalonia.Input/MouseDevice.cs +++ b/src/Avalonia.Input/MouseDevice.cs @@ -298,21 +298,48 @@ namespace Avalonia.Input Contract.Requires(device != null); Contract.Requires(root != null); - var element = root.PointerOverElement; + var element = root.PointerOverElement; var e = new PointerEventArgs { RoutedEvent = InputElement.PointerLeaveEvent, Device = device, }; - while (element != null) + if (element!=null && !element.IsAttachedToVisualTree) + { + // element has been removed from visual tree so do top down cleanup + if (root.IsPointerOver) + ClearChildrenPointerOver(e, root,true); + } + else + { + while (element != null) + { + e.Source = element; + e.Handled = false; + element.RaiseEvent(e); + element = (IInputElement)element.VisualParent; + } + } + root.PointerOverElement = null; + } + + private void ClearChildrenPointerOver(PointerEventArgs e, IInputElement element,bool clearRoot) + { + foreach (IInputElement el in element.VisualChildren) + { + if (el.IsPointerOver) + { + ClearChildrenPointerOver(e, el, true); + break; + } + } + if(clearRoot) { e.Source = element; + e.Handled = false; element.RaiseEvent(e); - element = (IInputElement)element.VisualParent; } - - root.PointerOverElement = null; } private IInputElement SetPointerOver(IPointerDevice device, IInputRoot root, Point p) @@ -361,12 +388,19 @@ namespace Avalonia.Input el = root.PointerOverElement; e.RoutedEvent = InputElement.PointerLeaveEvent; - while (el != null && el != branch) + if (el!=null && branch!=null && !el.IsAttachedToVisualTree) { - e.Source = el; - e.Handled = false; - el.RaiseEvent(e); - el = (IInputElement)el.VisualParent; + ClearChildrenPointerOver(e,branch,false); + } + else + { + while (el != null && el != branch) + { + e.Source = el; + e.Handled = false; + el.RaiseEvent(e); + el = (IInputElement)el.VisualParent; + } } el = root.PointerOverElement = element; From b15996a091f06094b49a0fb6c2d140957f8ac96e Mon Sep 17 00:00:00 2001 From: ahopper Date: Wed, 7 Nov 2018 08:00:09 +0000 Subject: [PATCH 02/10] fix hittest exception during scene changes --- src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs index ffa0b0bcc5..ad4c475d89 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs @@ -160,7 +160,7 @@ namespace Avalonia.Rendering.SceneGraph private IEnumerable HitTest(IVisualNode node, Point p, Rect? clip, Func filter) { - if (filter?.Invoke(node.Visual) != false) + if (filter?.Invoke(node.Visual) != false && node.Visual.IsAttachedToVisualTree) { var clipped = false; @@ -186,7 +186,7 @@ namespace Avalonia.Rendering.SceneGraph } } - if (node.HitTest(p) && node.Visual.IsAttachedToVisualTree) + if (node.HitTest(p)) { yield return node.Visual; } From e11af71e9f8c88bf6f4effdd59c36196737df8f6 Mon Sep 17 00:00:00 2001 From: ahopper Date: Mon, 12 Nov 2018 10:57:16 +0000 Subject: [PATCH 03/10] allow for content changes with no mouse movement --- src/Avalonia.Controls/TopLevel.cs | 8 ++++- src/Avalonia.Input/IPointerDevice.cs | 2 ++ src/Avalonia.Input/MouseDevice.cs | 44 ++++++++++++++++------------ 3 files changed, 35 insertions(+), 19 deletions(-) diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs index 5443baf225..082fc8858d 100644 --- a/src/Avalonia.Controls/TopLevel.cs +++ b/src/Avalonia.Controls/TopLevel.cs @@ -230,8 +230,9 @@ namespace Avalonia.Controls void IRenderRoot.Invalidate(Rect rect) { PlatformImpl?.Invalidate(rect); + UpdatePointerOver(); } - + /// Point IRenderRoot.PointToClient(Point p) { @@ -349,5 +350,10 @@ namespace Avalonia.Controls { _inputManager.ProcessInput(e); } + + private void UpdatePointerOver() + { + (this as IInputRoot).MouseDevice.LayoutUpdated(this); + } } } diff --git a/src/Avalonia.Input/IPointerDevice.cs b/src/Avalonia.Input/IPointerDevice.cs index 8613717f60..d7e7077429 100644 --- a/src/Avalonia.Input/IPointerDevice.cs +++ b/src/Avalonia.Input/IPointerDevice.cs @@ -12,5 +12,7 @@ namespace Avalonia.Input void Capture(IInputElement control); Point GetPosition(IVisual relativeTo); + + void LayoutUpdated(IInputRoot root); } } diff --git a/src/Avalonia.Input/MouseDevice.cs b/src/Avalonia.Input/MouseDevice.cs index 893ffe491f..916827775a 100644 --- a/src/Avalonia.Input/MouseDevice.cs +++ b/src/Avalonia.Input/MouseDevice.cs @@ -104,6 +104,18 @@ namespace Avalonia.Input ProcessRawEvent(margs); } + public void LayoutUpdated(IInputRoot root) + { + if (Captured == null) + { + SetPointerOver(this, root, root.PointToClient(Position)); + } + else + { + SetPointerOver(this, root, Captured); + } + } + private void ProcessRawEvent(RawMouseEventArgs e) { Contract.Requires(e != null); @@ -298,7 +310,7 @@ namespace Avalonia.Input Contract.Requires(device != null); Contract.Requires(root != null); - var element = root.PointerOverElement; + var element = root.PointerOverElement; var e = new PointerEventArgs { RoutedEvent = InputElement.PointerLeaveEvent, @@ -311,16 +323,14 @@ namespace Avalonia.Input if (root.IsPointerOver) ClearChildrenPointerOver(e, root,true); } - else + while (element != null) { - while (element != null) - { - e.Source = element; - e.Handled = false; - element.RaiseEvent(e); - element = (IInputElement)element.VisualParent; - } + e.Source = element; + e.Handled = false; + element.RaiseEvent(e); + element = (IInputElement)element.VisualParent; } + root.PointerOverElement = null; } @@ -392,16 +402,14 @@ namespace Avalonia.Input { ClearChildrenPointerOver(e,branch,false); } - else + + while (el != null && el != branch) { - while (el != null && el != branch) - { - e.Source = el; - e.Handled = false; - el.RaiseEvent(e); - el = (IInputElement)el.VisualParent; - } - } + e.Source = el; + e.Handled = false; + el.RaiseEvent(e); + el = (IInputElement)el.VisualParent; + } el = root.PointerOverElement = element; e.RoutedEvent = InputElement.PointerEnterEvent; From 7c5802efcfbbbf27a6f1a437b27ee2f3f1a9a85b Mon Sep 17 00:00:00 2001 From: ahopper Date: Tue, 20 Nov 2018 22:12:55 +0000 Subject: [PATCH 04/10] change name and check invalidate rect --- src/Avalonia.Controls/TopLevel.cs | 6 +++--- src/Avalonia.Input/IPointerDevice.cs | 2 +- src/Avalonia.Input/MouseDevice.cs | 19 ++++++++++++------- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs index 082fc8858d..10419131eb 100644 --- a/src/Avalonia.Controls/TopLevel.cs +++ b/src/Avalonia.Controls/TopLevel.cs @@ -230,7 +230,7 @@ namespace Avalonia.Controls void IRenderRoot.Invalidate(Rect rect) { PlatformImpl?.Invalidate(rect); - UpdatePointerOver(); + UpdatePointerOver(rect); } /// @@ -351,9 +351,9 @@ namespace Avalonia.Controls _inputManager.ProcessInput(e); } - private void UpdatePointerOver() + private void UpdatePointerOver(Rect rect) { - (this as IInputRoot).MouseDevice.LayoutUpdated(this); + (this as IInputRoot).MouseDevice.SceneInvalidated(this, rect); } } } diff --git a/src/Avalonia.Input/IPointerDevice.cs b/src/Avalonia.Input/IPointerDevice.cs index d7e7077429..932cbc989f 100644 --- a/src/Avalonia.Input/IPointerDevice.cs +++ b/src/Avalonia.Input/IPointerDevice.cs @@ -13,6 +13,6 @@ namespace Avalonia.Input Point GetPosition(IVisual relativeTo); - void LayoutUpdated(IInputRoot root); + void SceneInvalidated(IInputRoot root, Rect rect); } } diff --git a/src/Avalonia.Input/MouseDevice.cs b/src/Avalonia.Input/MouseDevice.cs index 916827775a..a4f0020ea3 100644 --- a/src/Avalonia.Input/MouseDevice.cs +++ b/src/Avalonia.Input/MouseDevice.cs @@ -104,16 +104,21 @@ namespace Avalonia.Input ProcessRawEvent(margs); } - public void LayoutUpdated(IInputRoot root) + public void SceneInvalidated(IInputRoot root, Rect rect) { - if (Captured == null) + var clientPoint = root.PointToClient(Position); + + if (rect.Contains(clientPoint)) { - SetPointerOver(this, root, root.PointToClient(Position)); + if (Captured == null) + { + SetPointerOver(this, root, clientPoint); + } + else + { + SetPointerOver(this, root, Captured); + } } - else - { - SetPointerOver(this, root, Captured); - } } private void ProcessRawEvent(RawMouseEventArgs e) From 38a3db18cb34a8ec6585b7d137035bc23510001f Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 17 Jan 2019 14:42:12 +0100 Subject: [PATCH 05/10] Added IRenderer.SceneInvalidated event. And use this event to trigger an update of the mouse pointer-over state. --- src/Avalonia.Controls/TopLevel.cs | 6 ++-- .../Rendering/DeferredRenderer.cs | 18 ++++++++++ src/Avalonia.Visuals/Rendering/IRenderer.cs | 13 +++++-- .../Rendering/ImmediateRenderer.cs | 5 +++ .../Rendering/SceneInvalidatedEventArgs.cs | 36 +++++++++++++++++++ tests/Avalonia.LeakTests/ControlTests.cs | 1 + 6 files changed, 74 insertions(+), 5 deletions(-) create mode 100644 src/Avalonia.Visuals/Rendering/SceneInvalidatedEventArgs.cs diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs index 10419131eb..294b15a564 100644 --- a/src/Avalonia.Controls/TopLevel.cs +++ b/src/Avalonia.Controls/TopLevel.cs @@ -97,6 +97,7 @@ namespace Avalonia.Controls _renderInterface = TryGetService(dependencyResolver); Renderer = impl.CreateRenderer(this); + Renderer.SceneInvalidated += SceneInvalidated; impl.SetInputRoot(this); @@ -230,7 +231,6 @@ namespace Avalonia.Controls void IRenderRoot.Invalidate(Rect rect) { PlatformImpl?.Invalidate(rect); - UpdatePointerOver(rect); } /// @@ -351,9 +351,9 @@ namespace Avalonia.Controls _inputManager.ProcessInput(e); } - private void UpdatePointerOver(Rect rect) + private void SceneInvalidated(object sender, SceneInvalidatedEventArgs e) { - (this as IInputRoot).MouseDevice.SceneInvalidated(this, rect); + (this as IInputRoot).MouseDevice.SceneInvalidated(this, e.DirtyRect); } } } diff --git a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs index b48efaa34e..0808957482 100644 --- a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs +++ b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs @@ -99,6 +99,9 @@ namespace Avalonia.Rendering /// public string DebugFramesPath { get; set; } + /// + public event EventHandler SceneInvalidated; + /// /// Gets the render layers. /// @@ -470,6 +473,21 @@ namespace Avalonia.Rendering oldScene?.Dispose(); } + if (SceneInvalidated != null) + { + var rect = new Rect(); + + foreach (var layer in scene.Layers) + { + foreach (var dirty in layer.Dirty) + { + rect = rect.Union(dirty); + } + } + + SceneInvalidated(this, new SceneInvalidatedEventArgs((IRenderRoot)_root, rect)); + } + _dirty.Clear(); } else diff --git a/src/Avalonia.Visuals/Rendering/IRenderer.cs b/src/Avalonia.Visuals/Rendering/IRenderer.cs index 9085e63aa9..36a1f7d220 100644 --- a/src/Avalonia.Visuals/Rendering/IRenderer.cs +++ b/src/Avalonia.Visuals/Rendering/IRenderer.cs @@ -18,11 +18,20 @@ namespace Avalonia.Rendering bool DrawFps { get; set; } /// - /// Gets or sets a value indicating whether the renderer should a visual representation + /// Gets or sets a value indicating whether the renderer should draw a visual representation /// of its dirty rectangles. /// bool DrawDirtyRects { get; set; } + /// + /// Raised when a portion of the scene has been invalidated. + /// + /// + /// Indicates that the underlying low-level scene information has been updated. Used to + /// signal that an update to the current pointer-over state may be required. + /// + event EventHandler SceneInvalidated; + /// /// Mark a visual as dirty and needing re-rendering. /// @@ -63,4 +72,4 @@ namespace Avalonia.Rendering /// void Stop(); } -} \ No newline at end of file +} diff --git a/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs b/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs index 03ac004fd5..21129e38af 100644 --- a/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs +++ b/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs @@ -42,6 +42,9 @@ namespace Avalonia.Rendering /// public bool DrawDirtyRects { get; set; } + /// + public event EventHandler SceneInvalidated; + /// public void Paint(Rect rect) { @@ -81,6 +84,8 @@ namespace Avalonia.Rendering _renderTarget.Dispose(); _renderTarget = null; } + + SceneInvalidated?.Invoke(this, new SceneInvalidatedEventArgs((IRenderRoot)_root, rect)); } /// diff --git a/src/Avalonia.Visuals/Rendering/SceneInvalidatedEventArgs.cs b/src/Avalonia.Visuals/Rendering/SceneInvalidatedEventArgs.cs new file mode 100644 index 0000000000..40cb9f3356 --- /dev/null +++ b/src/Avalonia.Visuals/Rendering/SceneInvalidatedEventArgs.cs @@ -0,0 +1,36 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; + +namespace Avalonia.Rendering +{ + /// + /// Provides data for the event. + /// + public class SceneInvalidatedEventArgs : EventArgs + { + /// + /// Initializes a new instance of the class. + /// + /// The render root that has been updated. + /// The updated area. + public SceneInvalidatedEventArgs( + IRenderRoot root, + Rect dirtyRect) + { + RenderRoot = root; + DirtyRect = dirtyRect; + } + + /// + /// Gets the invalidated area. + /// + public Rect DirtyRect { get; } + + /// + /// Gets the render root that has been invalidated. + /// + public IRenderRoot RenderRoot { get; } + } +} diff --git a/tests/Avalonia.LeakTests/ControlTests.cs b/tests/Avalonia.LeakTests/ControlTests.cs index 4dcd98cb93..b7aa452a18 100644 --- a/tests/Avalonia.LeakTests/ControlTests.cs +++ b/tests/Avalonia.LeakTests/ControlTests.cs @@ -348,6 +348,7 @@ namespace Avalonia.LeakTests { public bool DrawFps { get; set; } public bool DrawDirtyRects { get; set; } + public event EventHandler SceneInvalidated; public void AddDirty(IVisual visual) { From 65234e8e43cdbff29791caecf224cbb4b05062be Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 17 Jan 2019 21:48:08 +0100 Subject: [PATCH 06/10] Allow for null renderer. This can happen in unit tests. --- src/Avalonia.Controls/TopLevel.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs index 294b15a564..1201941a86 100644 --- a/src/Avalonia.Controls/TopLevel.cs +++ b/src/Avalonia.Controls/TopLevel.cs @@ -97,7 +97,11 @@ namespace Avalonia.Controls _renderInterface = TryGetService(dependencyResolver); Renderer = impl.CreateRenderer(this); - Renderer.SceneInvalidated += SceneInvalidated; + + if (Renderer != null) + { + Renderer.SceneInvalidated += SceneInvalidated; + } impl.SetInputRoot(this); From 86ed01d08c62b6d2986da06913f13353972f0fb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Fri, 18 Jan 2019 19:25:58 +0100 Subject: [PATCH 07/10] Added NuGet and MyGet badges --- readme.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/readme.md b/readme.md index 9280125323..897f6db0c0 100644 --- a/readme.md +++ b/readme.md @@ -1,10 +1,10 @@ - + # Avalonia -| Gitter Chat | Build Status (Win, Linux, OSX) | Open Collective | +| Gitter Chat | Build Status (Win, Linux, OSX) | Open Collective | NuGet | MyGet | |---|---|---| -| [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/AvaloniaUI/Avalonia?utm_campaign=pr-badge&utm_content=badge&utm_medium=badge&utm_source=badge) | [![Build Status](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_apis/build/status/AvaloniaUI.Avalonia)](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_build/latest?definitionId=4) | [![Backers on Open Collective](https://opencollective.com/Avalonia/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/Avalonia/sponsors/badge.svg)](#sponsors) | +| [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/AvaloniaUI/Avalonia?utm_campaign=pr-badge&utm_content=badge&utm_medium=badge&utm_source=badge) | [![Build Status](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_apis/build/status/AvaloniaUI.Avalonia)](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_build/latest?definitionId=4) | [![Backers on Open Collective](https://opencollective.com/Avalonia/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/Avalonia/sponsors/badge.svg)](#sponsors) | [![NuGet](https://img.shields.io/nuget/v/Avalonia.svg)](https://www.nuget.org/packages/Avalonia) | [![MyGet](https://img.shields.io/myget/avalonia-ci/vpre/Avalonia.svg?label=myget)](https://www.myget.org/gallery/avalonia-ci) | ## About From 2f95655a24677843c053f248a286e51efe973b88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Fri, 18 Jan 2019 19:29:45 +0100 Subject: [PATCH 08/10] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 897f6db0c0..140184ee83 100644 --- a/readme.md +++ b/readme.md @@ -3,7 +3,7 @@ # Avalonia | Gitter Chat | Build Status (Win, Linux, OSX) | Open Collective | NuGet | MyGet | -|---|---|---| +|---|---|---|---|---|---| | [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/AvaloniaUI/Avalonia?utm_campaign=pr-badge&utm_content=badge&utm_medium=badge&utm_source=badge) | [![Build Status](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_apis/build/status/AvaloniaUI.Avalonia)](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_build/latest?definitionId=4) | [![Backers on Open Collective](https://opencollective.com/Avalonia/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/Avalonia/sponsors/badge.svg)](#sponsors) | [![NuGet](https://img.shields.io/nuget/v/Avalonia.svg)](https://www.nuget.org/packages/Avalonia) | [![MyGet](https://img.shields.io/myget/avalonia-ci/vpre/Avalonia.svg?label=myget)](https://www.myget.org/gallery/avalonia-ci) | ## About From 9437314a6d778ec763cdb5ec343cd044277d8e03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Fri, 18 Jan 2019 19:32:38 +0100 Subject: [PATCH 09/10] Update readme.md --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 140184ee83..12f683bd55 100644 --- a/readme.md +++ b/readme.md @@ -1,9 +1,9 @@ - + # Avalonia | Gitter Chat | Build Status (Win, Linux, OSX) | Open Collective | NuGet | MyGet | -|---|---|---|---|---|---| +|---|---|---|---|---| | [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/AvaloniaUI/Avalonia?utm_campaign=pr-badge&utm_content=badge&utm_medium=badge&utm_source=badge) | [![Build Status](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_apis/build/status/AvaloniaUI.Avalonia)](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_build/latest?definitionId=4) | [![Backers on Open Collective](https://opencollective.com/Avalonia/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/Avalonia/sponsors/badge.svg)](#sponsors) | [![NuGet](https://img.shields.io/nuget/v/Avalonia.svg)](https://www.nuget.org/packages/Avalonia) | [![MyGet](https://img.shields.io/myget/avalonia-ci/vpre/Avalonia.svg?label=myget)](https://www.myget.org/gallery/avalonia-ci) | ## About From 591ecc4ded6e5fdaeb1a8d46e6559596f09c3f50 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Fri, 18 Jan 2019 22:27:20 +0300 Subject: [PATCH 10/10] [RENDER] Don't crash on Paint call when renderer is already disposed --- src/Avalonia.Visuals/Rendering/DeferredRenderer.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs index 084b14ea97..60e624948e 100644 --- a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs +++ b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs @@ -29,6 +29,7 @@ namespace Avalonia.Rendering private readonly ISceneBuilder _sceneBuilder; private bool _running; + private bool _disposed; private volatile IRef _scene; private DirtyVisuals _dirty; private IRef _overlay; @@ -125,6 +126,9 @@ namespace Avalonia.Rendering { lock (_sceneLock) { + if (_disposed) + return; + _disposed = true; var scene = _scene; _scene = null; scene?.Dispose(); @@ -171,7 +175,7 @@ namespace Avalonia.Rendering var t = (IRenderLoopTask)this; if(t.NeedsUpdate) UpdateScene(); - if(_scene.Item != null) + if(_scene?.Item != null) Render(true); } @@ -481,6 +485,8 @@ namespace Avalonia.Rendering Dispatcher.UIThread.VerifyAccess(); lock (_sceneLock) { + if (_disposed) + return; if (_scene?.Item.Generation > _lastSceneId) return; }