AvaloniaUI / Avalonia.Controls.ItemsRepeater

ItemsRepeater is a light-weight control to generate and present a collection of items.
MIT License
3 stars 1 forks source link

ScrollViewer or ItemsRepeater does not render items added to the top #28

Open Hunv opened 1 month ago

Hunv commented 1 month ago

Describe the bug

I have this:

<ScrollViewer
  ScrollViewer.VerticalScrollBarVisibility= "Auto"
  Grid.Row= "0"
  >
  <cntrl:ItemsRepeater
      ItemsSource = "{Binding MyItemList}"
      Background= "{DynamicResource SiteBackgroundBrush}"
    >
    <ItemsRepeater.ItemTemplate >
      <DataTemplate DataType= "m:MyModel" >
        <Border
          BorderThickness= "2"
          CornerRadius= "5"
          BorderBrush= "{DynamicResource ItemBackgroundBrush}"
          Background= "{DynamicResource ItemBackgroundBrush}"
          Margin= "5,5,5,0"
          >
          <Grid Margin= "0,5,0,0" >
            ...            
          </Grid>
        </Border>
      </DataTemplate>
    </ItemsRepeater.ItemTemplate>
  </cntrl:ItemsRepeater>
</ScrollViewer>

The MyItemList is an ObservableCollection. When I add a new Item to the Top of the list via MyItemList.Insert(0, ...) and run a this.RaisePropertyChanged(nameof(MyItemList));, the space of the new item in the ItemsRepeater is used but the item itself is not rendered. This does not happen from the very beginning but after some (not so long) time. I think shortly after when the first items runs out of the visible part of the Window. If I scroll just a pixel in the ScrollViewer, everything is where and how it should be immediately. This does not happen, if the ScrollViewer is not involved.

This is how it looks like: image

To Reproduce

Create a new Avalonia Project from scratch with Desktop enabled. Leave everything else at default. Make the following changes:

  1. Add the Avalonia.ItemsRepeater Nuget to the main project
  2. Replace code in MainViewModel.cs with this:
    
    using System.Collections.ObjectModel;
    using System;
    using ReactiveUI;

namespace AvaloniaApplication1.ViewModels;

public class MainViewModel : ViewModelBase { public ObservableCollection MyItemList { get; set; } = new ObservableCollection(); private readonly System.Timers.Timer _TmrDisruptionUpdate = new(1000);

public MainViewModel() 
{ 
    MyItemList.Add(new MyModel() { Text = "foobar"});
    MyItemList.Add(new MyModel() { Text = "Hello World" });
    MyItemList.Add(new MyModel() { Text = "John Doe" });
    MyItemList.Add(new MyModel() { Text = "xxxxx" });

    _TmrDisruptionUpdate.Elapsed += _TmrDisruptionUpdate_Elapsed;
    _TmrDisruptionUpdate.Start();
}

private void _TmrDisruptionUpdate_Elapsed(object? sender, System.Timers.ElapsedEventArgs e)
{
    MyItemList.Insert(0, new MyModel() { Text = DateTime.Now.ToString() });        
    this.RaisePropertyChanged(nameof(MyItemList));
}

}


3. Create a new class called `MyModel.cs` with the following content:

namespace AvaloniaApplication1.ViewModels { public class MyModel { public string Text { get; set; } } }


4. Edit the MainView.axaml as follows:

<UserControl xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:vm="clr-namespace:AvaloniaApplication1.ViewModels" xmlns:cntrl="using:Avalonia.Controls" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="AvaloniaApplication1.Views.MainView" x:DataType="vm:MainViewModel">

<ScrollViewer ScrollViewer.VerticalScrollBarVisibility="Auto"

<cntrl:ItemsRepeater ItemsSource="{Binding MyItemList}" Background="#222222"

``` I create a sample project with the things above: [ScrollViewerRenderIssue.zip](https://github.com/user-attachments/files/17344272/ScrollViewerRenderIssue.zip)

Expected behavior

Also later added items are rendered as the first items that were added.

Avalonia version

11.1.4

OS

Windows

Additional context

No response

thevortexcloud commented 1 month ago

FYI: ItemsRepeater is being deprecated soonish. It is however still somewhat supported right now.

https://github.com/AvaloniaUI/Avalonia.Controls.ItemsRepeater

Hunv commented 1 month ago

FYI: ItemsRepeater is being deprecated soonish. It is however still somewhat supported right now.

https://github.com/AvaloniaUI/Avalonia.Controls.ItemsRepeater

I wasn't aware that the ItemsRepeater is deprecated. OK, thank you for the hint. On the first view ItemsControl can be used as a drop-in replacement for the ItemsRepeater in this case. This also seems to fix the issue. But it seems that the ItemsControl is much slower than the ItemsRepeater if the list is longer (i.e. 1000 items).

thevortexcloud commented 1 month ago

I wasn't aware that the ItemsRepeater is deprecated.

It's not yet. It will be sometime after 12.0 releases though (no idea when that is). I will say you should still avoid using it for new developments though. But fixes and bug reports are technically still being accepted for it.

But it seems that the ItemsControl is much slower than the ItemsRepeater if the list is longer (i.e. 1000 items).

Do you have virtualisation enabled? The majority of ItemsRepeater panels are virtualised. ItemsControl however is not virtualised by default.

https://github.com/AvaloniaUI/Avalonia/blob/a04af7cebf3d49b81c228cbb6c18eb2e860ada58/src/Avalonia.Controls/ItemsControl.cs#L28-L32

If you change ItemsPanel on the ItemsControl to a VirtualizingStackPanel it will probably fix your issue.

Hunv commented 1 month ago

Thank you very much for that hint. This replaces the ItemsRepeater completely - at least for me:

 <ScrollViewer
    ScrollViewer.VerticalScrollBarVisibility="Auto"
    >
    <ItemsControl
        ItemsSource="{Binding MyItemList}"
        >
      <ItemsControl.ItemTemplate>
        <DataTemplate DataType="vm:MyModel">
          <Border>
            ...
          </Border>
        </DataTemplate>
      </ItemsControl.ItemTemplate>
      <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
          <VirtualizingStackPanel Orientation="Vertical" />
        </ItemsPanelTemplate>
      </ItemsControl.ItemsPanel>
    </ItemsControl>
  </ScrollViewer>
thevortexcloud commented 1 month ago

Glad I could help