ComponentOne for WinUI
仮想化
コントロール > ListView > ListViewの使い方 > 仮想化

UI Virtualization

UI virtualization renders only visible items, reducing memory usage and improving performance.

Data Virtualization

Data virtualization loads data incrementally as required by the control.

The ListView control supports data virtualization through C1VirtualDataCollection.

VirtualModeDataCollection is not a built-in class and must be implemented to define data retrieval behavior.

Implementation

The following example demonstrates a custom implementation of VirtualModeDataCollection:

C#
コードのコピー
public class VirtualModeDataCollection : C1VirtualDataCollection<Person>
{
   private readonly int TotalCount = 1_000_000_000;
   protected override async Task<Tuple<int, IReadOnlyList<Person>>> GetPageAsync(int pageIndex, int startingIndex, int count, IReadOnlyList<SortDescription> sortDescriptions = null, FilterExpression filterExpression = null, CancellationToken cancellationToken = default(CancellationToken))
   {
      await Task.Delay(100, cancellationToken).ConfigureAwait(false); //Simulates network traffic.
      return new Tuple<int, IReadOnlyList<Person>>(TotalCount, Enumerable.Range(startingIndex, count).Select(i => new Person(i)).ToList());
   }
}

Usage

After implementing the virtual data collection, assign it to the ItemsSource property:

XAML
コードのコピー
<Grid x:Name="LayoutRoot">
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <c1:C1ListView x:Name="listView" Grid.Row="0" SelectionMode="Single" DisplayMemberPath="Name"  Margin="10 0 10 10" IsSwipeEnabled="True"/>
</Grid>
C#
コードのコピー
using C1.DataCollection;
public MainWindow()
{
    InitializeComponent();
    //Bind to datasource
    this.Loaded += VirtualMode_Loaded;
}
// Use the LoadAsync method for data virtualization
private async void VirtualMode_Loaded(object sender, RoutedEventArgs e)
{
    var persons = new VirtualModeDataCollection();
    listView.ItemsSource = persons;
    await persons.LoadAsync(0, 0);
}

Behavior

Notes

  • The GetPageAsync method defines how data is fetched

  • Performance depends on data source latency and implementation efficiency

Preview State

The PreviewItemTemplate property defines how items are displayed while content is loading or during fast scrolling.

XAML
コードのコピー
<c1:C1ListView x:Name="listView" IsSwipeEnabled="True"  Visibility="Collapsed"  Orientation="Horizontal"  Zoom="1"  ZoomMode="Enabled"  RefreshWhileScrolling="False">
    <c1:C1ListView.PreviewItemTemplate>
        <DataTemplate>
            <Grid Background="Gray">
                <Image Source="{Binding Thumbnail}" Stretch="UniformToFill" />
            </Grid>
        </DataTemplate>
    </c1:C1ListView.PreviewItemTemplate>
    <c1:C1ListView.ItemTemplate>
        <DataTemplate>
            <Grid>
                <Image Source="{Binding Content}" Stretch="UniformToFill" />
                <TextBlock Text="{Binding Title}" Margin="4 0 0 4" VerticalAlignment="Bottom" />
            </Grid>
        </DataTemplate>
    </c1:C1ListView.ItemTemplate>
    <c1:C1ListView.ItemContainerStyle>
        <!--This style allows showing the preview while the full image is being loaded-->
        <Style TargetType="c1:ListViewItemView">
            <Setter Property="BorderThickness" Value="1" />
            <Setter Property="Margin" Value="0" />
            <Setter Property="Padding" Value="2" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="c1:ListViewItemView">
                        <Grid>
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="CommonStates">
                                    <VisualState x:Name="Normal" />
                                    <VisualState x:Name="PointerOver">
                                        <Storyboard>
                                            <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PointerOverBorder" />
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Disabled">
                                        <Storyboard>
                                            <DoubleAnimation Duration="0" To=".55" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="Content" />
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </c1:C1ListView.ItemContainerStyle>
</c1:C1ListView>
C#
コードのコピー
public MainWindow()
{
  InitializeComponent();
  LoadPhotos();
}
private async void LoadPhotos()
{
  var source = new List<Photo>();
  var state = ApplicationState.Loading;
  UpdateView(source, state);
  try
  {
    source = await PhotosFromFlickr();
    state = ApplicationState.Loaded;
  }
  catch (Exception)
  {
    state = ApplicationState.Failed;
  }
  UpdateView(source, state);
}
private void UpdateView(List<Photo> source, ApplicationState state)
{
  if (state == ApplicationState.Loading)
  {
    UpdateVisibility(state);
  }
  else if (state == ApplicationState.Loaded)
  {
    listView.ItemsSource = source;
    UpdateVisibility(state);
  }
  else if (state == ApplicationState.Failed)
  {
    MessageBox.Show("There was an error when attempting to download data from Flickr.");
    UpdateVisibility(state);
  }
}
private async Task<List<Photo>> PhotosFromFlickr()
{
  List<Photo> photos = new List<Photo>();
  Uri flickrAPI = new Uri("http://api.flickr.com/services/feeds/photos_public.gne?tags=explore");
  string AtomNS = "http://www.w3.org/2005/Atom";
  HttpClient httpClient = new HttpClient();
  using (HttpResponseMessage httpResponse = await httpClient.GetAsync(flickrAPI, HttpCompletionOption.ResponseHeadersRead))
  {
    httpResponse.EnsureSuccessStatusCode();
    if (httpResponse.Content is not null)
    {
      Stream stream = await httpResponse.Content.ReadAsStreamAsync();
      photos = Photo.FromStream(stream, AtomNS);
    }
  }
  return photos;
}
public class Photo
{
  private readonly string Title { get; set; }
  private readonly string Content { get; set; }
  private readonly string Thumbnail { get; set; }
}