|
|
@@ -1,9 +1,12 @@
|
|
|
// 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.
|
|
|
|
|
|
+using System;
|
|
|
+using System.Collections;
|
|
|
using System.Collections.Generic;
|
|
|
using System.Collections.Specialized;
|
|
|
using Avalonia.Controls.Generators;
|
|
|
+using Avalonia.Controls.Primitives;
|
|
|
using Avalonia.Controls.Utils;
|
|
|
using Avalonia.Input;
|
|
|
|
|
|
@@ -12,8 +15,18 @@ namespace Avalonia.Controls.Presenters
|
|
|
/// <summary>
|
|
|
/// Displays items inside an <see cref="ItemsControl"/>.
|
|
|
/// </summary>
|
|
|
- public class ItemsPresenter : ItemsPresenterBase
|
|
|
+ public class ItemsPresenter : ItemsPresenterBase, IScrollable
|
|
|
{
|
|
|
+ /// <summary>
|
|
|
+ /// Defines the <see cref="VirtualizationMode"/> property.
|
|
|
+ /// </summary>
|
|
|
+ public static readonly StyledProperty<ItemVirtualizationMode> VirtualizationModeProperty =
|
|
|
+ AvaloniaProperty.Register<ItemsPresenter, ItemVirtualizationMode>(
|
|
|
+ nameof(VirtualizationMode),
|
|
|
+ defaultValue: ItemVirtualizationMode.Simple);
|
|
|
+
|
|
|
+ private VirtualizationInfo _virt;
|
|
|
+
|
|
|
/// <summary>
|
|
|
/// Initializes static members of the <see cref="ItemsPresenter"/> class.
|
|
|
/// </summary>
|
|
|
@@ -24,11 +37,72 @@ namespace Avalonia.Controls.Presenters
|
|
|
KeyboardNavigationMode.Once);
|
|
|
}
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// Gets or sets the virtualization mode for the items.
|
|
|
+ /// </summary>
|
|
|
+ public ItemVirtualizationMode VirtualizationMode
|
|
|
+ {
|
|
|
+ get { return GetValue(VirtualizationModeProperty); }
|
|
|
+ set { SetValue(VirtualizationModeProperty, value); }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <inheritdoc/>
|
|
|
+ bool IScrollable.IsLogicalScrollEnabled
|
|
|
+ {
|
|
|
+ get { return _virt != null && VirtualizationMode != ItemVirtualizationMode.None; }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <inheritdoc/>
|
|
|
+ Action IScrollable.InvalidateScroll { get; set; }
|
|
|
+
|
|
|
+ Size IScrollable.Extent
|
|
|
+ {
|
|
|
+ get
|
|
|
+ {
|
|
|
+ switch (VirtualizationMode)
|
|
|
+ {
|
|
|
+ case ItemVirtualizationMode.Simple:
|
|
|
+ return new Size(0, Items?.Count() ?? 0);
|
|
|
+ default:
|
|
|
+ return default(Size);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Vector IScrollable.Offset { get; set; }
|
|
|
+
|
|
|
+ Size IScrollable.Viewport
|
|
|
+ {
|
|
|
+ get
|
|
|
+ {
|
|
|
+ throw new NotImplementedException();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Size IScrollable.ScrollSize
|
|
|
+ {
|
|
|
+ get
|
|
|
+ {
|
|
|
+ throw new NotImplementedException();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Size IScrollable.PageScrollSize
|
|
|
+ {
|
|
|
+ get
|
|
|
+ {
|
|
|
+ throw new NotImplementedException();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/// <inheritdoc/>
|
|
|
protected override void CreatePanel()
|
|
|
{
|
|
|
base.CreatePanel();
|
|
|
|
|
|
+ var virtualizingPanel = Panel as IVirtualizingPanel;
|
|
|
+ _virt = virtualizingPanel != null ? new VirtualizationInfo(virtualizingPanel) : null;
|
|
|
+
|
|
|
if (!Panel.IsSet(KeyboardNavigation.DirectionalNavigationProperty))
|
|
|
{
|
|
|
KeyboardNavigation.SetDirectionalNavigation(
|
|
|
@@ -55,7 +129,7 @@ namespace Avalonia.Controls.Presenters
|
|
|
generator.InsertSpace(e.NewStartingIndex, e.NewItems.Count);
|
|
|
}
|
|
|
|
|
|
- AddContainers(generator.Materialize(e.NewStartingIndex, e.NewItems, MemberSelector));
|
|
|
+ AddContainers(e.NewStartingIndex, e.NewItems);
|
|
|
break;
|
|
|
|
|
|
case NotifyCollectionChangedAction.Remove:
|
|
|
@@ -64,8 +138,7 @@ namespace Avalonia.Controls.Presenters
|
|
|
|
|
|
case NotifyCollectionChangedAction.Replace:
|
|
|
RemoveContainers(generator.Dematerialize(e.OldStartingIndex, e.OldItems.Count));
|
|
|
- var containers = generator.Materialize(e.NewStartingIndex, e.NewItems, MemberSelector);
|
|
|
- AddContainers(containers);
|
|
|
+ var containers = AddContainers(e.NewStartingIndex, e.NewItems);
|
|
|
|
|
|
var i = e.NewStartingIndex;
|
|
|
|
|
|
@@ -83,7 +156,7 @@ namespace Avalonia.Controls.Presenters
|
|
|
|
|
|
if (Items != null)
|
|
|
{
|
|
|
- AddContainers(generator.Materialize(0, Items, MemberSelector));
|
|
|
+ AddContainers(0, Items);
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
@@ -92,17 +165,20 @@ namespace Avalonia.Controls.Presenters
|
|
|
InvalidateMeasure();
|
|
|
}
|
|
|
|
|
|
- private void AddContainersToPanel(IEnumerable<ItemContainer> items)
|
|
|
+ private IList<ItemContainerInfo> AddContainers(int index, IEnumerable items)
|
|
|
{
|
|
|
- foreach (var i in items)
|
|
|
+ var generator = ItemContainerGenerator;
|
|
|
+ var result = new List<ItemContainerInfo>();
|
|
|
+
|
|
|
+ foreach (var item in items)
|
|
|
{
|
|
|
+ var i = generator.Materialize(index++, item, MemberSelector);
|
|
|
+
|
|
|
if (i.ContainerControl != null)
|
|
|
{
|
|
|
if (i.Index < this.Panel.Children.Count)
|
|
|
{
|
|
|
- // HACK: This will insert at the wrong place when there are null items,
|
|
|
- // but all of this will need to be rewritten when we implement
|
|
|
- // virtualization so hope no-one notices until then :)
|
|
|
+ // TODO: This will insert at the wrong place when there are null items.
|
|
|
this.Panel.Children.Insert(i.Index, i.ContainerControl);
|
|
|
}
|
|
|
else
|
|
|
@@ -110,39 +186,34 @@ namespace Avalonia.Controls.Presenters
|
|
|
this.Panel.Children.Add(i.ContainerControl);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ result.Add(i);
|
|
|
}
|
|
|
+
|
|
|
+ return result;
|
|
|
}
|
|
|
|
|
|
- private void AddContainers(IEnumerable<ItemContainer> items)
|
|
|
+ private void RemoveContainers(IEnumerable<ItemContainerInfo> items)
|
|
|
{
|
|
|
foreach (var i in items)
|
|
|
{
|
|
|
if (i.ContainerControl != null)
|
|
|
{
|
|
|
- if (i.Index < this.Panel.Children.Count)
|
|
|
- {
|
|
|
- // HACK: This will insert at the wrong place when there are null items,
|
|
|
- // but all of this will need to be rewritten when we implement
|
|
|
- // virtualization so hope no-one notices until then :)
|
|
|
- this.Panel.Children.Insert(i.Index, i.ContainerControl);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- this.Panel.Children.Add(i.ContainerControl);
|
|
|
- }
|
|
|
+ this.Panel.Children.Remove(i.ContainerControl);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private void RemoveContainers(IEnumerable<ItemContainer> items)
|
|
|
+ private class VirtualizationInfo
|
|
|
{
|
|
|
- foreach (var i in items)
|
|
|
+ public VirtualizationInfo(IVirtualizingPanel panel)
|
|
|
{
|
|
|
- if (i.ContainerControl != null)
|
|
|
- {
|
|
|
- this.Panel.Children.Remove(i.ContainerControl);
|
|
|
- }
|
|
|
+ Panel = panel;
|
|
|
}
|
|
|
+
|
|
|
+ public IVirtualizingPanel Panel { get; }
|
|
|
+ public int FirstIndex { get; set; }
|
|
|
+ public int LastIndex { get; set; }
|
|
|
}
|
|
|
}
|
|
|
}
|