diff --git a/src/Avalonia.Animation/DisposeAnimationInstanceSubject.cs b/src/Avalonia.Animation/DisposeAnimationInstanceSubject.cs index b44f392ce3..0c15524362 100644 --- a/src/Avalonia.Animation/DisposeAnimationInstanceSubject.cs +++ b/src/Avalonia.Animation/DisposeAnimationInstanceSubject.cs @@ -2,14 +2,7 @@ // Licensed under the MIT license. See licence.md file in the project root for full license information. using System; -using System.Collections.Generic; -using System.Linq; -using System.Reactive.Linq; using Avalonia.Animation.Animators; -using Avalonia.Animation.Utils; -using Avalonia.Collections; -using Avalonia.Data; -using Avalonia.Reactive; namespace Avalonia.Animation { @@ -46,6 +39,7 @@ namespace Avalonia.Animation public void OnError(Exception error) { _lastInstance?.Dispose(); + _lastInstance = null; } void IObserver.OnNext(bool matchVal) @@ -53,12 +47,18 @@ namespace Avalonia.Animation if (matchVal != _lastMatch) { _lastInstance?.Dispose(); + if (matchVal) { _lastInstance = _animator.Run(_animation, _control, _clock, _onComplete); } + else + { + _lastInstance = null; + } + _lastMatch = matchVal; } } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/PriorityLevel.cs b/src/Avalonia.Base/PriorityLevel.cs index 6366911e77..a2364083ea 100644 --- a/src/Avalonia.Base/PriorityLevel.cs +++ b/src/Avalonia.Base/PriorityLevel.cs @@ -3,7 +3,8 @@ using System; using System.Collections.Generic; -using System.Reactive.Disposables; +using System.Diagnostics; +using System.Threading; using Avalonia.Data; namespace Avalonia @@ -181,9 +182,9 @@ namespace Avalonia private sealed class RemoveBindingDisposable : IDisposable { - private readonly LinkedListNode _binding; private readonly LinkedList _bindings; private readonly PriorityLevel _priorityLevel; + private LinkedListNode _binding; public RemoveBindingDisposable( LinkedListNode binding, @@ -197,11 +198,21 @@ namespace Avalonia public void Dispose() { - PriorityBindingEntry entry = _binding.Value; + LinkedListNode binding = Interlocked.Exchange(ref _binding, null); + + if (binding == null) + { + // Some system is trying to remove binding twice. + Debug.Assert(false); + + return; + } + + PriorityBindingEntry entry = binding.Value; if (!entry.HasCompleted) { - _bindings.Remove(_binding); + _bindings.Remove(binding); entry.Dispose(); diff --git a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs index a50175bdee..6869ea0822 100644 --- a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs +++ b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs @@ -1088,7 +1088,9 @@ namespace Avalonia.Controls.Primitives } else { - SelectedIndex = _updateSelectedIndex != int.MinValue ? _updateSelectedIndex : 0; + SelectedIndex = _updateSelectedIndex != int.MinValue ? + _updateSelectedIndex : + AlwaysSelected ? 0 : -1; } } } diff --git a/src/Avalonia.Visuals/Media/PathMarkupParser.cs b/src/Avalonia.Visuals/Media/PathMarkupParser.cs index 8852883dcc..e8f149df11 100644 --- a/src/Avalonia.Visuals/Media/PathMarkupParser.cs +++ b/src/Avalonia.Visuals/Media/PathMarkupParser.cs @@ -32,6 +32,7 @@ namespace Avalonia.Media private IGeometryContext _geometryContext; private Point _currentPoint; + private Point? _beginFigurePoint; private Point? _previousControlPoint; private bool _isOpen; private bool _isDisposed; @@ -180,6 +181,8 @@ namespace Avalonia.Media _geometryContext.BeginFigure(_currentPoint); + _beginFigurePoint = _currentPoint; + _isOpen = true; } @@ -212,6 +215,12 @@ namespace Avalonia.Media if (_isOpen) { _geometryContext.EndFigure(true); + + if (_beginFigurePoint != null) + { + _currentPoint = _beginFigurePoint.Value; + _beginFigurePoint = null; + } } _previousControlPoint = null; @@ -233,12 +242,6 @@ namespace Avalonia.Media { span = ReadSeparator(span); AddLine(ref span, relative); - - if (!relative) - { - _currentPoint = currentPoint; - CreateFigure(); - } } } diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs index 8f27ebe853..d5237e2aca 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs @@ -109,6 +109,43 @@ namespace Avalonia.Controls.UnitTests.Primitives Assert.True(items[1].IsSelected); } + [Fact] + public void SelectedIndex_Should_Be_Minus_1_After_Initialize() + { + var items = new[] + { + new Item(), + new Item(), + }; + + var target = new ListBox(); + target.BeginInit(); + target.Items = items; + target.Template = Template(); + target.EndInit(); + + Assert.Equal(-1, target.SelectedIndex); + } + + [Fact] + public void SelectedIndex_Should_Be_0_After_Initialize_With_AlwaysSelected() + { + var items = new[] + { + new Item(), + new Item(), + }; + + var target = new ListBox(); + target.BeginInit(); + target.SelectionMode = SelectionMode.Single | SelectionMode.AlwaysSelected; + target.Items = items; + target.Template = Template(); + target.EndInit(); + + Assert.Equal(0, target.SelectedIndex); + } + [Fact] public void Setting_SelectedIndex_During_Initialize_Should_Select_Item_When_AlwaysSelected_Is_Used() { diff --git a/tests/Avalonia.Visuals.UnitTests/Media/PathMarkupParserTests.cs b/tests/Avalonia.Visuals.UnitTests/Media/PathMarkupParserTests.cs index 5570378063..e1475dce80 100644 --- a/tests/Avalonia.Visuals.UnitTests/Media/PathMarkupParserTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/Media/PathMarkupParserTests.cs @@ -100,9 +100,7 @@ namespace Avalonia.Visuals.UnitTests.Media Assert.Equal(new Point(10, 10), lineSegment.Point); - figure = pathGeometry.Figures[1]; - - segment = figure.Segments[0]; + segment = figure.Segments[1]; Assert.IsType(segment); @@ -235,5 +233,30 @@ namespace Avalonia.Visuals.UnitTests.Media Assert.Throws(() => parser.Parse(pathData)); } } + + [Fact] + public void CloseFigure_Should_Move_CurrentPoint_To_CreateFigurePoint() + { + var pathGeometry = new PathGeometry(); + using (var context = new PathGeometryContext(pathGeometry)) + using (var parser = new PathMarkupParser(context)) + { + parser.Parse("M10,10L100,100Z m10,10"); + + Assert.Equal(2, pathGeometry.Figures.Count); + + var figure = pathGeometry.Figures[0]; + + Assert.Equal(new Point(10, 10), figure.StartPoint); + + Assert.Equal(true, figure.IsClosed); + + Assert.Equal(new Point(100, 100), ((LineSegment)figure.Segments[0]).Point); + + figure = pathGeometry.Figures[1]; + + Assert.Equal(new Point(20, 20), figure.StartPoint); + } + } } }