From b6447c0e0920966eeaf2052934651a360a7722c9 Mon Sep 17 00:00:00 2001 From: Andrey Kunchev Date: Tue, 1 Oct 2019 19:06:00 +0300 Subject: [PATCH 01/20] failing test for #3053 --- .../Media/PathMarkupParserTests.cs | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/Avalonia.Visuals.UnitTests/Media/PathMarkupParserTests.cs b/tests/Avalonia.Visuals.UnitTests/Media/PathMarkupParserTests.cs index 5570378063..5cdbcd9116 100644 --- a/tests/Avalonia.Visuals.UnitTests/Media/PathMarkupParserTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/Media/PathMarkupParserTests.cs @@ -235,5 +235,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); + } + } } } From 2b9180c794b77e6ca5db4f5519929b6b5fcdfc8d Mon Sep 17 00:00:00 2001 From: Andrey Kunchev Date: Tue, 1 Oct 2019 22:27:10 +0300 Subject: [PATCH 02/20] fix invalid test related to issue #3053 --- .../Avalonia.Visuals.UnitTests/Media/PathMarkupParserTests.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/Avalonia.Visuals.UnitTests/Media/PathMarkupParserTests.cs b/tests/Avalonia.Visuals.UnitTests/Media/PathMarkupParserTests.cs index 5cdbcd9116..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); From a675cd2e687f53a79404769c149e1e37e36f4ac4 Mon Sep 17 00:00:00 2001 From: Andrey Kunchev Date: Tue, 1 Oct 2019 22:43:14 +0300 Subject: [PATCH 03/20] when close figure set current point back to start, fixes partially #3053 --- src/Avalonia.Visuals/Media/PathMarkupParser.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Avalonia.Visuals/Media/PathMarkupParser.cs b/src/Avalonia.Visuals/Media/PathMarkupParser.cs index 8852883dcc..c93edaca14 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; From f4c7f63ae7ca14c92248e7f71a752d632b75cde3 Mon Sep 17 00:00:00 2001 From: Andrey Kunchev Date: Tue, 1 Oct 2019 22:45:24 +0300 Subject: [PATCH 04/20] remove wrong logic for path assume line by default if command is missing --- src/Avalonia.Visuals/Media/PathMarkupParser.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/Avalonia.Visuals/Media/PathMarkupParser.cs b/src/Avalonia.Visuals/Media/PathMarkupParser.cs index c93edaca14..e8f149df11 100644 --- a/src/Avalonia.Visuals/Media/PathMarkupParser.cs +++ b/src/Avalonia.Visuals/Media/PathMarkupParser.cs @@ -242,12 +242,6 @@ namespace Avalonia.Media { span = ReadSeparator(span); AddLine(ref span, relative); - - if (!relative) - { - _currentPoint = currentPoint; - CreateFigure(); - } } } From 677762c336c68711c9c0fc7463bc3c68916d7a50 Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Tue, 1 Oct 2019 23:13:07 +0200 Subject: [PATCH 05/20] Cache method value. --- src/Avalonia.Base/Utilities/WeakEventHandlerManager.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Avalonia.Base/Utilities/WeakEventHandlerManager.cs b/src/Avalonia.Base/Utilities/WeakEventHandlerManager.cs index f4cec98628..37e25d0fac 100644 --- a/src/Avalonia.Base/Utilities/WeakEventHandlerManager.cs +++ b/src/Avalonia.Base/Utilities/WeakEventHandlerManager.cs @@ -142,10 +142,12 @@ namespace Avalonia.Utilities _data = ndata; } + MethodInfo method = s.Method; + var subscriber = (TSubscriber)s.Target; - if (!s_Callers.TryGetValue(s.Method, out var caller)) - s_Callers[s.Method] = caller = - (CallerDelegate)Delegate.CreateDelegate(typeof(CallerDelegate), null, s.Method); + if (!s_Callers.TryGetValue(method, out var caller)) + s_Callers[method] = caller = + (CallerDelegate)Delegate.CreateDelegate(typeof(CallerDelegate), null, method); _data[_count] = new Descriptor { Caller = caller, From ca1d231fce70524fe067f2857a2bb27fc0423d1e Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Wed, 2 Oct 2019 00:27:02 +0200 Subject: [PATCH 06/20] Reduce boxing allocations. --- .../ControlCatalog/ViewModels/ItemsRepeaterPageViewModel.cs | 2 +- src/Avalonia.Base/Utilities/SingleOrDictionary.cs | 2 +- src/Avalonia.Controls/Calendar/DatePicker.cs | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/samples/ControlCatalog/ViewModels/ItemsRepeaterPageViewModel.cs b/samples/ControlCatalog/ViewModels/ItemsRepeaterPageViewModel.cs index 436a479441..25fd550520 100644 --- a/samples/ControlCatalog/ViewModels/ItemsRepeaterPageViewModel.cs +++ b/samples/ControlCatalog/ViewModels/ItemsRepeaterPageViewModel.cs @@ -11,7 +11,7 @@ namespace ControlCatalog.ViewModels public ItemsRepeaterPageViewModel() { Items = new ObservableCollection( - Enumerable.Range(1, 100000).Select(i => $"Item {i}")); + Enumerable.Range(1, 100000).Select(i => $"Item {i.ToString()}")); } public ObservableCollection Items { get; } diff --git a/src/Avalonia.Base/Utilities/SingleOrDictionary.cs b/src/Avalonia.Base/Utilities/SingleOrDictionary.cs index bda85f90e2..140da6750d 100644 --- a/src/Avalonia.Base/Utilities/SingleOrDictionary.cs +++ b/src/Avalonia.Base/Utilities/SingleOrDictionary.cs @@ -38,7 +38,7 @@ namespace Avalonia.Utilities { if (dictionary == null) { - if (!_singleValue.HasValue || !_singleValue.Value.Key.Equals(key)) + if (!_singleValue.HasValue || !EqualityComparer.Default.Equals(_singleValue.Value.Key, key)) { value = default(TValue); return false; diff --git a/src/Avalonia.Controls/Calendar/DatePicker.cs b/src/Avalonia.Controls/Calendar/DatePicker.cs index 70de8bec16..55797ae1e3 100644 --- a/src/Avalonia.Controls/Calendar/DatePicker.cs +++ b/src/Avalonia.Controls/Calendar/DatePicker.cs @@ -1042,7 +1042,8 @@ namespace Avalonia.Controls } } DateTime? d = SetTextBoxValue(s); - if (!SelectedDate.Equals(d)) + + if (SelectedDate != d) { SelectedDate = d; } @@ -1058,7 +1059,8 @@ namespace Avalonia.Controls else { DateTime? d = SetTextBoxValue(_defaultText); - if (!SelectedDate.Equals(d)) + + if (SelectedDate != d) { SelectedDate = d; } From c70721aa2c7aae2172536bb3e29348205d2a08cf Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Wed, 2 Oct 2019 00:31:11 +0200 Subject: [PATCH 07/20] Avoid integer boxing. --- samples/ControlCatalog/Pages/ListBoxPage.xaml.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/ControlCatalog/Pages/ListBoxPage.xaml.cs b/samples/ControlCatalog/Pages/ListBoxPage.xaml.cs index cdbf8fd2b6..0f2d4461bf 100644 --- a/samples/ControlCatalog/Pages/ListBoxPage.xaml.cs +++ b/samples/ControlCatalog/Pages/ListBoxPage.xaml.cs @@ -78,7 +78,7 @@ namespace ControlCatalog.Pages } } - private string GenerateItem() => $"Item {_counter++}"; + private string GenerateItem() => $"Item {_counter++.ToString()}"; } } } From 2f525dfdad51e54de3e913f83b13851d22596c0f Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Wed, 2 Oct 2019 14:04:00 +0800 Subject: [PATCH 08/20] Fix on linux clients without a `Screen`. --- src/Avalonia.X11/X11Window.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 00761dfce8..5b9eebb9cb 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -100,14 +100,17 @@ namespace Avalonia.X11 int defaultWidth = 300, defaultHeight = 200; - if (!_popup) + if (!_popup && Screen != null) { var monitor = Screen.AllScreens.OrderBy(x => x.PixelDensity) .FirstOrDefault(m => m.Bounds.Contains(Position)); - // Emulate Window 7+'s default window size behavior. - defaultWidth = (int)(monitor.WorkingArea.Width * 0.75d); - defaultHeight = (int)(monitor.WorkingArea.Height * 0.7d); + if (monitor != null) + { + // Emulate Window 7+'s default window size behavior. + defaultWidth = (int)(monitor.WorkingArea.Width * 0.75d); + defaultHeight = (int)(monitor.WorkingArea.Height * 0.7d); + } } _handle = XCreateWindow(_x11.Display, _x11.RootWindow, 10, 10, defaultWidth, defaultHeight, 0, From 8093716a3680cc6a7e53195cca14269d7fb25b28 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Wed, 2 Oct 2019 13:04:04 +0200 Subject: [PATCH 09/20] Added tests for selection after initialization. --- .../Primitives/SelectingItemsControlTests.cs | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) 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() { From 60e3c3c9772d413f9ac02d6d1869bfb4a9827eed Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Wed, 2 Oct 2019 13:06:15 +0200 Subject: [PATCH 10/20] Fix selection after initialization. Fixes first item in menus being selected when menu is shown. --- src/Avalonia.Controls/Primitives/SelectingItemsControl.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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; } } } From 15e15f227f0f11bc38b7b42f42ca818676d55613 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dariusz=20Komosi=C5=84ski?= Date: Wed, 2 Oct 2019 14:17:04 +0200 Subject: [PATCH 11/20] Fix double dispose of bindings caused by animations. Add assertion for double dispose. --- .../DisposeAnimationInstanceSubject.cs | 16 ++++++++-------- src/Avalonia.Base/PriorityLevel.cs | 19 +++++++++++++++---- 2 files changed, 23 insertions(+), 12 deletions(-) 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(); From 9a9ef657e26ea7f0bf382ce0041eebe575fb211d Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 3 Oct 2019 17:46:30 +0200 Subject: [PATCH 12/20] Ported Track layout code from WPF. To fix problem with scrollbar layout when the scrollbar range was large. NOTE: This commit adds `Track.IsDirectionReversed` and modifies the default direction of vertical tracks to be the reverse of before in order to match WPF. --- src/Avalonia.Controls/Primitives/Track.cs | 318 +++++++++++++++------ src/Avalonia.Themes.Default/ScrollBar.xaml | 3 +- src/Avalonia.Themes.Default/Slider.xaml | 2 +- 3 files changed, 236 insertions(+), 87 deletions(-) diff --git a/src/Avalonia.Controls/Primitives/Track.cs b/src/Avalonia.Controls/Primitives/Track.cs index 21a7dd68f8..0af8ac3415 100644 --- a/src/Avalonia.Controls/Primitives/Track.cs +++ b/src/Avalonia.Controls/Primitives/Track.cs @@ -1,10 +1,13 @@ -// 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. +// Portions of this source file are adapted from the Windows Presentation Foundation project. +// (https://github.com/dotnet/wpf/) +// +// Licensed to The Avalonia Project under MIT License, courtesy of The .NET Foundation. using System; using Avalonia.Input; using Avalonia.Layout; using Avalonia.Metadata; +using Avalonia.Utilities; namespace Avalonia.Controls.Primitives { @@ -34,6 +37,9 @@ namespace Avalonia.Controls.Primitives public static readonly StyledProperty + - + + + + + + + diff --git a/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml.cs b/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml.cs index 1a607342f3..decd849adc 100644 --- a/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml.cs +++ b/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml.cs @@ -74,7 +74,7 @@ namespace ControlCatalog.Pages private void RepeaterClick(object sender, PointerPressedEventArgs e) { - var item = (e.Source as TextBlock)?.DataContext as string; + var item = (e.Source as TextBlock)?.DataContext as ItemsRepeaterPageViewModel.Item; ((ItemsRepeaterPageViewModel)DataContext).SelectedItem = item; } } diff --git a/samples/ControlCatalog/ViewModels/ItemsRepeaterPageViewModel.cs b/samples/ControlCatalog/ViewModels/ItemsRepeaterPageViewModel.cs index 25fd550520..bc2ce80714 100644 --- a/samples/ControlCatalog/ViewModels/ItemsRepeaterPageViewModel.cs +++ b/samples/ControlCatalog/ViewModels/ItemsRepeaterPageViewModel.cs @@ -1,4 +1,5 @@ -using System.Collections.ObjectModel; +using System; +using System.Collections.ObjectModel; using System.Linq; using ReactiveUI; @@ -10,18 +11,44 @@ namespace ControlCatalog.ViewModels public ItemsRepeaterPageViewModel() { - Items = new ObservableCollection( - Enumerable.Range(1, 100000).Select(i => $"Item {i.ToString()}")); + Items = new ObservableCollection( + Enumerable.Range(1, 100000).Select(i => new Item + { + Text = $"Item {i.ToString()}", + })); } - public ObservableCollection Items { get; } + public ObservableCollection Items { get; } - public string SelectedItem { get; set; } + public Item SelectedItem { get; set; } public void AddItem() { var index = SelectedItem != null ? Items.IndexOf(SelectedItem) : -1; - Items.Insert(index + 1, $"New Item {newItemIndex++}"); + Items.Insert(index + 1, new Item { Text = $"New Item {newItemIndex++}" }); + } + + public void RandomizeHeights() + { + var random = new Random(); + + foreach (var i in Items) + { + i.Height = random.Next(240) + 10; + } + } + + public class Item : ReactiveObject + { + private double _height = double.NaN; + + public string Text { get; set; } + + public double Height + { + get => _height; + set => this.RaiseAndSetIfChanged(ref _height, value); + } } } } From b317df99e779e81d3dccee25682742daabb65c6f Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 4 Oct 2019 01:20:25 +0200 Subject: [PATCH 16/20] Added failing test for #3041. --- .../LayoutManagerTests.cs | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/Avalonia.Layout.UnitTests/LayoutManagerTests.cs b/tests/Avalonia.Layout.UnitTests/LayoutManagerTests.cs index 4c288b2702..3f20c9a76a 100644 --- a/tests/Avalonia.Layout.UnitTests/LayoutManagerTests.cs +++ b/tests/Avalonia.Layout.UnitTests/LayoutManagerTests.cs @@ -341,5 +341,38 @@ namespace Avalonia.Layout.UnitTests //layoutmanager should process properly other visuals Assert.All(targets, c => Assert.True(c.Arranged)); } + + + [Fact] + public void LayoutManager_Should_Recover_From_Infinite_Loop_On_Measure() + { + // Test for issue #3041. + var control = new LayoutTestControl(); + var root = new LayoutTestRoot { Child = control }; + + root.LayoutManager.ExecuteInitialLayoutPass(root); + control.Measured = false; + + control.DoMeasureOverride = (l, s) => + { + control.InvalidateMeasure(); + return new Size(100, 100); + }; + + control.InvalidateMeasure(); + root.LayoutManager.ExecuteLayoutPass(); + + // This is the important part: running a second layout pass in which we exceed the maximum + // retries causes LayoutQueue.Info.Count to exceed _maxEnqueueCountPerLoop. + root.LayoutManager.ExecuteLayoutPass(); + + control.Measured = false; + control.DoMeasureOverride = null; + + root.LayoutManager.ExecuteLayoutPass(); + + Assert.True(control.Measured); + Assert.True(control.IsMeasureValid); + } } } From 9fd8fdb53473372a72c3c705b674596838605176 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 4 Oct 2019 01:22:57 +0200 Subject: [PATCH 17/20] Fix comparison in LayoutQueue. --- src/Avalonia.Layout/LayoutQueue.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Layout/LayoutQueue.cs b/src/Avalonia.Layout/LayoutQueue.cs index ce40fdde49..eb0e4bd9f3 100644 --- a/src/Avalonia.Layout/LayoutQueue.cs +++ b/src/Avalonia.Layout/LayoutQueue.cs @@ -60,7 +60,7 @@ namespace Avalonia.Layout public void EndLoop() { - var notfinalized = _loopQueueInfo.Where(v => v.Value.Count == _maxEnqueueCountPerLoop).ToArray(); + var notfinalized = _loopQueueInfo.Where(v => v.Value.Count >= _maxEnqueueCountPerLoop).ToArray(); _loopQueueInfo.Clear(); From 393bbcf882bb7818937b4b474b421f20e20bb89a Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 4 Oct 2019 01:27:00 +0200 Subject: [PATCH 18/20] Disable horizontal scrollbar on ItemsRepeaterPage. --- samples/ControlCatalog/MainView.xaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml index c99a6b117b..874560a294 100644 --- a/samples/ControlCatalog/MainView.xaml +++ b/samples/ControlCatalog/MainView.xaml @@ -34,7 +34,8 @@ + ScrollViewer.VerticalScrollBarVisibility="Disabled" + ScrollViewer.HorizontalScrollBarVisibility="Disabled"> From 76840f463e5d4f5da6e3f1bb5ca30414347e7b7c Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 4 Oct 2019 02:04:17 +0200 Subject: [PATCH 19/20] Don't hide Track during measure. It causes it to stop being laid out. Instead hide the child controls. --- src/Avalonia.Controls/Primitives/Track.cs | 24 +++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/Primitives/Track.cs b/src/Avalonia.Controls/Primitives/Track.cs index 0af8ac3415..a569808b35 100644 --- a/src/Avalonia.Controls/Primitives/Track.cs +++ b/src/Avalonia.Controls/Primitives/Track.cs @@ -342,7 +342,7 @@ namespace Avalonia.Controls.Primitives // hide the track and don't arrange the pieces if (notEnoughContentToScroll || thumbLongerThanTrack) { - IsVisible = false; + ShowChildren(false); ThumbCenterOffset = Double.NaN; Density = Double.NaN; decreaseButtonLength = 0.0; @@ -351,7 +351,7 @@ namespace Avalonia.Controls.Primitives } else { - IsVisible = true; + ShowChildren(true); } // Compute lengths of increase and decrease button @@ -413,5 +413,25 @@ namespace Avalonia.Controls.Primitives Minimum, Maximum); } + + private void ShowChildren(bool visible) + { + // WPF sets Visible = Hidden here but we don't have that, and setting IsVisible = false + // will cause us to stop being laid out. Instead show/hide the child controls. + if (Thumb != null) + { + Thumb.IsVisible = visible; + } + + if (IncreaseButton != null) + { + IncreaseButton.IsVisible = visible; + } + + if (DecreaseButton != null) + { + DecreaseButton.IsVisible = visible; + } + } } } From a95273902b2f975787f2b7d3d48516d305a31989 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sun, 6 Oct 2019 20:45:17 +0200 Subject: [PATCH 20/20] Queue caret update with correct priority. When trying to scroll the caret into view, if we need to wait for a layout first make sure that we queue the update with a lower priority then `Layout`. `Render` is the next lowest priority so use this. Fixes #3070 --- src/Avalonia.Controls/Presenters/TextPresenter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/Presenters/TextPresenter.cs b/src/Avalonia.Controls/Presenters/TextPresenter.cs index debbb81264..5931fec350 100644 --- a/src/Avalonia.Controls/Presenters/TextPresenter.cs +++ b/src/Avalonia.Controls/Presenters/TextPresenter.cs @@ -244,7 +244,7 @@ namespace Avalonia.Controls.Presenters var rect = FormattedText.HitTestTextPosition(caretIndex); this.BringIntoView(rect); }, - DispatcherPriority.Normal); + DispatcherPriority.Render); } } }