Browse Source
Merge pull request #2813 from AvaloniaUI/fixes/2804-itemsrepeater-problems
Fix ItemsRepeater problems
pull/2818/head
Steven Kirk
7 years ago
committed by
GitHub
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with
48 additions and
14 deletions
-
samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml
-
samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml.cs
-
samples/ControlCatalog/ViewModels/ItemsRepeaterPageViewModel.cs
-
src/Avalonia.Controls/Repeater/ItemsRepeater.cs
-
src/Avalonia.Controls/Repeater/ItemsSourceView.cs
-
src/Avalonia.Layout/UniformGridLayoutState.cs
|
|
|
@ -6,19 +6,20 @@ |
|
|
|
<TextBlock Classes="h1">ItemsRepeater</TextBlock> |
|
|
|
<TextBlock Classes="h2">A data-driven collection control that incorporates a flexible layout system, custom views, and virtualization.</TextBlock> |
|
|
|
</StackPanel> |
|
|
|
<StackPanel DockPanel.Dock="Right" Margin="8 0"> |
|
|
|
<StackPanel DockPanel.Dock="Right" Margin="8 0" Spacing="4"> |
|
|
|
<ComboBox SelectedIndex="0" SelectionChanged="LayoutChanged"> |
|
|
|
<ComboBoxItem>Stack - Vertical</ComboBoxItem> |
|
|
|
<ComboBoxItem>Stack - Horizontal</ComboBoxItem> |
|
|
|
<ComboBoxItem>UniformGrid - Vertical</ComboBoxItem> |
|
|
|
<ComboBoxItem>UniformGrid - Horizontal</ComboBoxItem> |
|
|
|
</ComboBox> |
|
|
|
<Button Command="{Binding AddItem}">Add Item</Button> |
|
|
|
</StackPanel> |
|
|
|
<Border BorderThickness="1" BorderBrush="{DynamicResource ThemeBorderMidBrush}" Margin="0 0 0 16"> |
|
|
|
<ScrollViewer Name="scroller" |
|
|
|
HorizontalScrollBarVisibility="Auto" |
|
|
|
VerticalScrollBarVisibility="Auto"> |
|
|
|
<ItemsRepeater Name="repeater" Items="{Binding}"/> |
|
|
|
<ItemsRepeater Name="repeater" Background="Transparent" Items="{Binding Items}"/> |
|
|
|
</ScrollViewer> |
|
|
|
</Border> |
|
|
|
</DockPanel> |
|
|
|
|
|
|
|
@ -1,8 +1,11 @@ |
|
|
|
using System; |
|
|
|
using System.Linq; |
|
|
|
using Avalonia.Controls; |
|
|
|
using Avalonia.Controls.Primitives; |
|
|
|
using Avalonia.Input; |
|
|
|
using Avalonia.Layout; |
|
|
|
using Avalonia.Markup.Xaml; |
|
|
|
using ControlCatalog.ViewModels; |
|
|
|
|
|
|
|
namespace ControlCatalog.Pages |
|
|
|
{ |
|
|
|
@ -16,7 +19,8 @@ namespace ControlCatalog.Pages |
|
|
|
this.InitializeComponent(); |
|
|
|
_repeater = this.FindControl<ItemsRepeater>("repeater"); |
|
|
|
_scroller = this.FindControl<ScrollViewer>("scroller"); |
|
|
|
DataContext = Enumerable.Range(1, 100000).Select(i => $"Item {i}" ).ToArray(); |
|
|
|
_repeater.PointerPressed += RepeaterClick; |
|
|
|
DataContext = new ItemsRepeaterPageViewModel(); |
|
|
|
} |
|
|
|
|
|
|
|
private void InitializeComponent() |
|
|
|
@ -67,5 +71,11 @@ namespace ControlCatalog.Pages |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private void RepeaterClick(object sender, PointerPressedEventArgs e) |
|
|
|
{ |
|
|
|
var item = (e.Source as TextBlock)?.DataContext as string; |
|
|
|
((ItemsRepeaterPageViewModel)DataContext).SelectedItem = item; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -0,0 +1,27 @@ |
|
|
|
using System.Collections.ObjectModel; |
|
|
|
using System.Linq; |
|
|
|
using ReactiveUI; |
|
|
|
|
|
|
|
namespace ControlCatalog.ViewModels |
|
|
|
{ |
|
|
|
public class ItemsRepeaterPageViewModel : ReactiveObject |
|
|
|
{ |
|
|
|
private int newItemIndex = 1; |
|
|
|
|
|
|
|
public ItemsRepeaterPageViewModel() |
|
|
|
{ |
|
|
|
Items = new ObservableCollection<string>( |
|
|
|
Enumerable.Range(1, 100000).Select(i => $"Item {i}")); |
|
|
|
} |
|
|
|
|
|
|
|
public ObservableCollection<string> Items { get; } |
|
|
|
|
|
|
|
public string SelectedItem { get; set; } |
|
|
|
|
|
|
|
public void AddItem() |
|
|
|
{ |
|
|
|
var index = SelectedItem != null ? Items.IndexOf(SelectedItem) : -1; |
|
|
|
Items.Insert(index + 1, $"New Item {newItemIndex++}"); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -707,9 +707,9 @@ namespace Avalonia.Controls |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private void InvalidateArrangeForLayout(object sender, EventArgs e) => InvalidateMeasure(); |
|
|
|
private void InvalidateMeasureForLayout(object sender, EventArgs e) => InvalidateMeasure(); |
|
|
|
|
|
|
|
private void InvalidateMeasureForLayout(object sender, EventArgs e) => InvalidateArrange(); |
|
|
|
private void InvalidateArrangeForLayout(object sender, EventArgs e) => InvalidateArrange(); |
|
|
|
|
|
|
|
private VirtualizingLayoutContext GetLayoutContext() |
|
|
|
{ |
|
|
|
|
|
|
|
@ -35,9 +35,11 @@ namespace Avalonia.Controls |
|
|
|
{ |
|
|
|
Contract.Requires<ArgumentNullException>(source != null); |
|
|
|
|
|
|
|
_inner = source as IList; |
|
|
|
|
|
|
|
if (_inner == null && source is IEnumerable<object> objectEnumerable) |
|
|
|
if (source is IList list) |
|
|
|
{ |
|
|
|
_inner = list; |
|
|
|
} |
|
|
|
else if (source is IEnumerable<object> objectEnumerable) |
|
|
|
{ |
|
|
|
_inner = new List<object>(objectEnumerable); |
|
|
|
} |
|
|
|
|
|
|
|
@ -72,12 +72,6 @@ namespace Avalonia.Layout |
|
|
|
|
|
|
|
_cachedFirstElement.Measure(availableSize); |
|
|
|
|
|
|
|
// This doesn't need to be done in the UWP version and I'm not sure why. If we
|
|
|
|
// don't do this here, and we receive a recycled element then it will be shown
|
|
|
|
// at its previous arrange point, but we don't want it shown at all until its
|
|
|
|
// arranged.
|
|
|
|
_cachedFirstElement.Arrange(new Rect(-10000.0, -10000.0, 0, 0)); |
|
|
|
|
|
|
|
SetSize(_cachedFirstElement, layoutItemWidth, LayoutItemHeight, availableSize, stretch, orientation, minRowSpacing, minColumnSpacing); |
|
|
|
|
|
|
|
// See if we can move ownership to the flow algorithm. If we can, we do not need a local cache.
|
|
|
|
|