WinUI | ComponentOne
Controls / FlexGrid / Performance / Virtual Mode
In This Topic
    Virtual Mode
    In This Topic

    FlexGrid uses on-demand loading to load items as the user scrolls through the items and pages. The FlexGrid control supports this feature by means of C1DataCollection. Loading items or pages on demand improves the application's performance by requesting less data at a given time.

    This virtualization technique is implemented by inheriting the C1CursorDataCollection class. This inherited class must implement HasMoreItems property and GetPageAsync method to enable on-demand loading.

    The following example loads YouTube videos on-demand when the user searches for a video in a textbox.

    Follow the steps below to perform on-demand loading:

    1. Add a class, say YouTubeDataCollection, and add the following code.

      public class YouTubeDataCollection : C1CursorDataCollection<YouTubeVideo>
          {
              private string _q;
              private string _orderBy = "relevance";
              private SemaphoreSlim _searchSemaphore = new SemaphoreSlim(1);
              public YouTubeDataCollection()
              {
                  PageSize = 20;
              }
              public int PageSize { get; set; }
              public override bool HasMoreItems
              {
                  get { return _q != null && base.HasMoreItems; }
              }
              public async Task SearchAsync(string q)
              {
                  //Sets the filter string and wait the Delay time.
                  _q = q;
                  await Task.Delay(500);
                  if (_q != q)//If the text changed means there was another keystroke.
                      return;
                  try
                  {
                      await _searchSemaphore.WaitAsync();
                      if (_q != q)//If the text changed means there was another keystroke.
                          return;
                      await RefreshAsync();
                  }
                  catch (Exception ex)
                  {
                      System.Diagnostics.Debug.WriteLine(ex.Message);
                  }
                  finally
                  {
                      _searchSemaphore.Release();
                  }
              }
              public async Task OrderAsync(string orderBy)
              {
                  _orderBy = orderBy;
                  if (_q != null)
                      await RefreshAsync();
              }
              protected override async Task<Tuple<string, IReadOnlyList<YouTubeVideo>>> GetPageAsync(int startingIndex, string pageToken, int? count = null, IReadOnlyList<SortDescription> sortDescriptions = null, FilterExpression filterExpresssion = null, CancellationToken cancellationToken = default(CancellationToken))
              {
                  return await LoadVideosAsync(_q, _orderBy, pageToken, PageSize, cancellationToken);
              }
              public static async Task<Tuple<string, IReadOnlyList<YouTubeVideo>>> LoadVideosAsync(string q, string orderBy, string pageToken, int maxResults, CancellationToken cancellationToken = default(CancellationToken))
              {
                  if (q == null) q = "";
                  var youtubeUrl = string.Format("https://www.googleapis.com/youtube/v3/search?part=snippet&type=video&q={0}&order={1}&maxResults={2}{3}&key={4}", Uri.EscapeUriString(q), orderBy, maxResults, string.IsNullOrWhiteSpace(pageToken) ? "" : "&pageToken=" + pageToken, "AIzaSyCGIvlreIsHaOVVoR2JAPJnbHkSUv3v4y0");
                  var client = new HttpClient();
                  var response = await client.GetAsync(youtubeUrl, cancellationToken);
                  if (response.IsSuccessStatusCode)
                  {
                      var videos = new List<YouTubeVideo>();
                      var serializer = new DataContractJsonSerializer(typeof(YouTubeSearchResult));
                      var result = serializer.ReadObject(await response.Content.ReadAsStreamAsync()) as YouTubeSearchResult;
                      foreach (var item in result.Items)
                      {
                          var video = new YouTubeVideo()
                          {
                              Title = item.Snippet.Title,
                              Description = item.Snippet.Description,
                              Thumbnail = item.Snippet.Thumbnails.Default.Url,
                              Link = "http://www.youtube.com/watch?v=" + item.Id.VideoId,
                              ChannelTitle = item.Snippet.ChannelTitle,
                          };
                          videos.Add(video);
                      }
                      return new Tuple<string, IReadOnlyList<YouTubeVideo>>(result.NextPageToken, videos);
                  }
                  else
                  {
                      throw new Exception(await response.Content.ReadAsStringAsync());
                  }
              }
          }
          [DataContract]
          public class YouTubeSearchResult
          {
              [DataMember(Name = "nextPageToken")]
              public string NextPageToken { get; set; }
              [DataMember(Name = "items")]
              public YouTubeSearchItemResult[] Items { get; set; }
          }
          [DataContract]
          public class YouTubeSearchItemResult
          {
              [DataMember(Name = "id")]
              public YouTubeVideoId Id { get; set; }
              [DataMember(Name = "snippet")]
              public YouTubeSnippet Snippet { get; set; }
          }
          [DataContract]
          public class YouTubeVideoId
          {
              [DataMember(Name = "videoId")]
              public string VideoId { get; set; }
          }
          [DataContract]
          public class YouTubeSnippet
          {
              [DataMember(Name = "title")]
              public string Title { get; set; }
              [DataMember(Name = "description")]
              public string Description { get; set; }
              [DataMember(Name = "thumbnails")]
              public YouTubeThumbnails Thumbnails { get; set; }
              [DataMember(Name = "channelTitle")]
              public string ChannelTitle { get; set; }
          }
          [DataContract]
          public class YouTubeThumbnails
          {
              [DataMember(Name = "default")]
              public YouTubeThumbnail Default { get; set; }
              [DataMember(Name = "medium")]
              public YouTubeThumbnail Medium { get; set; }
              [DataMember(Name = "high")]
              public YouTubeThumbnail High { get; set; }
          }
          [DataContract]
          public class YouTubeThumbnail
          {
              [DataMember(Name = "url")]
              public string Url { get; set; }
          }
          [DataContract]
          public class YouTubeVideo
          {
              public string Title { get; set; }
              public string Description { get; set; }
              public string Thumbnail { get; set; }
              public string Link { get; set; }
              public string ChannelTitle { get; set; }
          }
      
    2. Add the following XAML code in the page to search a video from YouTube using on-demand loading in FlexGrid.

      XAML
      Copy Code
      <Window
          x:Class="WinUIApp1.OnDemand"
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
          xmlns:local="using:WinUIApp1"
          xmlns:core="using:C1.WinUI.Core"
          xmlns:input="using:C1.WinUI.Input"
          xmlns:c1="using:C1.WinUI.Grid"
          xmlns:i="using:Microsoft.Xaml.Interactivity"
          xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
          xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
          mc:Ignorable="d">
          <Grid>
              <Grid.RowDefinitions>
                  <RowDefinition Height="Auto"/>
                  <RowDefinition/>
              </Grid.RowDefinitions>
              <input:C1TextBox x:Name="search" Margin="4" TextChanged="search_TextChanged"/>
              <c1:FlexGrid x:Name="flexGrid1" AutoGenerateColumns="False" HeadersVisibility="Column" IsReadOnly="True" Grid.Row="1">
                  <c1:FlexGrid.Columns>
                      <c1:GridImageColumn Binding="Thumbnail" Header=" " Width="62" PlaceHolder="ms-appx:///Images/default.png"/>
                      <c1:GridHyperlinkColumn Binding="Link" ContentBinding="Title" Header="Title" MinWidth="300" Width="*"/>
                      <c1:GridColumn Binding="ChannelTitle" Header="Channel"/>
                  </c1:FlexGrid.Columns>
                  <i:Interaction.Behaviors>
                      <c1:EmptyGridBehavior EmptyView="{Binding ElementName=emptyListLabel}" />
                  </i:Interaction.Behaviors>
              </c1:FlexGrid>
              <TextBlock x:Name="emptyListLabel" HorizontalAlignment="Center" VerticalAlignment="Top" Grid.Row="1"/>
              <core:C1ActivityIndicator x:Name="activityIndicator" VerticalAlignment="Center" Grid.Row="1" Width="30" Height="30"/>
          </Grid>
      </Window>
      
    3. Also, add the C# code to the page as follows:

      C#
      Copy Code
      public sealed partial class OnDemand : Window
           {
               YouTubeDataCollection _dataCollection;
               public QuickStart()
              {
                   this.InitializeComponent();
                  _dataCollection = new YouTubeDataCollection() { PageSize = 10 };
                   flexGrid1.ItemsSource = _dataCollection;
                   search.Text = "TV";
                   var task = PerformSearch();
               }
               private async Task PerformSearch()
               {
                   try
                   {
                       activityIndicator.Visibility = Visibility.Visible;
                       await _dataCollection.SearchAsync(search.Text);
                   }
                   finally
                   {
                       activityIndicator.Visibility = Visibility.Collapsed;
                   }
               }
              private async void search_TextChanged(object sender, TextChangedEventArgs e)
               {
                   await PerformSearch();
               }
           }