UI virtualization renders only visible items, reducing memory usage and improving performance.
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.
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()); } } |
|
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); } |
|
Data is retrieved on demand
Only visible or required items are loaded
Improves performance for large datasets
Notes
The
GetPageAsyncmethod defines how data is fetchedPerformance depends on data source latency and implementation efficiency
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; } } |
|