Skip to content

Commit

Permalink
Merge pull request #9677 from AvaloniaUI/refactor/itemcontainergenerator
Browse files Browse the repository at this point in the history
Refactor ItemsControl container generation and implement smooth virtualization
  • Loading branch information
maxkatz6 authored Jan 17, 2023
2 parents a003b90 + 17e1d37 commit 6bad0ac
Show file tree
Hide file tree
Showing 118 changed files with 4,190 additions and 7,379 deletions.
4 changes: 2 additions & 2 deletions samples/ControlCatalog/Pages/CarouselPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
</Button>
<Carousel Name="carousel" Grid.Column="1">
<Carousel.PageTransition>
<PageSlide Duration="0.25" Orientation="Vertical" />
<PageSlide Duration="0.25" Orientation="Horizontal" />
</Carousel.PageTransition>
<Image Source="/Assets/delicate-arch-896885_640.jpg"/>
<Image Source="/Assets/hirsch-899118_640.jpg"/>
Expand All @@ -35,7 +35,7 @@

<StackPanel Orientation="Horizontal" Spacing="4">
<TextBlock VerticalAlignment="Center">Orientation</TextBlock>
<ComboBox Name="orientation" SelectedIndex="1" VerticalAlignment="Center">
<ComboBox Name="orientation" SelectedIndex="0" VerticalAlignment="Center">
<ComboBoxItem>Horizontal</ComboBoxItem>
<ComboBoxItem>Vertical</ComboBoxItem>
</ComboBox>
Expand Down
2 changes: 1 addition & 1 deletion samples/ControlCatalog/Pages/DialogsPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
Classes="h2"
IsVisible="False"
Text="Last picker results:" />
<ItemsPresenter x:Name="PickerLastResults" />
<ItemsControl x:Name="PickerLastResults" />

<TextBox Name="BookmarkContainer" Watermark="Bookmark" />
<TextBox Name="OpenedFileContent"
Expand Down
60 changes: 30 additions & 30 deletions samples/ControlCatalog/Pages/DialogsPage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public DialogsPage()
{
this.InitializeComponent();

var results = this.Get<ItemsPresenter>("PickerLastResults");
var results = this.Get<ItemsControl>("PickerLastResults");
var resultsVisible = this.Get<TextBlock>("PickerLastResultsVisible");
var bookmarkContainer = this.Get<TextBox>("BookmarkContainer");
var openedFileContent = this.Get<TextBox>("OpenedFileContent");
Expand All @@ -36,29 +36,29 @@ List<FileDialogFilter> GetFilters()
{
if (this.Get<CheckBox>("UseFilters").IsChecked != true)
return new List<FileDialogFilter>();
return new List<FileDialogFilter>
{
new FileDialogFilter
{
Name = "Text files (.txt)", Extensions = new List<string> {"txt"}
},
new FileDialogFilter
{
Name = "All files",
Extensions = new List<string> {"*"}
}
};
return new List<FileDialogFilter>
{
new FileDialogFilter
{
Name = "Text files (.txt)", Extensions = new List<string> {"txt"}
},
new FileDialogFilter
{
Name = "All files",
Extensions = new List<string> {"*"}
}
};
}

List<FilePickerFileType>? GetFileTypes()
{
if (this.Get<CheckBox>("UseFilters").IsChecked != true)
return null;
return new List<FilePickerFileType>
{
FilePickerFileTypes.All,
FilePickerFileTypes.TextPlain
};
{
FilePickerFileTypes.All,
FilePickerFileTypes.TextPlain
};
}

this.Get<Button>("OpenFile").Click += async delegate
Expand Down Expand Up @@ -205,15 +205,15 @@ List<FileDialogFilter> GetFilters()
await using var stream = await file.OpenWriteAsync();
await using var reader = new System.IO.StreamWriter(stream);
#else
using var stream = await file.OpenWriteAsync();
using var reader = new System.IO.StreamWriter(stream);
using var stream = await file.OpenWriteAsync();
using var reader = new System.IO.StreamWriter(stream);
#endif
await reader.WriteLineAsync(openedFileContent.Text);

lastSelectedDirectory = await file.GetParentAsync();
}

await SetPickerResult(file is null ? null : new [] {file});
await SetPickerResult(file is null ? null : new[] { file });
};
this.Get<Button>("OpenFolderPicker").Click += async delegate
{
Expand Down Expand Up @@ -243,7 +243,7 @@ List<FileDialogFilter> GetFilters()
: null;

await SetPickerResult(folder is null ? null : new[] { folder });

lastSelectedDirectory = folder;
};

Expand All @@ -260,23 +260,23 @@ async Task SetPickerResult(IReadOnlyCollection<IStorageItem>? items)

var props = await item.GetBasicPropertiesAsync();
resultText += @$"Size: {props.Size}
DateCreated: {props.DateCreated}
DateModified: {props.DateModified}
CanBookmark: {item.CanBookmark}
";
DateCreated: {props.DateCreated}
DateModified: {props.DateModified}
CanBookmark: {item.CanBookmark}
";
if (item is IStorageFile file)
{
resultText += @$"
CanOpenRead: {file.CanOpenRead}
CanOpenWrite: {file.CanOpenWrite}
Content:
";
CanOpenRead: {file.CanOpenRead}
CanOpenWrite: {file.CanOpenWrite}
Content:
";
if (file.CanOpenRead)
{
#if NET6_0_OR_GREATER
await using var stream = await file.OpenReadAsync();
#else
using var stream = await file.OpenReadAsync();
using var stream = await file.OpenReadAsync();
#endif
using var reader = new System.IO.StreamReader(stream);

Expand Down
2 changes: 1 addition & 1 deletion samples/ControlCatalog/Pages/TabControlPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
<TabControl
Items="{Binding Tabs}"
Margin="0 16"
HeaderDisplayMemberBinding="{Binding Header, x:DataType=viewModels:TabControlPageViewModelItem}"
DisplayMemberBinding="{Binding Header, x:DataType=viewModels:TabControlPageViewModelItem}"
TabStripPlacement="{Binding TabPlacement}">
<TabControl.ContentTemplate>
<DataTemplate x:DataType="viewModels:TabControlPageViewModelItem">
Expand Down
4 changes: 1 addition & 3 deletions samples/SampleControls/HamburgerMenu/HamburgerMenu.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -168,9 +168,7 @@
HorizontalScrollBarVisibility="{TemplateBinding (ScrollViewer.HorizontalScrollBarVisibility)}"
VerticalScrollBarVisibility="{TemplateBinding (ScrollViewer.VerticalScrollBarVisibility)}">
<ItemsPresenter Name="PART_ItemsPresenter"
HorizontalAlignment="Stretch"
ItemTemplate="{TemplateBinding ItemTemplate}"
Items="{TemplateBinding Items}">
HorizontalAlignment="Stretch">
<ItemsPresenter.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel x:Name="HamburgerItemsPanel"
Expand Down
5 changes: 1 addition & 4 deletions samples/VirtualizationDemo/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,8 @@
<DockPanel LastChildFill="True" Margin="16">
<StackPanel DockPanel.Dock="Right"
Margin="16 0 0 0"
MinWidth="150"
Width="150"
Spacing="4">
<ComboBox Items="{Binding VirtualizationModes}"
SelectedItem="{Binding VirtualizationMode}"/>
<ComboBox Items="{Binding Orientations}"
SelectedItem="{Binding Orientation}"/>
<TextBox Watermark="Item Count"
Expand Down Expand Up @@ -49,7 +47,6 @@
Items="{Binding Items}"
Selection="{Binding Selection}"
SelectionMode="Multiple"
VirtualizationMode="{Binding VirtualizationMode}"
ScrollViewer.HorizontalScrollBarVisibility="{Binding HorizontalScrollBarVisibility, Mode=TwoWay}"
ScrollViewer.VerticalScrollBarVisibility="{Binding VerticalScrollBarVisibility, Mode=TwoWay}">
<ListBox.ItemsPanel>
Expand Down
10 changes: 0 additions & 10 deletions samples/VirtualizationDemo/ViewModels/MainWindowViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ internal class MainWindowViewModel : ViewModelBase
private ScrollBarVisibility _horizontalScrollBarVisibility = ScrollBarVisibility.Auto;
private ScrollBarVisibility _verticalScrollBarVisibility = ScrollBarVisibility.Auto;
private Orientation _orientation = Orientation.Vertical;
private ItemVirtualizationMode _virtualizationMode = ItemVirtualizationMode.Simple;

public MainWindowViewModel()
{
Expand Down Expand Up @@ -81,15 +80,6 @@ public ScrollBarVisibility VerticalScrollBarVisibility
public IEnumerable<ScrollBarVisibility> ScrollBarVisibilities =>
Enum.GetValues(typeof(ScrollBarVisibility)).Cast<ScrollBarVisibility>();

public ItemVirtualizationMode VirtualizationMode
{
get { return _virtualizationMode; }
set { this.RaiseAndSetIfChanged(ref _virtualizationMode, value); }
}

public IEnumerable<ItemVirtualizationMode> VirtualizationModes =>
Enum.GetValues(typeof(ItemVirtualizationMode)).Cast<ItemVirtualizationMode>();

public MiniCommand AddItemCommand { get; private set; }
public MiniCommand RecreateCommand { get; private set; }
public MiniCommand RemoveItemCommand { get; private set; }
Expand Down
2 changes: 0 additions & 2 deletions src/Avalonia.Base/Animation/PageSlide.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ public virtual async Task Start(Visual? from, Visual? to, bool forward, Cancella
var animation = new Animation
{
Easing = SlideOutEasing,
FillMode = FillMode.Forward,
Children =
{
new KeyFrame
Expand Down Expand Up @@ -110,7 +109,6 @@ public virtual async Task Start(Visual? from, Visual? to, bool forward, Cancella
to.IsVisible = true;
var animation = new Animation
{
FillMode = FillMode.Forward,
Easing = SlideInEasing,
Children =
{
Expand Down
2 changes: 0 additions & 2 deletions src/Avalonia.Base/Animation/Transitions/Rotate3DTransition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ KeyFrame CreateKeyFrame(double cue, double rotation, int zIndex, bool isVisible
{
Easing = SlideOutEasing,
Duration = Duration,
FillMode = FillMode.Forward,
Children =
{
CreateKeyFrame(0d, 0d, 2),
Expand All @@ -90,7 +89,6 @@ KeyFrame CreateKeyFrame(double cue, double rotation, int zIndex, bool isVisible
{
Easing = SlideInEasing,
Duration = Duration,
FillMode = FillMode.Forward,
Children =
{
CreateKeyFrame(0d, 90d * (forward ? 1 : -1), 1),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,8 @@
IsScrollChainingEnabled="{TemplateBinding (ScrollViewer.IsScrollChainingEnabled)}"
AllowAutoHide="{TemplateBinding (ScrollViewer.AllowAutoHide)}">
<ItemsPresenter Name="PART_ItemsPresenter"
Items="{TemplateBinding Items}"
ItemsPanel="{TemplateBinding ItemsPanel}"
ItemTemplate="{TemplateBinding ItemTemplate}"
Margin="{TemplateBinding Padding}"
VirtualizationMode="{TemplateBinding VirtualizationMode}" />
Margin="{TemplateBinding Padding}"/>
</ScrollViewer>
</Border>
</ControlTemplate>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,8 @@
IsScrollChainingEnabled="{TemplateBinding (ScrollViewer.IsScrollChainingEnabled)}"
AllowAutoHide="{TemplateBinding (ScrollViewer.AllowAutoHide)}">
<ItemsPresenter Name="PART_ItemsPresenter"
Items="{TemplateBinding Items}"
ItemsPanel="{TemplateBinding ItemsPanel}"
ItemTemplate="{TemplateBinding ItemTemplate}"
Margin="{TemplateBinding Padding}"
VirtualizationMode="{TemplateBinding VirtualizationMode}" />
Margin="{TemplateBinding Padding}"/>
</ScrollViewer>
</Border>
</ControlTemplate>
Expand Down
52 changes: 31 additions & 21 deletions src/Avalonia.Controls/Carousel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
using Avalonia.Controls.Utils;
using Avalonia.Input;

namespace Avalonia.Controls
{
Expand All @@ -11,12 +10,6 @@ namespace Avalonia.Controls
/// </summary>
public class Carousel : SelectingItemsControl
{
/// <summary>
/// Defines the <see cref="IsVirtualized"/> property.
/// </summary>
public static readonly StyledProperty<bool> IsVirtualizedProperty =
AvaloniaProperty.Register<Carousel, bool>(nameof(IsVirtualized), true);

/// <summary>
/// Defines the <see cref="PageTransition"/> property.
/// </summary>
Expand All @@ -28,7 +21,9 @@ public class Carousel : SelectingItemsControl
/// <see cref="Carousel"/>.
/// </summary>
private static readonly ITemplate<Panel> PanelTemplate =
new FuncTemplate<Panel>(() => new Panel());
new FuncTemplate<Panel>(() => new VirtualizingCarouselPanel());

private IScrollable? _scroller;

/// <summary>
/// Initializes static members of the <see cref="Carousel"/> class.
Expand All @@ -38,18 +33,6 @@ static Carousel()
SelectionModeProperty.OverrideDefaultValue<Carousel>(SelectionMode.AlwaysSelected);
ItemsPanelProperty.OverrideDefaultValue<Carousel>(PanelTemplate);
}

/// <summary>
/// Gets or sets a value indicating whether the items in the carousel are virtualized.
/// </summary>
/// <remarks>
/// When the carousel is virtualized, only the active page is held in memory.
/// </remarks>
public bool IsVirtualized
{
get { return GetValue(IsVirtualizedProperty); }
set { SetValue(IsVirtualizedProperty, value); }
}

/// <summary>
/// Gets or sets the transition to use when moving between pages.
Expand All @@ -65,7 +48,7 @@ public IPageTransition? PageTransition
/// </summary>
public void Next()
{
if (SelectedIndex < Items.Count() - 1)
if (SelectedIndex < ItemCount - 1)
{
++SelectedIndex;
}
Expand All @@ -81,5 +64,32 @@ public void Previous()
--SelectedIndex;
}
}

protected override Size ArrangeOverride(Size finalSize)
{
var result = base.ArrangeOverride(finalSize);

if (_scroller is not null)
_scroller.Offset = new(SelectedIndex, 0);

return result;
}

protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
_scroller = e.NameScope.Find<IScrollable>("PART_ScrollViewer");
}

protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);

if (change.Property == SelectedIndexProperty && _scroller is not null)
{
var value = change.GetNewValue<int>();
_scroller.Offset = new(value, 0);
}
}
}
}
Loading

0 comments on commit 6bad0ac

Please sign in to comment.