diff --git a/samples/VirtualizationDemo/MainWindow.xaml b/samples/VirtualizationDemo/MainWindow.xaml
index 58970eff01..12137cd03d 100644
--- a/samples/VirtualizationDemo/MainWindow.xaml
+++ b/samples/VirtualizationDemo/MainWindow.xaml
@@ -39,6 +39,8 @@
+
+
-
+
diff --git a/samples/VirtualizationDemo/ViewModels/ItemViewModel.cs b/samples/VirtualizationDemo/ViewModels/ItemViewModel.cs
index e883cdfeb9..4401a2dfeb 100644
--- a/samples/VirtualizationDemo/ViewModels/ItemViewModel.cs
+++ b/samples/VirtualizationDemo/ViewModels/ItemViewModel.cs
@@ -10,6 +10,7 @@ namespace VirtualizationDemo.ViewModels
{
private string _prefix;
private int _index;
+ private double _height = double.NaN;
public ItemViewModel(int index, string prefix = "Item")
{
@@ -18,5 +19,11 @@ namespace VirtualizationDemo.ViewModels
}
public string Header => $"{_prefix} {_index}";
+
+ public double Height
+ {
+ get => _height;
+ set => this.RaiseAndSetIfChanged(ref _height, value);
+ }
}
}
diff --git a/samples/VirtualizationDemo/ViewModels/MainWindowViewModel.cs b/samples/VirtualizationDemo/ViewModels/MainWindowViewModel.cs
index eba17f92e4..80e0fb2586 100644
--- a/samples/VirtualizationDemo/ViewModels/MainWindowViewModel.cs
+++ b/samples/VirtualizationDemo/ViewModels/MainWindowViewModel.cs
@@ -98,6 +98,24 @@ namespace VirtualizationDemo.ViewModels
public ReactiveCommand SelectFirstCommand { get; private set; }
public ReactiveCommand SelectLastCommand { get; private set; }
+ public void RandomizeSize()
+ {
+ var random = new Random();
+
+ foreach (var i in Items)
+ {
+ i.Height = random.Next(240) + 10;
+ }
+ }
+
+ public void ResetSize()
+ {
+ foreach (var i in Items)
+ {
+ i.Height = double.NaN;
+ }
+ }
+
private void ResizeItems(int count)
{
if (Items == null)
diff --git a/src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs b/src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs
index f72a65ead2..d11ce9a7ea 100644
--- a/src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs
+++ b/src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs
@@ -20,6 +20,8 @@ namespace Avalonia.Controls.Presenters
///
internal class ItemVirtualizerSimple : ItemVirtualizer
{
+ private int _anchor;
+
///
/// Initializes a new instance of the class.
///
@@ -362,7 +364,10 @@ namespace Avalonia.Controls.Presenters
if (panel.OverflowCount > 0)
{
- RemoveContainers(panel.OverflowCount);
+ if (_anchor <= FirstIndex)
+ {
+ RemoveContainers(panel.OverflowCount);
+ }
}
}
@@ -540,7 +545,9 @@ namespace Avalonia.Controls.Presenters
// it means we're running a unit test.
if (container != null && layoutManager != null)
{
+ _anchor = index;
layoutManager.ExecuteLayoutPass();
+ _anchor = -1;
if (newOffset != -1 && newOffset != OffsetValue)
{
diff --git a/src/Avalonia.Controls/Primitives/RangeBase.cs b/src/Avalonia.Controls/Primitives/RangeBase.cs
index 76df94cdb8..ae175734b9 100644
--- a/src/Avalonia.Controls/Primitives/RangeBase.cs
+++ b/src/Avalonia.Controls/Primitives/RangeBase.cs
@@ -44,13 +44,13 @@ namespace Avalonia.Controls.Primitives
/// Defines the property.
///
public static readonly StyledProperty SmallChangeProperty =
- AvaloniaProperty.Register(nameof(SmallChange), 0.1);
+ AvaloniaProperty.Register(nameof(SmallChange), 1);
///
/// Defines the property.
///
public static readonly StyledProperty LargeChangeProperty =
- AvaloniaProperty.Register(nameof(LargeChange), 1);
+ AvaloniaProperty.Register(nameof(LargeChange), 10);
private double _minimum;
private double _maximum = 100.0;
diff --git a/src/Avalonia.Controls/Primitives/ScrollBar.cs b/src/Avalonia.Controls/Primitives/ScrollBar.cs
index f0d8c81808..e1b3061b54 100644
--- a/src/Avalonia.Controls/Primitives/ScrollBar.cs
+++ b/src/Avalonia.Controls/Primitives/ScrollBar.cs
@@ -216,25 +216,25 @@ namespace Avalonia.Controls.Primitives
private void SmallDecrement()
{
- Value = Math.Max(Value - SmallChange * ViewportSize, Minimum);
+ Value = Math.Max(Value - SmallChange, Minimum);
OnScroll(ScrollEventType.SmallDecrement);
}
private void SmallIncrement()
{
- Value = Math.Min(Value + SmallChange * ViewportSize, Maximum);
+ Value = Math.Min(Value + SmallChange, Maximum);
OnScroll(ScrollEventType.SmallIncrement);
}
private void LargeDecrement()
{
- Value = Math.Max(Value - LargeChange * ViewportSize, Minimum);
+ Value = Math.Max(Value - LargeChange, Minimum);
OnScroll(ScrollEventType.LargeDecrement);
}
private void LargeIncrement()
{
- Value = Math.Min(Value + LargeChange * ViewportSize, Maximum);
+ Value = Math.Min(Value + LargeChange, Maximum);
OnScroll(ScrollEventType.LargeIncrement);
}
diff --git a/src/Avalonia.Controls/Slider.cs b/src/Avalonia.Controls/Slider.cs
index 260c708515..bc4733296b 100644
--- a/src/Avalonia.Controls/Slider.cs
+++ b/src/Avalonia.Controls/Slider.cs
@@ -47,8 +47,6 @@ namespace Avalonia.Controls
Thumb.DragStartedEvent.AddClassHandler(x => x.OnThumbDragStarted, RoutingStrategies.Bubble);
Thumb.DragDeltaEvent.AddClassHandler(x => x.OnThumbDragDelta, RoutingStrategies.Bubble);
Thumb.DragCompletedEvent.AddClassHandler(x => x.OnThumbDragCompleted, RoutingStrategies.Bubble);
- SmallChangeProperty.OverrideDefaultValue(1);
- LargeChangeProperty.OverrideDefaultValue(10);
}
///
diff --git a/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization_Simple.cs b/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization_Simple.cs
index 9921a8de6c..97d57e9eb6 100644
--- a/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization_Simple.cs
+++ b/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization_Simple.cs
@@ -15,6 +15,7 @@ using Avalonia.Input;
using Avalonia.Layout;
using Avalonia.Platform;
using Avalonia.Rendering;
+using Avalonia.Styling;
using Avalonia.UnitTests;
using Xunit;
@@ -756,6 +757,80 @@ namespace Avalonia.Controls.UnitTests.Presenters
Assert.Same(target.Panel.Children[9].DataContext, last);
}
+ [Fact]
+ public void Scrolling_Less_Than_A_Page_Should_Move_Recycled_Items()
+ {
+ var target = CreateTarget();
+ var items = (IList)target.Items;
+
+ target.ApplyTemplate();
+ target.Measure(new Size(100, 100));
+ target.Arrange(new Rect(0, 0, 100, 100));
+
+ var containers = target.Panel.Children.ToList();
+ var scroller = (ScrollContentPresenter)target.Parent;
+
+ scroller.Offset = new Vector(0, 5);
+
+ var scrolledContainers = containers
+ .Skip(5)
+ .Take(5)
+ .Concat(containers.Take(5)).ToList();
+
+ Assert.Equal(new Vector(0, 5), ((ILogicalScrollable)target).Offset);
+ Assert.Equal(scrolledContainers, target.Panel.Children);
+
+ for (var i = 0; i < target.Panel.Children.Count; ++i)
+ {
+ Assert.Equal(items[i + 5], target.Panel.Children[i].DataContext);
+ }
+
+ scroller.Offset = new Vector(0, 0);
+ Assert.Equal(new Vector(0, 0), ((ILogicalScrollable)target).Offset);
+ Assert.Equal(containers, target.Panel.Children);
+
+ var dcs = target.Panel.Children.Select(x => x.DataContext).ToList();
+
+ for (var i = 0; i < target.Panel.Children.Count; ++i)
+ {
+ Assert.Equal(items[i], target.Panel.Children[i].DataContext);
+ }
+ }
+
+ [Fact]
+ public void Scrolling_More_Than_A_Page_Should_Recycle_Items()
+ {
+ var target = CreateTarget(itemCount: 50);
+ var items = (IList)target.Items;
+
+ target.ApplyTemplate();
+ target.Measure(new Size(100, 100));
+ target.Arrange(new Rect(0, 0, 100, 100));
+
+ var containers = target.Panel.Children.ToList();
+ var scroller = (ScrollContentPresenter)target.Parent;
+
+ scroller.Offset = new Vector(0, 20);
+
+ Assert.Equal(new Vector(0, 20), ((ILogicalScrollable)target).Offset);
+ Assert.Equal(containers, target.Panel.Children);
+
+ for (var i = 0; i < target.Panel.Children.Count; ++i)
+ {
+ Assert.Equal(items[i + 20], target.Panel.Children[i].DataContext);
+ }
+
+ scroller.Offset = new Vector(0, 0);
+
+ Assert.Equal(new Vector(0, 0), ((ILogicalScrollable)target).Offset);
+ Assert.Equal(containers, target.Panel.Children);
+
+ for (var i = 0; i < target.Panel.Children.Count; ++i)
+ {
+ Assert.Equal(items[i], target.Panel.Children[i].DataContext);
+ }
+ }
+
public class Vertical
{
[Fact]
@@ -941,86 +1016,8 @@ namespace Avalonia.Controls.UnitTests.Presenters
}
}
- public class WithContainers
- {
- [Fact]
- public void Scrolling_Less_Than_A_Page_Should_Move_Recycled_Items()
- {
- var target = CreateTarget();
- var items = (IList)target.Items;
-
- target.ApplyTemplate();
- target.Measure(new Size(100, 100));
- target.Arrange(new Rect(0, 0, 100, 100));
-
- var containers = target.Panel.Children.ToList();
- var scroller = (ScrollContentPresenter)target.Parent;
-
- scroller.Offset = new Vector(0, 5);
-
- var scrolledContainers = containers
- .Skip(5)
- .Take(5)
- .Concat(containers.Take(5)).ToList();
-
- Assert.Equal(new Vector(0, 5), ((ILogicalScrollable)target).Offset);
- Assert.Equal(scrolledContainers, target.Panel.Children);
-
- for (var i = 0; i < target.Panel.Children.Count; ++i)
- {
- Assert.Equal(items[i + 5], target.Panel.Children[i].DataContext);
- }
-
- scroller.Offset = new Vector(0, 0);
- Assert.Equal(new Vector(0, 0), ((ILogicalScrollable)target).Offset);
- Assert.Equal(containers, target.Panel.Children);
-
- var dcs = target.Panel.Children.Select(x => x.DataContext).ToList();
-
- for (var i = 0; i < target.Panel.Children.Count; ++i)
- {
- Assert.Equal(items[i], target.Panel.Children[i].DataContext);
- }
- }
-
- [Fact]
- public void Scrolling_More_Than_A_Page_Should_Recycle_Items()
- {
- var target = CreateTarget(itemCount: 50);
- var items = (IList)target.Items;
-
- target.ApplyTemplate();
- target.Measure(new Size(100, 100));
- target.Arrange(new Rect(0, 0, 100, 100));
-
- var containers = target.Panel.Children.ToList();
- var scroller = (ScrollContentPresenter)target.Parent;
-
- scroller.Offset = new Vector(0, 20);
-
- Assert.Equal(new Vector(0, 20), ((ILogicalScrollable)target).Offset);
- Assert.Equal(containers, target.Panel.Children);
-
- for (var i = 0; i < target.Panel.Children.Count; ++i)
- {
- Assert.Equal(items[i + 20], target.Panel.Children[i].DataContext);
- }
-
- scroller.Offset = new Vector(0, 0);
-
- Assert.Equal(new Vector(0, 0), ((ILogicalScrollable)target).Offset);
- Assert.Equal(containers, target.Panel.Children);
-
- for (var i = 0; i < target.Panel.Children.Count; ++i)
- {
- Assert.Equal(items[i], target.Panel.Children[i].DataContext);
- }
- }
- }
-
private static ItemsPresenter CreateTarget(
Orientation orientation = Orientation.Vertical,
- bool useContainers = true,
int itemCount = 20,
bool useAvaloniaList = false)
{
@@ -1034,11 +1031,11 @@ namespace Avalonia.Controls.UnitTests.Presenters
{
CanHorizontallyScroll = true,
CanVerticallyScroll = true,
- Content = result = new TestItemsPresenter(useContainers)
+ Content = result = new TestItemsPresenter
{
Items = items,
ItemsPanel = VirtualizingPanelTemplate(orientation),
- ItemTemplate = ItemTemplate(),
+ DataTemplates = { StringDataTemplate() },
VirtualizationMode = ItemVirtualizationMode.Simple,
}
};
@@ -1047,7 +1044,7 @@ namespace Avalonia.Controls.UnitTests.Presenters
return result;
}
- private static IDataTemplate ItemTemplate()
+ private static IDataTemplate StringDataTemplate()
{
return new FuncDataTemplate(x => new Canvas
{
@@ -1065,7 +1062,7 @@ namespace Avalonia.Controls.UnitTests.Presenters
});
}
- private class TestScroller : ScrollContentPresenter, IRenderRoot, ILayoutRoot
+ private class TestScroller : ScrollContentPresenter, IRenderRoot, ILayoutRoot, IStyleRoot
{
public IRenderer Renderer { get; }
public Size ClientSize { get; }
@@ -1085,18 +1082,12 @@ namespace Avalonia.Controls.UnitTests.Presenters
private class TestItemsPresenter : ItemsPresenter
{
- private bool _useContainers;
-
- public TestItemsPresenter(bool useContainers)
- {
- _useContainers = useContainers;
- }
-
protected override IItemContainerGenerator CreateItemContainerGenerator()
{
- return _useContainers ?
- new ItemContainerGenerator(this, TestContainer.ContentProperty, null) :
- new ItemContainerGenerator(this);
+ return new ItemContainerGenerator(
+ this,
+ TestContainer.ContentProperty,
+ null);
}
}
@@ -1104,8 +1095,12 @@ namespace Avalonia.Controls.UnitTests.Presenters
{
public TestContainer()
{
- Width = 10;
- Height = 10;
+ Template = new FuncControlTemplate(parent => new ContentPresenter
+ {
+ Name = "PART_ContentPresenter",
+ [~ContentPresenter.ContentProperty] = parent[~ContentControl.ContentProperty],
+ [~ContentPresenter.ContentTemplateProperty] = parent[~ContentControl.ContentTemplateProperty],
+ });
}
}
}