Browse Source
Merge pull request #1962 from donandren/issues/1395
unit test for Listbox OutOfRangeException issue #1395
fixes/publish-avalonia-native-osx-package-seperately
Steven Kirk
8 years ago
committed by
GitHub
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with
79 additions and
4 deletions
-
src/Avalonia.Base/Utilities/MathUtilities.cs
-
src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs
-
tests/Avalonia.Controls.UnitTests/ListBoxTests.cs
|
|
|
@ -1,7 +1,6 @@ |
|
|
|
// 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.
|
|
|
|
|
|
|
|
|
|
|
|
namespace Avalonia.Utilities |
|
|
|
{ |
|
|
|
/// <summary>
|
|
|
|
@ -31,5 +30,28 @@ namespace Avalonia.Utilities |
|
|
|
return val; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Clamps a value between a minimum and maximum value.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="val">The value.</param>
|
|
|
|
/// <param name="min">The minimum value.</param>
|
|
|
|
/// <param name="max">The maximum value.</param>
|
|
|
|
/// <returns>The clamped value.</returns>
|
|
|
|
public static int Clamp(int val, int min, int max) |
|
|
|
{ |
|
|
|
if (val < min) |
|
|
|
{ |
|
|
|
return min; |
|
|
|
} |
|
|
|
else if (val > max) |
|
|
|
{ |
|
|
|
return max; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
return val; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -76,9 +76,23 @@ namespace Avalonia.Controls.Presenters |
|
|
|
var firstIndex = ItemCount - panel.Children.Count; |
|
|
|
RecycleContainersForMove(firstIndex - FirstIndex); |
|
|
|
|
|
|
|
panel.PixelOffset = VirtualizingPanel.ScrollDirection == Orientation.Vertical ? |
|
|
|
panel.Children[0].Bounds.Height : |
|
|
|
panel.Children[0].Bounds.Width; |
|
|
|
double pixelOffset; |
|
|
|
var child = panel.Children[0]; |
|
|
|
|
|
|
|
if (child.IsArrangeValid) |
|
|
|
{ |
|
|
|
pixelOffset = VirtualizingPanel.ScrollDirection == Orientation.Vertical ? |
|
|
|
child.Bounds.Height : |
|
|
|
child.Bounds.Width; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
pixelOffset = VirtualizingPanel.ScrollDirection == Orientation.Vertical ? |
|
|
|
child.DesiredSize.Height : |
|
|
|
child.DesiredSize.Width; |
|
|
|
} |
|
|
|
|
|
|
|
panel.PixelOffset = pixelOffset; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -402,6 +416,10 @@ namespace Avalonia.Controls.Presenters |
|
|
|
var panel = VirtualizingPanel; |
|
|
|
var generator = Owner.ItemContainerGenerator; |
|
|
|
var selector = Owner.MemberSelector; |
|
|
|
|
|
|
|
//validate delta it should never overflow last index or generate index < 0
|
|
|
|
delta = MathUtilities.Clamp(delta, -FirstIndex, ItemCount - FirstIndex - panel.Children.Count); |
|
|
|
|
|
|
|
var sign = delta < 0 ? -1 : 1; |
|
|
|
var count = Math.Min(Math.Abs(delta), panel.Children.Count); |
|
|
|
var move = count < panel.Children.Count; |
|
|
|
|
|
|
|
@ -196,6 +196,41 @@ namespace Avalonia.Controls.UnitTests |
|
|
|
target.Presenter.Panel.Children.Cast<ListBoxItem>().Select(x => (string)x.Content)); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
[Fact] |
|
|
|
public void ListBox_After_Scroll_IndexOutOfRangeException_Shouldnt_Be_Thrown() |
|
|
|
{ |
|
|
|
var items = Enumerable.Range(0, 11).Select(x => $"{x}").ToArray(); |
|
|
|
|
|
|
|
var target = new ListBox |
|
|
|
{ |
|
|
|
Template = ListBoxTemplate(), |
|
|
|
Items = items, |
|
|
|
ItemTemplate = new FuncDataTemplate<string>(x => new TextBlock { Height = 11 }) |
|
|
|
}; |
|
|
|
|
|
|
|
Prepare(target); |
|
|
|
|
|
|
|
var panel = target.Presenter.Panel as IVirtualizingPanel; |
|
|
|
|
|
|
|
var listBoxItems = panel.Children.OfType<ListBoxItem>(); |
|
|
|
|
|
|
|
//virtualization should have created exactly 10 items
|
|
|
|
Assert.Equal(10, listBoxItems.Count()); |
|
|
|
Assert.Equal("0", listBoxItems.First().DataContext); |
|
|
|
Assert.Equal("9", listBoxItems.Last().DataContext); |
|
|
|
|
|
|
|
//instead pixeloffset > 0 there could be pretty complex sequence for repro
|
|
|
|
//it involves add/remove/scroll to end multiple actions
|
|
|
|
//which i can't find so far :(, but this is the simplest way to add it to unit test
|
|
|
|
panel.PixelOffset = 1; |
|
|
|
|
|
|
|
//here scroll to end -> IndexOutOfRangeException is thrown
|
|
|
|
target.Scroll.Offset = new Vector(0, 2); |
|
|
|
|
|
|
|
Assert.True(true); |
|
|
|
} |
|
|
|
|
|
|
|
private FuncControlTemplate ListBoxTemplate() |
|
|
|
{ |
|
|
|
return new FuncControlTemplate<ListBox>(parent => |
|
|
|
|