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.
148 lines
4.0 KiB
148 lines
4.0 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 Avalonia.Controls.Primitives;
|
|
using System;
|
|
using System.Collections.Specialized;
|
|
|
|
namespace Avalonia.Controls
|
|
{
|
|
public class VirtualizingStackPanel : StackPanel, IScrollable, IVirtualizingPanel
|
|
{
|
|
private double _takenSpace;
|
|
private int _canBeRemoved;
|
|
|
|
bool IVirtualizingPanel.IsFull
|
|
{
|
|
get
|
|
{
|
|
return Orientation == Orientation.Horizontal ?
|
|
_takenSpace >= Bounds.Width :
|
|
_takenSpace >= Bounds.Height;
|
|
}
|
|
}
|
|
|
|
int IVirtualizingPanel.OverflowCount => _canBeRemoved;
|
|
|
|
Action IVirtualizingPanel.ArrangeCompleted { get; set; }
|
|
|
|
Action IScrollable.InvalidateScroll
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
Size IScrollable.Extent => new Size(_takenSpace, _takenSpace);
|
|
|
|
Vector IScrollable.Offset
|
|
{
|
|
get { return default(Vector); }
|
|
set { }
|
|
}
|
|
|
|
Size IScrollable.Viewport => Bounds.Size;
|
|
|
|
Size IScrollable.ScrollSize => new Size(1, 1);
|
|
|
|
Size IScrollable.PageScrollSize => new Size(1, 1);
|
|
|
|
protected override Size ArrangeOverride(Size finalSize)
|
|
{
|
|
_canBeRemoved = 0;
|
|
_takenSpace = 0;
|
|
var result = base.ArrangeOverride(finalSize);
|
|
((IVirtualizingPanel)this).ArrangeCompleted?.Invoke();
|
|
return result;
|
|
}
|
|
|
|
protected override void ChildrenChanged(object sender, NotifyCollectionChangedEventArgs e)
|
|
{
|
|
base.ChildrenChanged(sender, e);
|
|
|
|
switch (e.Action)
|
|
{
|
|
case NotifyCollectionChangedAction.Add:
|
|
foreach (IControl control in e.NewItems)
|
|
{
|
|
UpdatePhysicalSizeForAdd(control);
|
|
}
|
|
|
|
break;
|
|
|
|
case NotifyCollectionChangedAction.Remove:
|
|
foreach (IControl control in e.OldItems)
|
|
{
|
|
UpdatePhysicalSizeForRemove(control);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
internal override void ArrangeChild(
|
|
IControl child,
|
|
Rect rect,
|
|
Size panelSize,
|
|
Orientation orientation)
|
|
{
|
|
base.ArrangeChild(child, rect, panelSize, orientation);
|
|
|
|
if (orientation == Orientation.Horizontal)
|
|
{
|
|
if (rect.X >= panelSize.Width)
|
|
{
|
|
++_canBeRemoved;
|
|
}
|
|
|
|
if (rect.Right >= _takenSpace)
|
|
{
|
|
_takenSpace = rect.Right;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (rect.Y >= panelSize.Height)
|
|
{
|
|
++_canBeRemoved;
|
|
}
|
|
|
|
if (rect.Bottom >= _takenSpace)
|
|
{
|
|
_takenSpace = rect.Bottom;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void UpdatePhysicalSizeForAdd(IControl child)
|
|
{
|
|
var bounds = Bounds;
|
|
var gap = Gap;
|
|
|
|
child.Measure(bounds.Size);
|
|
|
|
if (Orientation == Orientation.Vertical)
|
|
{
|
|
_takenSpace += child.DesiredSize.Height + gap;
|
|
}
|
|
else
|
|
{
|
|
_takenSpace += child.DesiredSize.Width + gap;
|
|
}
|
|
}
|
|
|
|
private void UpdatePhysicalSizeForRemove(IControl child)
|
|
{
|
|
var bounds = Bounds;
|
|
var gap = Gap;
|
|
|
|
if (Orientation == Orientation.Vertical)
|
|
{
|
|
_takenSpace -= child.DesiredSize.Height + gap;
|
|
}
|
|
else
|
|
{
|
|
_takenSpace -= child.DesiredSize.Width + gap;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|