diff --git a/build/Base.props b/build/Base.props
index a60373ebb3..100c9088cd 100644
--- a/build/Base.props
+++ b/build/Base.props
@@ -1,5 +1,6 @@
+
diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs
index 87c9ed0bae..558e96e132 100644
--- a/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs
+++ b/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs
@@ -148,6 +148,19 @@ namespace Avalonia.Rendering.SceneGraph
return (VisualNode)node;
}
+ private static object GetOrCreateChildNode(Scene scene, IVisual child, VisualNode parent)
+ {
+ var result = (VisualNode)scene.FindNode(child);
+
+ if (result != null && result.Parent != parent)
+ {
+ Deindex(scene, result);
+ result = null;
+ }
+
+ return result ?? CreateNode(scene, child, parent);
+ }
+
private static void Update(DrawingContext context, Scene scene, VisualNode node, Rect clip, bool forceRecurse)
{
var visual = node.Visual;
@@ -231,7 +244,7 @@ namespace Avalonia.Rendering.SceneGraph
{
foreach (var child in visual.VisualChildren.OrderBy(x => x, ZIndexComparer.Instance))
{
- var childNode = scene.FindNode(child) ?? CreateNode(scene, child, node);
+ var childNode = GetOrCreateChildNode(scene, child, node);
Update(context, scene, (VisualNode)childNode, clip, forceRecurse);
}
diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/VisualNode.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/VisualNode.cs
index d342f2eb2e..d2a9e0a673 100644
--- a/src/Avalonia.Visuals/Rendering/SceneGraph/VisualNode.cs
+++ b/src/Avalonia.Visuals/Rendering/SceneGraph/VisualNode.cs
@@ -119,6 +119,11 @@ namespace Avalonia.Rendering.SceneGraph
throw new ObjectDisposedException("Visual node for {node.Visual}");
}
+ if (child.Parent != this)
+ {
+ throw new AvaloniaInternalException("VisualNode added to wrong parent.");
+ }
+
EnsureChildrenCreated();
_children.Add(child);
}
@@ -155,6 +160,11 @@ namespace Avalonia.Rendering.SceneGraph
throw new ObjectDisposedException("Visual node for {node.Visual}");
}
+ if (node.Parent != this)
+ {
+ throw new AvaloniaInternalException("VisualNode added to wrong parent.");
+ }
+
EnsureChildrenCreated();
_children[index] = node;
}
diff --git a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
index d37bec3334..2c6425e26c 100644
--- a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
+++ b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
@@ -1031,6 +1031,9 @@ namespace Avalonia.Win32.Interop
[DllImport("shcore.dll")]
public static extern long GetDpiForMonitor(IntPtr hmonitor, MONITOR_DPI_TYPE dpiType, out uint dpiX, out uint dpiY);
+ [DllImport("gdi32.dll")]
+ public static extern int GetDeviceCaps(IntPtr hdc, DEVICECAP nIndex);
+
[DllImport("shcore.dll")]
public static extern void GetScaleFactorForMonitor(IntPtr hMon, out uint pScale);
@@ -1147,6 +1150,12 @@ namespace Avalonia.Win32.Interop
}
}
+ public enum DEVICECAP
+ {
+ HORZRES = 8,
+ DESKTOPHORZRES = 118
+ }
+
public enum PROCESS_DPI_AWARENESS
{
PROCESS_DPI_UNAWARE = 0,
diff --git a/src/Windows/Avalonia.Win32/ScreenImpl.cs b/src/Windows/Avalonia.Win32/ScreenImpl.cs
index e77aa07bcd..df4cf7fa19 100644
--- a/src/Windows/Avalonia.Win32/ScreenImpl.cs
+++ b/src/Windows/Avalonia.Win32/ScreenImpl.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using Avalonia.Platform;
+using Avalonia.Win32.Interop;
using static Avalonia.Win32.Interop.UnmanagedMethods;
namespace Avalonia.Win32
@@ -28,9 +29,28 @@ namespace Avalonia.Win32
(IntPtr monitor, IntPtr hdcMonitor, ref Rect lprcMonitor, IntPtr data) =>
{
MONITORINFO monitorInfo = MONITORINFO.Create();
- if (GetMonitorInfo(monitor,ref monitorInfo))
+ if (GetMonitorInfo(monitor, ref monitorInfo))
{
- GetDpiForMonitor(monitor, MONITOR_DPI_TYPE.MDT_EFFECTIVE_DPI, out var x, out _);
+ var dpi = 1.0;
+
+ var shcore = LoadLibrary("shcore.dll");
+ var method = GetProcAddress(shcore, nameof(GetDpiForMonitor));
+ if (method != IntPtr.Zero)
+ {
+ GetDpiForMonitor(monitor, MONITOR_DPI_TYPE.MDT_EFFECTIVE_DPI, out var x, out _);
+ dpi = (double)x;
+ }
+ else
+ {
+ var hdc = GetDC(IntPtr.Zero);
+
+ double virtW = GetDeviceCaps(hdc, DEVICECAP.HORZRES);
+ double physW = GetDeviceCaps(hdc, DEVICECAP.DESKTOPHORZRES);
+
+ dpi = (96d * physW / virtW);
+
+ ReleaseDC(IntPtr.Zero, hdc);
+ }
RECT bounds = monitorInfo.rcMonitor;
RECT workingArea = monitorInfo.rcWork;
@@ -40,7 +60,7 @@ namespace Avalonia.Win32
new PixelRect(workingArea.left, workingArea.top, workingArea.right - workingArea.left,
workingArea.bottom - workingArea.top);
screens[index] =
- new WinScreen((double)x / 96.0d, avaloniaBounds, avaloniaWorkArea, monitorInfo.dwFlags == 1,
+ new WinScreen(dpi / 96.0d, avaloniaBounds, avaloniaWorkArea, monitorInfo.dwFlags == 1,
monitor);
index++;
}
diff --git a/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/DeferredDrawingContextImplTests.cs b/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/DeferredDrawingContextImplTests.cs
index 4d23c57eed..f57c73c45c 100644
--- a/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/DeferredDrawingContextImplTests.cs
+++ b/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/DeferredDrawingContextImplTests.cs
@@ -17,7 +17,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
public void Should_Add_VisualNode()
{
var parent = new VisualNode(new TestRoot(), null);
- var child = new VisualNode(Mock.Of(), null);
+ var child = new VisualNode(Mock.Of(), parent);
var layers = new SceneLayers(parent.Visual);
var target = new DeferredDrawingContextImpl(null, layers);
@@ -32,7 +32,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
public void Should_Not_Replace_Identical_VisualNode()
{
var parent = new VisualNode(new TestRoot(), null);
- var child = new VisualNode(Mock.Of(), null);
+ var child = new VisualNode(Mock.Of(), parent);
var layers = new SceneLayers(parent.Visual);
parent.AddChild(child);
@@ -50,8 +50,8 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
public void Should_Replace_Different_VisualNode()
{
var parent = new VisualNode(new TestRoot(), null);
- var child1 = new VisualNode(Mock.Of(), null);
- var child2 = new VisualNode(Mock.Of(), null);
+ var child1 = new VisualNode(Mock.Of(), parent);
+ var child2 = new VisualNode(Mock.Of(), parent);
var layers = new SceneLayers(parent.Visual);
parent.AddChild(child1);
@@ -78,8 +78,8 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
var layers = new SceneLayers(root);
var target = new DeferredDrawingContextImpl(null, layers);
- var child1 = new VisualNode(Mock.Of(), null) { LayerRoot = root };
- var child2 = new VisualNode(Mock.Of(), null) { LayerRoot = root };
+ var child1 = new VisualNode(Mock.Of(), node) { LayerRoot = root };
+ var child2 = new VisualNode(Mock.Of(), node) { LayerRoot = root };
target.BeginUpdate(node);
using (target.BeginUpdate(child1)) { }
diff --git a/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs b/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs
index 5fd14e9ea9..327ef98c4d 100644
--- a/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs
+++ b/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs
@@ -620,10 +620,9 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
border1.IsVisible = false;
scene = scene.CloneScene();
-
- var panelNode = (VisualNode)scene.FindNode(panel);
sceneBuilder.Update(scene, decorator);
+ var panelNode = (VisualNode)scene.FindNode(panel);
Assert.Equal(2, panelNode.Children.Count);
Assert.False(panelNode.Children[0].Disposed);
Assert.False(panelNode.Children[1].Disposed);
diff --git a/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/VisualNodeTests.cs b/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/VisualNodeTests.cs
index 3211c3397b..4ec3630053 100644
--- a/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/VisualNodeTests.cs
+++ b/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/VisualNodeTests.cs
@@ -24,7 +24,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
var node = new VisualNode(Mock.Of(), null);
var collection = node.Children;
- node.AddChild(Mock.Of());
+ node.AddChild(Mock.Of(x => x.Parent == node));
Assert.NotSame(collection, node.Children);
}
@@ -106,9 +106,9 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
public void TrimChildren_Should_Work_Correctly()
{
var parent = new VisualNode(Mock.Of(), null);
- var child1 = new VisualNode(Mock.Of(), null);
- var child2 = new VisualNode(Mock.Of(), null);
- var child3 = new VisualNode(Mock.Of(), null);
+ var child1 = new VisualNode(Mock.Of(), parent);
+ var child2 = new VisualNode(Mock.Of(), parent);
+ var child3 = new VisualNode(Mock.Of(), parent);
parent.AddChild(child1);
parent.AddChild(child2);