csharpc-sharpdotnetxamlavaloniauicross-platformcross-platform-xamlavaloniaguimulti-platformuser-interfacedotnetcore
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
152 lines
5.2 KiB
152 lines
5.2 KiB
// 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.Specialized;
|
|
using Avalonia.Controls.Primitives;
|
|
using Avalonia.Input;
|
|
using static Avalonia.Utilities.MathUtilities;
|
|
|
|
namespace Avalonia.Controls.Presenters
|
|
{
|
|
/// <summary>
|
|
/// Displays items inside an <see cref="ItemsControl"/>.
|
|
/// </summary>
|
|
public class ItemsPresenter : ItemsPresenterBase, ILogicalScrollable
|
|
{
|
|
/// <summary>
|
|
/// Defines the <see cref="VirtualizationMode"/> property.
|
|
/// </summary>
|
|
public static readonly StyledProperty<ItemVirtualizationMode> VirtualizationModeProperty =
|
|
AvaloniaProperty.Register<ItemsPresenter, ItemVirtualizationMode>(
|
|
nameof(VirtualizationMode),
|
|
defaultValue: ItemVirtualizationMode.None);
|
|
|
|
private ItemVirtualizer _virtualizer;
|
|
|
|
/// <summary>
|
|
/// Initializes static members of the <see cref="ItemsPresenter"/> class.
|
|
/// </summary>
|
|
static ItemsPresenter()
|
|
{
|
|
KeyboardNavigation.TabNavigationProperty.OverrideDefaultValue(
|
|
typeof(ItemsPresenter),
|
|
KeyboardNavigationMode.Once);
|
|
|
|
VirtualizationModeProperty.Changed
|
|
.AddClassHandler<ItemsPresenter>(x => x.VirtualizationModeChanged);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the virtualization mode for the items.
|
|
/// </summary>
|
|
public ItemVirtualizationMode VirtualizationMode
|
|
{
|
|
get { return GetValue(VirtualizationModeProperty); }
|
|
set { SetValue(VirtualizationModeProperty, value); }
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
bool ILogicalScrollable.IsLogicalScrollEnabled
|
|
{
|
|
get { return _virtualizer?.IsLogicalScrollEnabled ?? false; }
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
Size IScrollable.Extent => _virtualizer.Extent;
|
|
|
|
/// <inheritdoc/>
|
|
Vector IScrollable.Offset
|
|
{
|
|
get { return _virtualizer.Offset; }
|
|
set { _virtualizer.Offset = CoerceOffset(value); }
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
Size IScrollable.Viewport => _virtualizer.Viewport;
|
|
|
|
/// <inheritdoc/>
|
|
Action ILogicalScrollable.InvalidateScroll { get; set; }
|
|
|
|
/// <inheritdoc/>
|
|
Size ILogicalScrollable.ScrollSize => new Size(1, 1);
|
|
|
|
/// <inheritdoc/>
|
|
Size ILogicalScrollable.PageScrollSize => new Size(0, 1);
|
|
|
|
/// <inheritdoc/>
|
|
bool ILogicalScrollable.BringIntoView(IControl target, Rect targetRect)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
IControl ILogicalScrollable.GetControlInDirection(NavigationDirection direction, IControl from)
|
|
{
|
|
return _virtualizer?.GetControlInDirection(direction, from);
|
|
}
|
|
|
|
public override void ScrollIntoView(object item)
|
|
{
|
|
_virtualizer?.ScrollIntoView(item);
|
|
}
|
|
|
|
protected override Size MeasureOverride(Size availableSize)
|
|
{
|
|
// If infinity is passed as the available size and we're virtualized then we need to
|
|
// fill the available space, but to do that we *don't* want to materialize all our
|
|
// items! Take a look at the root of the tree for a MaxClientSize and use that as
|
|
// the available size.
|
|
if (availableSize == Size.Infinity && VirtualizationMode != ItemVirtualizationMode.None)
|
|
{
|
|
var window = VisualRoot as TopLevel;
|
|
|
|
if (window != null)
|
|
{
|
|
availableSize = window.PlatformImpl.MaxClientSize;
|
|
}
|
|
}
|
|
|
|
Panel.Measure(availableSize);
|
|
return Panel.DesiredSize;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override void PanelCreated(IPanel panel)
|
|
{
|
|
_virtualizer = ItemVirtualizer.Create(this);
|
|
((ILogicalScrollable)this).InvalidateScroll?.Invoke();
|
|
|
|
if (!Panel.IsSet(KeyboardNavigation.DirectionalNavigationProperty))
|
|
{
|
|
KeyboardNavigation.SetDirectionalNavigation(
|
|
(InputElement)Panel,
|
|
KeyboardNavigationMode.Contained);
|
|
}
|
|
|
|
KeyboardNavigation.SetTabNavigation(
|
|
(InputElement)Panel,
|
|
KeyboardNavigation.GetTabNavigation(this));
|
|
}
|
|
|
|
protected override void ItemsChanged(NotifyCollectionChangedEventArgs e)
|
|
{
|
|
_virtualizer?.ItemsChanged(Items, e);
|
|
}
|
|
|
|
private Vector CoerceOffset(Vector value)
|
|
{
|
|
var scrollable = (ILogicalScrollable)this;
|
|
var maxX = Math.Max(scrollable.Extent.Width - scrollable.Viewport.Width, 0);
|
|
var maxY = Math.Max(scrollable.Extent.Height - scrollable.Viewport.Height, 0);
|
|
return new Vector(Clamp(value.X, 0, maxX), Clamp(value.Y, 0, maxY));
|
|
}
|
|
|
|
private void VirtualizationModeChanged(AvaloniaPropertyChangedEventArgs e)
|
|
{
|
|
_virtualizer?.Dispose();
|
|
_virtualizer = ItemVirtualizer.Create(this);
|
|
((ILogicalScrollable)this).InvalidateScroll?.Invoke();
|
|
}
|
|
}
|
|
}
|