Browse Source

WIP

pull/554/head
Steven Kirk 10 years ago
parent
commit
b91d8781d8
  1. 11
      samples/XamlTestApplicationPcl/Views/MainWindow.cs
  2. 11
      samples/XamlTestApplicationPcl/Views/MainWindow.xaml
  3. 3
      src/Avalonia.Controls/Avalonia.Controls.csproj
  4. 13
      src/Avalonia.Controls/IVirtualizingPanel.cs
  5. 34
      src/Avalonia.Controls/Panel.cs
  6. 18
      src/Avalonia.Controls/StackPanel.cs
  7. 67
      src/Avalonia.Controls/Thingamybob.cs
  8. 148
      src/Avalonia.Controls/VirtualizingStackPanel.cs

11
samples/XamlTestApplicationPcl/Views/MainWindow.cs

@ -25,6 +25,17 @@ namespace XamlTestApplication.Views
AvaloniaXamlLoader.Load(this);
_exitMenu = this.FindControl<MenuItem>("exitMenu");
_exitMenu.Click += (s, e) => Application.Current.Exit();
var vadd = this.FindControl<Button>("vadd");
var vsp = this.FindControl<VirtualizingStackPanel>("vsp");
var ivp = (IVirtualizingPanel)vsp;
var index = 0;
vadd.Click += (s, e) =>
{
vsp.Children.Add(new TextBlock { Text = "Hello " + ++index });
vadd.IsEnabled = !ivp.IsFull;
};
}
}
}

11
samples/XamlTestApplicationPcl/Views/MainWindow.xaml

@ -24,6 +24,17 @@
<TabControl.Transition>
<PageSlide Duration="0.25" />
</TabControl.Transition>
<TabItem Header="Virtualization">
<DockPanel LastChildFill="True">
<StackPanel DockPanel.Dock="Right" Orientation="Vertical">
<Button Name="vadd">Add Item</Button>
</StackPanel>
<Thingamybob></Thingamybob>
</DockPanel>
</TabItem>
<TabItem Header="Buttons">
<ScrollViewer CanScrollHorizontally="False">
<StackPanel Margin="10" Gap="4">

3
src/Avalonia.Controls/Avalonia.Controls.csproj

@ -57,6 +57,7 @@
<Compile Include="INameScope.cs" />
<Compile Include="IPseudoClasses.cs" />
<Compile Include="DropDownItem.cs" />
<Compile Include="IVirtualizingPanel.cs" />
<Compile Include="LayoutTransformControl.cs" />
<Compile Include="Mixins\ContentControlMixin.cs" />
<Compile Include="NameScope.cs" />
@ -161,6 +162,7 @@
<Compile Include="Templates\ITemplate`1.cs" />
<Compile Include="Templates\ITreeDataTemplate.cs" />
<Compile Include="Templates\FuncTreeDataTemplate.cs" />
<Compile Include="Thingamybob.cs" />
<Compile Include="ToolTip.cs" />
<Compile Include="UserControl.cs" />
<Compile Include="Templates\TemplateExtensions.cs" />
@ -171,6 +173,7 @@
<Compile Include="TopLevel.cs" />
<Compile Include="Primitives\PopupRoot.cs" />
<Compile Include="Utils\UndoRedoHelper.cs" />
<Compile Include="VirtualizingStackPanel.cs" />
<Compile Include="WindowState.cs" />
<Compile Include="Window.cs" />
<Compile Include="RowDefinition.cs" />

13
src/Avalonia.Controls/IVirtualizingPanel.cs

@ -0,0 +1,13 @@
using System;
namespace Avalonia.Controls
{
public interface IVirtualizingPanel : IPanel
{
bool IsFull { get; }
int OverflowCount { get; }
Action ArrangeCompleted { get; set; }
}
}

34
src/Avalonia.Controls/Panel.cs

@ -79,12 +79,28 @@ namespace Avalonia.Controls
set { SetValue(BackgroundProperty, value); }
}
/// <summary>
/// Renders the visual to a <see cref="DrawingContext"/>.
/// </summary>
/// <param name="context">The drawing context.</param>
public override void Render(DrawingContext context)
{
var background = Background;
if (background != null)
{
var renderSize = Bounds.Size;
context.FillRectangle(background, new Rect(renderSize));
}
base.Render(context);
}
/// <summary>
/// Called when the <see cref="Children"/> collection changes.
/// </summary>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event args.</param>
private void ChildrenChanged(object sender, NotifyCollectionChangedEventArgs e)
protected virtual void ChildrenChanged(object sender, NotifyCollectionChangedEventArgs e)
{
List<Control> controls;
@ -122,21 +138,5 @@ namespace Avalonia.Controls
InvalidateMeasure();
}
/// <summary>
/// Renders the visual to a <see cref="DrawingContext"/>.
/// </summary>
/// <param name="context">The drawing context.</param>
public override void Render(DrawingContext context)
{
var background = Background;
if (background != null)
{
var renderSize = Bounds.Size;
context.FillRectangle(background, new Rect(renderSize));
}
base.Render(context);
}
}
}

18
src/Avalonia.Controls/StackPanel.cs

@ -181,6 +181,7 @@ namespace Avalonia.Controls
/// <returns>The space taken.</returns>
protected override Size ArrangeOverride(Size finalSize)
{
var orientation = Orientation;
double arrangedWidth = finalSize.Width;
double arrangedHeight = finalSize.Height;
double gap = Gap;
@ -199,11 +200,11 @@ namespace Avalonia.Controls
double childWidth = child.DesiredSize.Width;
double childHeight = child.DesiredSize.Height;
if (Orientation == Orientation.Vertical)
if (orientation == Orientation.Vertical)
{
double width = Math.Max(childWidth, arrangedWidth);
Rect childFinal = new Rect(0, arrangedHeight, width, childHeight);
child.Arrange(childFinal);
ArrangeChild(child, childFinal, finalSize, orientation);
arrangedWidth = Math.Max(arrangedWidth, childWidth);
arrangedHeight += childHeight + gap;
}
@ -211,13 +212,13 @@ namespace Avalonia.Controls
{
double height = Math.Max(childHeight, arrangedHeight);
Rect childFinal = new Rect(arrangedWidth, 0, childWidth, height);
child.Arrange(childFinal);
ArrangeChild(child, childFinal, finalSize, orientation);
arrangedWidth += childWidth + gap;
arrangedHeight = Math.Max(arrangedHeight, childHeight);
}
}
if (Orientation == Orientation.Vertical)
if (orientation == Orientation.Vertical)
{
arrangedHeight = Math.Max(arrangedHeight - gap, finalSize.Height);
}
@ -228,5 +229,14 @@ namespace Avalonia.Controls
return new Size(arrangedWidth, arrangedHeight);
}
internal virtual void ArrangeChild(
IControl child,
Rect rect,
Size panelSize,
Orientation orientation)
{
child.Arrange(rect);
}
}
}

67
src/Avalonia.Controls/Thingamybob.cs

@ -0,0 +1,67 @@
using Avalonia.Media;
using System;
namespace Avalonia.Controls
{
public class Thingamybob : Decorator
{
private int _lastIndex;
public override void ApplyTemplate()
{
if (Child == null)
{
Child = new VirtualizingStackPanel();
((IVirtualizingPanel)Child).ArrangeCompleted = CheckPanel;
}
}
protected override Size ArrangeOverride(Size finalSize)
{
var result = base.ArrangeOverride(finalSize);
CreateItems();
return result;
}
private void CreateItems()
{
var panel = Child as IVirtualizingPanel;
var randomColor = Color.FromUInt32(
(uint)(0xff000000 + new Random().Next(0xffffff)));
while (!panel.IsFull)
{
panel.Children.Add(new TextBlock
{
Text = "Item " + ++_lastIndex,
Background = new SolidColorBrush(randomColor),
});
}
}
private void RemoveItems()
{
var panel = Child as IVirtualizingPanel;
var remove = panel.OverflowCount;
panel.Children.RemoveRange(
panel.Children.Count - remove,
panel.OverflowCount);
_lastIndex -= remove;
}
private void CheckPanel()
{
var panel = Child as IVirtualizingPanel;
if (!panel.IsFull)
{
CreateItems();
}
else if (panel.OverflowCount > 0)
{
RemoveItems();
}
}
}
}

148
src/Avalonia.Controls/VirtualizingStackPanel.cs

@ -0,0 +1,148 @@
// 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;
}
}
}
}
Loading…
Cancel
Save