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
parent
commit
06659ae445
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 24
      src/Avalonia.Base/Utilities/MathUtilities.cs
  2. 24
      src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs
  3. 35
      tests/Avalonia.Controls.UnitTests/ListBoxTests.cs

24
src/Avalonia.Base/Utilities/MathUtilities.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;
}
}
}
}

24
src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs

@ -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;

35
tests/Avalonia.Controls.UnitTests/ListBoxTests.cs

@ -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 =>

Loading…
Cancel
Save