Browse Source

Merge pull request #7892 from 0x0ade/recycledanchors

Fix IsRegisteredAsAnchorCandidate desync, mainly affecting recycled anchors
pull/8023/head
Steven Kirk 4 years ago
committed by GitHub
parent
commit
94780b5bc5
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml
  2. 10
      samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml.cs
  3. 13
      samples/ControlCatalog/ViewModels/ItemsRepeaterPageViewModel.cs
  4. 8
      src/Avalonia.Controls/Repeater/ItemsRepeater.cs
  5. 29
      src/Avalonia.Controls/Repeater/ViewportManager.cs

2
samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml

@ -53,10 +53,12 @@
<ComboBoxItem>UniformGrid - Horizontal</ComboBoxItem>
</ComboBox>
<Button Command="{Binding AddItem}">Add Item</Button>
<Button Command="{Binding RemoveItem}">Remove Item</Button>
<Button Command="{Binding RandomizeHeights}">Randomize Heights</Button>
<Button Command="{Binding ResetItems}">Reset items</Button>
<Button x:Name="scrollToLast">Scroll to Last</Button>
<Button x:Name="scrollToRandom">Scroll to Random</Button>
<Button x:Name="scrollToSelected">Scroll to Selected</Button>
</StackPanel>
<Border BorderThickness="1" BorderBrush="{DynamicResource SystemControlHighlightBaseMediumLowBrush}" Margin="0 0 0 16">
<ScrollViewer Name="scroller"

10
samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml.cs

@ -15,8 +15,10 @@ namespace ControlCatalog.Pages
private readonly ItemsRepeaterPageViewModel _viewModel;
private ItemsRepeater _repeater;
private ScrollViewer _scroller;
private int _selectedIndex;
private Button _scrollToLast;
private Button _scrollToRandom;
private Button _scrollToSelected;
private Random _random = new Random(0);
public ItemsRepeaterPage()
@ -26,10 +28,12 @@ namespace ControlCatalog.Pages
_scroller = this.FindControl<ScrollViewer>("scroller");
_scrollToLast = this.FindControl<Button>("scrollToLast");
_scrollToRandom = this.FindControl<Button>("scrollToRandom");
_scrollToSelected = this.FindControl<Button>("scrollToSelected");
_repeater.PointerPressed += RepeaterClick;
_repeater.KeyDown += RepeaterOnKeyDown;
_scrollToLast.Click += scrollToLast_Click;
_scrollToRandom.Click += scrollToRandom_Click;
_scrollToSelected.Click += scrollToSelected_Click;
DataContext = _viewModel = new ItemsRepeaterPageViewModel();
}
@ -121,6 +125,7 @@ namespace ControlCatalog.Pages
{
var item = (e.Source as TextBlock)?.DataContext as ItemsRepeaterPageViewModel.Item;
_viewModel.SelectedItem = item;
_selectedIndex = _viewModel.Items.IndexOf(item);
}
private void RepeaterOnKeyDown(object sender, KeyEventArgs e)
@ -140,5 +145,10 @@ namespace ControlCatalog.Pages
{
ScrollTo(_random.Next(_viewModel.Items.Count - 1));
}
private void scrollToSelected_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
ScrollTo(_selectedIndex);
}
}
}

13
samples/ControlCatalog/ViewModels/ItemsRepeaterPageViewModel.cs

@ -31,6 +31,19 @@ namespace ControlCatalog.ViewModels
Items.Insert(index + 1, new Item(index + 1) { Text = $"New Item {_newItemIndex++}" });
}
public void RemoveItem()
{
if (SelectedItem is not null)
{
Items.Remove(SelectedItem);
SelectedItem = null;
}
else if (Items.Count > 0)
{
Items.RemoveAt(Items.Count - 1);
}
}
public void RandomizeHeights()
{
var random = new Random();

8
src/Avalonia.Controls/Repeater/ItemsRepeater.cs

@ -401,11 +401,7 @@ namespace Avalonia.Controls
var newBounds = element.Bounds;
virtInfo.ArrangeBounds = newBounds;
if (!virtInfo.IsRegisteredAsAnchorCandidate)
{
_viewportManager.RegisterScrollAnchorCandidate(element);
virtInfo.IsRegisteredAsAnchorCandidate = true;
}
_viewportManager.RegisterScrollAnchorCandidate(element, virtInfo);
}
}
@ -490,7 +486,7 @@ namespace Avalonia.Controls
_processingItemsSourceChange.Action == NotifyCollectionChangedAction.Reset);
_viewManager.ClearElement(element, isClearedDueToCollectionChange);
_viewportManager.OnElementCleared(element);
_viewportManager.OnElementCleared(element, GetVirtualizationInfo(element));
}
private int GetElementIndexImpl(IControl element)

29
src/Avalonia.Controls/Repeater/ViewportManager.cs

@ -249,9 +249,10 @@ namespace Avalonia.Controls
virtInfo.IsRegisteredAsAnchorCandidate = false;
}
public void OnElementCleared(IControl element)
public void OnElementCleared(IControl element, VirtualizationInfo virtInfo)
{
_scroller?.UnregisterAnchorCandidate(element);
virtInfo.IsRegisteredAsAnchorCandidate = false;
}
public void OnOwnerMeasuring()
@ -358,9 +359,12 @@ namespace Avalonia.Controls
{
foreach (var child in _owner.Children)
{
if (child != targetChild)
var info = ItemsRepeater.GetVirtualizationInfo(child);
if (child != targetChild && info.IsRegisteredAsAnchorCandidate)
{
_scroller.UnregisterAnchorCandidate(child);
info.IsRegisteredAsAnchorCandidate = false;
}
}
}
@ -377,9 +381,13 @@ namespace Avalonia.Controls
}
}
public void RegisterScrollAnchorCandidate(IControl element)
public void RegisterScrollAnchorCandidate(IControl element, VirtualizationInfo virtInfo)
{
_scroller?.RegisterAnchorCandidate(element);
if (!virtInfo.IsRegisteredAsAnchorCandidate)
{
_scroller?.RegisterAnchorCandidate(element);
virtInfo.IsRegisteredAsAnchorCandidate = true;
}
}
private IControl? GetImmediateChildOfRepeater(IControl descendant)
@ -405,15 +413,18 @@ namespace Avalonia.Controls
_isBringIntoViewInProgress = false;
_makeAnchorElement = null;
// Undo the anchor deregistrations done by OnBringIntoViewRequested.
if (_scroller is object)
{
foreach (var child in _owner.Children)
{
var info = ItemsRepeater.GetVirtualizationInfo(child);
if (info.IsRealized && info.IsHeldByLayout)
// The item brought into view is still registered - don't register it more than once.
if (info.IsRealized && info.IsHeldByLayout && !info.IsRegisteredAsAnchorCandidate)
{
_scroller.RegisterAnchorCandidate(child);
info.IsRegisteredAsAnchorCandidate = true;
}
}
}
@ -430,7 +441,13 @@ namespace Avalonia.Controls
{
foreach (var child in _owner.Children)
{
_scroller.UnregisterAnchorCandidate(child);
var info = ItemsRepeater.GetVirtualizationInfo(child);
if (info.IsRegisteredAsAnchorCandidate)
{
_scroller.UnregisterAnchorCandidate(child);
info.IsRegisteredAsAnchorCandidate = false;
}
}
_scroller = null;

Loading…
Cancel
Save