From 815d3f719ebbdb2e443e08ced24295e44dea73de Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 12 Oct 2017 09:42:24 +0200 Subject: [PATCH 01/12] Report correct root in logical tree attach/detach. Fixes #1192. --- src/Avalonia.Controls/Control.cs | 6 +-- .../ControlTests.cs | 41 ++++++++++++++++++- .../ContentPresenterTests_Standalone.cs | 4 ++ 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/src/Avalonia.Controls/Control.cs b/src/Avalonia.Controls/Control.cs index f3705c9127..7434bd6cc1 100644 --- a/src/Avalonia.Controls/Control.cs +++ b/src/Avalonia.Controls/Control.cs @@ -773,11 +773,9 @@ namespace Avalonia.Controls { while (e != null) { - var root = e as IStyleRoot; - - if (root != null && root.StylingParent == null) + if (e is IRenderRoot root) { - return root; + return root as IStyleRoot; } e = e.StylingParent; diff --git a/tests/Avalonia.Controls.UnitTests/ControlTests.cs b/tests/Avalonia.Controls.UnitTests/ControlTests.cs index 605406518d..b7e2cbeca9 100644 --- a/tests/Avalonia.Controls.UnitTests/ControlTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ControlTests.cs @@ -123,7 +123,26 @@ namespace Avalonia.Controls.UnitTests } [Fact] - public void DetachedToLogicalParent_Should_Be_Called_When_Removed_From_Tree() + public void AttachedToLogicalParent_Should_Not_Be_Called_With_GlobalStyles_As_Root() + { + var globalStyles = Mock.Of(); + var root = new TestRoot { StylingParent = globalStyles }; + var child = new Border(); + var raised = false; + + child.AttachedToLogicalTree += (s, e) => + { + Assert.Equal(root, e.Root); + raised = true; + }; + + root.Child = child; + + Assert.True(raised); + } + + [Fact] + public void DetachedFromLogicalParent_Should_Be_Called_When_Removed_From_Tree() { var root = new TestRoot(); var parent = new Border(); @@ -148,6 +167,26 @@ namespace Avalonia.Controls.UnitTests Assert.True(grandchildRaised); } + [Fact] + public void DetachedFromLogicalParent_Should_Not_Be_Called_With_GlobalStyles_As_Root() + { + var globalStyles = Mock.Of(); + var root = new TestRoot { StylingParent = globalStyles }; + var child = new Border(); + var raised = false; + + child.DetachedFromLogicalTree += (s, e) => + { + Assert.Equal(root, e.Root); + raised = true; + }; + + root.Child = child; + root.Child = null; + + Assert.True(raised); + } + [Fact] public void Adding_Tree_To_IStyleRoot_Should_Style_Controls() { diff --git a/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_Standalone.cs b/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_Standalone.cs index 032928d673..027e162877 100644 --- a/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_Standalone.cs +++ b/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_Standalone.cs @@ -12,6 +12,7 @@ using Moq; using System; using System.Linq; using Xunit; +using Avalonia.Rendering; namespace Avalonia.Controls.UnitTests.Presenters { @@ -56,6 +57,7 @@ namespace Avalonia.Controls.UnitTests.Presenters var parentMock = new Mock(); parentMock.As(); + parentMock.As(); parentMock.As(); (target as ISetLogicalParent).SetParent(parentMock.Object); @@ -100,6 +102,7 @@ namespace Avalonia.Controls.UnitTests.Presenters }; var parentMock = new Mock(); + parentMock.As(); parentMock.As(); parentMock.As().SetupGet(l => l.IsAttachedToLogicalTree).Returns(true); @@ -144,6 +147,7 @@ namespace Avalonia.Controls.UnitTests.Presenters var parentMock = new Mock(); parentMock.As(); + parentMock.As(); parentMock.As(); (target as ISetLogicalParent).SetParent(parentMock.Object); From d1eb0512bbffdec59b7c4664311693f057f29912 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 12 Oct 2017 14:23:45 +0200 Subject: [PATCH 02/12] Added failing test for #1171. --- .../Rendering/SceneGraph/SceneBuilderTests.cs | 54 +++++++++++++++++-- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs b/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs index c51e8941a9..d0f7671956 100644 --- a/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs @@ -143,13 +143,61 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph var borderNode = scene.FindNode(border); Assert.Equal(new Rect(50, 50, 50, 50), borderNode.ClipBounds); + } + } + + [Fact] + public void Should_Update_Descendent_ClipBounds_When_Margin_Changed() + { + using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface)) + { + Border border; + Canvas canvas; + var tree = new TestRoot + { + Width = 200, + Height = 300, + Child = canvas = new Canvas + { + ClipToBounds = true, + Width = 100, + Height = 100, + HorizontalAlignment = HorizontalAlignment.Left, + VerticalAlignment = VerticalAlignment.Top, + Children = + { + (border = new Border + { + Background = Brushes.AliceBlue, + Width = 100, + Height = 100, + [Canvas.LeftProperty] = 50, + [Canvas.TopProperty] = 50, + }) + } + } + }; + + tree.Measure(Size.Infinity); + tree.Arrange(new Rect(tree.DesiredSize)); - // Initial ClipBounds are correct, make sure they're still correct after updating border. + var scene = new Scene(tree); + var sceneBuilder = new SceneBuilder(); + sceneBuilder.UpdateAll(scene); + + var borderNode = scene.FindNode(border); + Assert.Equal(new Rect(50, 50, 50, 50), borderNode.ClipBounds); + + canvas.Width = canvas.Height = 125; + canvas.Measure(Size.Infinity); + canvas.Arrange(new Rect(tree.DesiredSize)); + + // Initial ClipBounds are correct, make sure they're still correct after updating canvas. scene = scene.Clone(); - Assert.True(sceneBuilder.Update(scene, border)); + Assert.True(sceneBuilder.Update(scene, canvas)); borderNode = scene.FindNode(border); - Assert.Equal(new Rect(50, 50, 50, 50), borderNode.ClipBounds); + Assert.Equal(new Rect(50, 50, 75, 75), borderNode.ClipBounds); } } From dc7740554ecda45c444ffd8807e30108d941f94e Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 12 Oct 2017 14:24:41 +0200 Subject: [PATCH 03/12] Propagate ClipBounds to child nodes. When a scenegraph node's ClipBounds changes, ensure that that change is propagated to child nodes. Fixes #1171 --- src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs index 10455eb147..90ef78de37 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs @@ -168,11 +168,14 @@ namespace Avalonia.Rendering.SceneGraph using (context.PushTransformContainer()) { var startLayer = opacity < 1 || visual.OpacityMask != null; + var clipBounds = bounds.TransformToAABB(contextImpl.Transform).Intersect(clip); - forceRecurse = forceRecurse || node.Transform != contextImpl.Transform; + forceRecurse = forceRecurse || + node.Transform != contextImpl.Transform || + node.ClipBounds != clipBounds; node.Transform = contextImpl.Transform; - node.ClipBounds = bounds.TransformToAABB(node.Transform).Intersect(clip); + node.ClipBounds = clipBounds; node.ClipToBounds = clipToBounds; node.GeometryClip = visual.Clip?.PlatformImpl; node.Opacity = opacity; From 763775fa824cc6263e9c397447651db9aec5e761 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 12 Oct 2017 23:26:31 +0200 Subject: [PATCH 04/12] Clear mouse capture when control removed. When a captured control is removed from the visual tree, clear the mouse capture. Note that our capture logic needs to be improved - it shouldn't be possible to capture a non-visible or non-enabled control. This doesn't address that but it does fix the crash in #1203. Fixes #1203 --- src/Avalonia.Input/MouseDevice.cs | 22 +++++++++++++++++-- .../MouseDeviceTests.cs | 19 +++++++++++++++- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/Avalonia.Input/MouseDevice.cs b/src/Avalonia.Input/MouseDevice.cs index 875a5ebaee..50cdb5945c 100644 --- a/src/Avalonia.Input/MouseDevice.cs +++ b/src/Avalonia.Input/MouseDevice.cs @@ -20,6 +20,8 @@ namespace Avalonia.Input private int _clickCount; private Rect _lastClickRect; private uint _lastClickTime; + private IInputElement _captured; + private IDisposable _capturedSubscription; /// /// Gets the control that is currently capturing by the mouse, if any. @@ -31,8 +33,23 @@ namespace Avalonia.Input /// public IInputElement Captured { - get; - protected set; + get => _captured; + protected set + { + _capturedSubscription?.Dispose(); + _capturedSubscription = null; + + if (value != null) + { + _capturedSubscription = Observable.FromEventPattern( + x => value.DetachedFromVisualTree += x, + x => value.DetachedFromVisualTree -= x) + .Take(1) + .Subscribe(_ => Captured = null); + } + + _captured = value; + } } /// @@ -55,6 +72,7 @@ namespace Avalonia.Input /// public virtual void Capture(IInputElement control) { + // TODO: Check visibility and enabled state before setting capture. Captured = control; } diff --git a/tests/Avalonia.Input.UnitTests/MouseDeviceTests.cs b/tests/Avalonia.Input.UnitTests/MouseDeviceTests.cs index 4a834fd55d..6aca69b88f 100644 --- a/tests/Avalonia.Input.UnitTests/MouseDeviceTests.cs +++ b/tests/Avalonia.Input.UnitTests/MouseDeviceTests.cs @@ -1,6 +1,5 @@ using Avalonia.Controls; using Avalonia.Input.Raw; -using Avalonia.Layout; using Avalonia.Rendering; using Avalonia.UnitTests; using Avalonia.VisualTree; @@ -12,6 +11,24 @@ namespace Avalonia.Input.UnitTests { public class MouseDeviceTests { + [Fact] + public void Capture_Is_Cleared_When_Control_Removed() + { + Canvas control; + var root = new TestRoot + { + Child = control = new Canvas(), + }; + var target = new MouseDevice(); + + target.Capture(control); + Assert.Same(control, target.Captured); + + root.Child = null; + + Assert.Null(target.Captured); + } + [Fact] public void MouseMove_Should_Update_PointerOver() { From a0f4d3fb051897d521f76241d8428a62317c9548 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 12 Oct 2017 23:27:25 +0200 Subject: [PATCH 05/12] Ignore Avalonia.Designer.HostApp in ncrunch. --- .ncrunch/Avalonia.Designer.HostApp.v3.ncrunchproject | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .ncrunch/Avalonia.Designer.HostApp.v3.ncrunchproject diff --git a/.ncrunch/Avalonia.Designer.HostApp.v3.ncrunchproject b/.ncrunch/Avalonia.Designer.HostApp.v3.ncrunchproject new file mode 100644 index 0000000000..319cd523ce --- /dev/null +++ b/.ncrunch/Avalonia.Designer.HostApp.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + True + + \ No newline at end of file From 3402456284313264e31cf8485b3c762ff6b3d28a Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 13 Oct 2017 14:38:48 +0200 Subject: [PATCH 06/12] Always raise logical tree attach/detach events. Previously, if the user overrode `OnAttachedToLogicalTree` or `OnDetachedFromLogicalTree` and forgot to call the base implementation, the events wouldn't be raised. It's very important that these events get raised so moved the code to raise them to `OnAttachedToLogicalTreeCore`/`OnDetachedFromLogicalTreeCore`. --- src/Avalonia.Controls/Control.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/Control.cs b/src/Avalonia.Controls/Control.cs index f3705c9127..050315af7c 100644 --- a/src/Avalonia.Controls/Control.cs +++ b/src/Avalonia.Controls/Control.cs @@ -656,7 +656,6 @@ namespace Avalonia.Controls /// The event args. protected virtual void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e) { - AttachedToLogicalTree?.Invoke(this, e); } /// @@ -665,7 +664,6 @@ namespace Avalonia.Controls /// The event args. protected virtual void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e) { - DetachedFromLogicalTree?.Invoke(this, e); } /// @@ -844,6 +842,7 @@ namespace Avalonia.Controls InitializeStylesIfNeeded(true); OnAttachedToLogicalTree(e); + AttachedToLogicalTree?.Invoke(this, e); } foreach (var child in LogicalChildren.OfType()) @@ -864,6 +863,7 @@ namespace Avalonia.Controls _isAttachedToLogicalTree = false; _styleDetach.OnNext(this); OnDetachedFromLogicalTree(e); + DetachedFromLogicalTree?.Invoke(this, e); foreach (var child in LogicalChildren.OfType()) { From 2c61d17bc3efc967716f4620dcb4dae9189b17d0 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 13 Oct 2017 15:45:25 +0200 Subject: [PATCH 07/12] Always raise visual tree attach/detach events. Previously, if the user overrode `OnAttachedToVisualTree` or `OnDetachedFromVisualTree` and forgot to call the base implementation, the events wouldn't be raised. It's very important that these events get raised so moved the code to raise them to `OnAttachedToVisualTreeCore`/`OnDetachedFromVisualTreeCore`. --- src/Avalonia.Visuals/Visual.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Visuals/Visual.cs b/src/Avalonia.Visuals/Visual.cs index cfe6bce7e0..bc65d4f69f 100644 --- a/src/Avalonia.Visuals/Visual.cs +++ b/src/Avalonia.Visuals/Visual.cs @@ -329,6 +329,7 @@ namespace Avalonia } OnAttachedToVisualTree(e); + AttachedToVisualTree?.Invoke(this, e); InvalidateVisual(); if (VisualChildren != null) @@ -357,6 +358,7 @@ namespace Avalonia } OnDetachedFromVisualTree(e); + DetachedFromVisualTree?.Invoke(this, e); e.Root?.Renderer?.AddDirty(this); if (VisualChildren != null) @@ -374,7 +376,6 @@ namespace Avalonia /// The event args. protected virtual void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) { - AttachedToVisualTree?.Invoke(this, e); } /// @@ -383,7 +384,6 @@ namespace Avalonia /// The event args. protected virtual void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) { - DetachedFromVisualTree?.Invoke(this, e); } /// From fbba93f4218feb983252602e51ca2dd919af12f2 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 13 Oct 2017 17:11:33 +0100 Subject: [PATCH 08/12] update replace scripts. --- scripts/ReplaceNugetCache.ps1 | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/scripts/ReplaceNugetCache.ps1 b/scripts/ReplaceNugetCache.ps1 index 5f678bedef..4ad31db274 100644 --- a/scripts/ReplaceNugetCache.ps1 +++ b/scripts/ReplaceNugetCache.ps1 @@ -1,5 +1,4 @@ -copy ..\samples\ControlCatalog.NetCore\bin\Debug\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia\$args\lib\netcoreapp1.0\ -copy ..\samples\ControlCatalog.NetCore.\bin\Debug\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia\$args\lib\netstandard1.3\ -copy ..\samples\ControlCatalog.NetCore.\bin\Debug\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia.gtk3\$args\lib\netstandard1.3\ -copy ..\samples\ControlCatalog.NetCore.\bin\Debug\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia.skia.desktop\$args\lib\netstandard1.3\ -copy ..\samples\ControlCatalog.NetCore.\bin\Debug\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia.win32\$args\lib\netstandard1.3\ +copy ..\samples\ControlCatalog.NetCore\bin\Debug\netcoreapp2.0\Avalonia**.dll ~\.nuget\packages\avalonia\$args\lib\netcoreapp2.0\ +copy ..\samples\ControlCatalog.NetCore.\bin\Debug\netcoreapp2.0\Avalonia**.dll ~\.nuget\packages\avalonia\$args\lib\netstandard2.0\ +copy ..\samples\ControlCatalog.NetCore.\bin\Debug\netcoreapp2.0\Avalonia**.dll ~\.nuget\packages\avalonia.gtk3\$args\lib\netstandard2.0\ +copy ..\samples\ControlCatalog.NetCore.\bin\Debug\netcoreapp2.0\Avalonia**.dll ~\.nuget\packages\avalonia.win32\$args\lib\netstandard2.0\ From aa2980b8c833f50b2b895a93802d7b3b256d4af3 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 13 Oct 2017 19:10:09 +0200 Subject: [PATCH 09/12] Don't return detached controls in HitTest. If a control has been detached from the visual tree but the scene hasn't yet been updated, don't return the control as part of a hit-test. --- src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs index a85fd36763..a4af106a73 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs @@ -173,7 +173,7 @@ namespace Avalonia.Rendering.SceneGraph } } - if (node.HitTest(p)) + if (node.HitTest(p) && node.Visual.IsAttachedToVisualTree) { yield return node.Visual; } From 30a31006cc19ab7b102aeaeb410cf47d5e9a66b1 Mon Sep 17 00:00:00 2001 From: Unknown Date: Fri, 13 Oct 2017 19:52:33 +0100 Subject: [PATCH 10/12] update linux and release replace scripts. --- scripts/ReplaceNugetCache.sh | 7 +++---- scripts/ReplaceNugetCacheRelease.ps1 | 9 ++++----- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/scripts/ReplaceNugetCache.sh b/scripts/ReplaceNugetCache.sh index 2ce3e7648d..636aec5f23 100755 --- a/scripts/ReplaceNugetCache.sh +++ b/scripts/ReplaceNugetCache.sh @@ -1,7 +1,6 @@ #!/usr/bin/env bash - cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp1.1/Avalonia**.dll ~/.nuget/packages/avalonia/$1/lib/netcoreapp1.0/ - cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp1.1/Avalonia**.dll ~/.nuget/packages/avalonia/$1/lib/netstandard1.1/ - cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp1.1/Avalonia**.dll ~/.nuget/packages/avalonia.gtk3/$1/lib/netstandard1.1/ - cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp1.1/Avalonia**.dll ~/.nuget/packages/avalonia.skia.desktop/$1/lib/netstandard1.3/ + cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp2.0/Avalonia**.dll ~/.nuget/packages/avalonia/$1/lib/netcoreapp2.0/ + cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp2.0/Avalonia**.dll ~/.nuget/packages/avalonia/$1/lib/netstandard2.0/ + cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp2.0/Avalonia**.dll ~/.nuget/packages/avalonia.gtk3/$1/lib/netstandard2.0/ diff --git a/scripts/ReplaceNugetCacheRelease.ps1 b/scripts/ReplaceNugetCacheRelease.ps1 index f3c1a0a975..f188c81c51 100644 --- a/scripts/ReplaceNugetCacheRelease.ps1 +++ b/scripts/ReplaceNugetCacheRelease.ps1 @@ -1,5 +1,4 @@ -copy ..\samples\ControlCatalog.NetCore\bin\Release\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia\$args\lib\netcoreapp1.0\ -copy ..\samples\ControlCatalog.NetCore.\bin\Release\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia\$args\lib\netstandard1.3\ -copy ..\samples\ControlCatalog.NetCore.\bin\Release\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia.gtk3\$args\lib\netstandard1.3\ -copy ..\samples\ControlCatalog.NetCore.\bin\Release\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia.skia.desktop\$args\lib\netstandard1.3\ -copy ..\samples\ControlCatalog.NetCore.\bin\Release\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia.win32\$args\lib\netstandard1.3\ +copy ..\samples\ControlCatalog.NetCore\bin\Release\netcoreapp2.0\Avalonia**.dll ~\.nuget\packages\avalonia\$args\lib\netcoreapp2.0\ +copy ..\samples\ControlCatalog.NetCore.\bin\Release\netcoreapp2.0\Avalonia**.dll ~\.nuget\packages\avalonia\$args\lib\netstandard2.0\ +copy ..\samples\ControlCatalog.NetCore.\bin\Release\netcoreapp2.0\Avalonia**.dll ~\.nuget\packages\avalonia.gtk3\$args\lib\netstandard2.0\ +copy ..\samples\ControlCatalog.NetCore.\bin\Release\netcoreapp2.0\Avalonia**.dll ~\.nuget\packages\avalonia.win32\$args\lib\netstandard2.0\ \ No newline at end of file From 83b21aab08167e474909951660441b2164f6350b Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sat, 14 Oct 2017 11:15:11 +0200 Subject: [PATCH 11/12] Disable osx builds They're failing and not that useful anyway. --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 52a400d19a..ea09278cdd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: csharp os: - linux - - osx dist: trusty osx_image: xcode8.3 env: From 268587c4320c43b9eb861a88119ab2e6ba4d8f9f Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sat, 14 Oct 2017 11:31:47 +0200 Subject: [PATCH 12/12] Fix DropDown popup opening. When the `DropDown` control is clicked, toggle the opening of the popup. Fixes #1169. --- src/Avalonia.Controls/DropDown.cs | 20 +++++++------- .../DropDownTests.cs | 26 +++++++++++++++++-- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/Avalonia.Controls/DropDown.cs b/src/Avalonia.Controls/DropDown.cs index 5349fb1ca7..fa2e0c1e16 100644 --- a/src/Avalonia.Controls/DropDown.cs +++ b/src/Avalonia.Controls/DropDown.cs @@ -120,21 +120,21 @@ namespace Avalonia.Controls /// protected override void OnPointerPressed(PointerPressedEventArgs e) { - if (!IsDropDownOpen && ((IVisual)e.Source).GetVisualRoot() is PopupRoot) - { - IsDropDownOpen = true; - e.Handled = true; - } - if (!e.Handled) { - if (UpdateSelectionFromEventSource(e.Source)) + if (((IVisual)e.Source).GetVisualRoot() is PopupRoot) { - _popup?.Close(); - e.Handled = true; + if (UpdateSelectionFromEventSource(e.Source)) + { + _popup?.Close(); + e.Handled = true; + } + } + else + { + IsDropDownOpen = !IsDropDownOpen; } } - base.OnPointerPressed(e); } diff --git a/tests/Avalonia.Controls.UnitTests/DropDownTests.cs b/tests/Avalonia.Controls.UnitTests/DropDownTests.cs index 30cca90b4a..b5de8c67fa 100644 --- a/tests/Avalonia.Controls.UnitTests/DropDownTests.cs +++ b/tests/Avalonia.Controls.UnitTests/DropDownTests.cs @@ -1,21 +1,43 @@ // 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.Linq; using Avalonia.Controls.Presenters; using Avalonia.Controls.Primitives; using Avalonia.Controls.Shapes; using Avalonia.Controls.Templates; +using Avalonia.Input; using Avalonia.LogicalTree; using Avalonia.Media; using Avalonia.UnitTests; -using Avalonia.VisualTree; using Xunit; namespace Avalonia.Controls.UnitTests { public class DropDownTests { + [Fact] + public void Clicking_On_Control_Toggles_IsDropDownOpen() + { + var target = new DropDown + { + Items = new[] { "Foo", "Bar" }, + }; + + target.RaiseEvent(new PointerPressedEventArgs + { + RoutedEvent = InputElement.PointerPressedEvent, + }); + + Assert.True(target.IsDropDownOpen); + + target.RaiseEvent(new PointerPressedEventArgs + { + RoutedEvent = InputElement.PointerPressedEvent, + }); + + Assert.False(target.IsDropDownOpen); + } + [Fact] public void SelectionBoxItem_Is_Rectangle_With_VisualBrush_When_Selection_Is_Control() {