Blazor | ComponentOne
Controls / ListView / Data Binding / On-Demand Loading
In This Topic
    On-Demand Loading
    In This Topic

    ListView uses on-demand loading to load items as the user scrolls through the items and pages. The ListView 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.

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

    1. In the Data folder, add a class, say YouTubeDataCollection, and add the following code.
      C#
      Copy Code
      using System;
      using System.Collections.Generic;
      using System.Globalization;
      using System.Net.Http;
      using System.Runtime.Serialization;
      using System.Runtime.Serialization.Json;
      using System.Threading;
      using System.Threading.Tasks;
      using C1.DataCollection;
      
      namespace OnDemand
      {
          public class YouTubeDataCollection : C1CursorDataCollection<YouTubeVideo>
          {
              private string _q;
              private string _orderBy = "relevance";
      
              public YouTubeDataCollection()
              {
                  PageSize = 20;
              }
      
              public int PageSize { get; set; }
      
              public override bool HasMoreItems
              {
                  get { return _q != null && base.HasMoreItems; }
              }
      
              private SemaphoreSlim _searchSemaphore = new SemaphoreSlim(1);
      
              public async Task SearchAsync(string q)
              {
                  //Sets the filter string and wait the Delay time.
                  _q = q;
                  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, "date", 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 (string.IsNullOrWhiteSpace(q)) return new Tuple<string, IReadOnlyList<YouTubeVideo>>(default, new YouTubeVideo[0]);
      
                  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, "AIzaSyCtwKIq-Td5FBNOlvOiWEJaClRBDyq-ZsU");
      
                  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,
                              PublishedAt = DateTime.Parse(item.Snippet.PublishedAt),
                          };
                          videos.Add(video);
                      }
                      return new Tuple<string, IReadOnlyList<YouTubeVideo>>(result.NextPageToken, videos);
                  }
                  else
                  {
                      throw new Exception(await response.Content.ReadAsStringAsync());
                  }
              }
          }
      
          public class YouTubeSearchResult
          {
              [DataMember(Name = "nextPageToken")]
              public string NextPageToken { get; set; }
              [DataMember(Name = "items")]
              public YouTubeSearchItemResult[] Items { get; set; }
          }
      
          public class YouTubeSearchItemResult
          {
              [DataMember(Name = "id")]
              public YouTubeVideoId Id { get; set; }
              [DataMember(Name = "snippet")]
              public YouTubeSnippet Snippet { get; set; }
          }
      
          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; }
              [DataMember(Name = "publishedAt")]
              public string PublishedAt { get; set; }
          }
      
          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; }
          }
      
          public class YouTubeThumbnail
          {
              [DataMember(Name = "url")]
              public string Url { get; set; }
          }
      
          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; }
              public DateTime PublishedAt { get; set; }
      
              public string PublishedDay
              {
                  get
                  {
                      var today = DateTime.Today;
                      var publishedDate = PublishedAt.Date;
                      var firstDayOfThisWeek = today.AddDays(CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek - today.DayOfWeek);
                      var firstDayOfLastWeek = firstDayOfThisWeek - TimeSpan.FromDays(7);
                      var firstDayOfTwoWeeksAgo = firstDayOfThisWeek - TimeSpan.FromDays(14);
                      var firstDayOfThreeWeeksAgo = firstDayOfThisWeek - TimeSpan.FromDays(21);
                      var firstDayOfThisMonth = new DateTime(today.Year, today.Month, 1);
                      var firstDayOfLastMonth = today.Month == 1 ? new DateTime(today.Year - 1, 12, 1) : new DateTime(today.Year, today.Month - 1, 1);
                      if (publishedDate == today)
                      {
                          return "Today";
                      }
                      else if (today.Subtract(publishedDate).TotalDays == 1)
                      {
                          return "Yesterday";
                      }
                      else if (publishedDate >= firstDayOfThisWeek)
                      {
                          return publishedDate.DayOfWeek.ToString();
                      }
                      else if (publishedDate >= firstDayOfLastWeek)
                      {
                          return "Last Week";
                      }
                      else if (publishedDate >= firstDayOfTwoWeeksAgo)
                      {
                          return "Two Weeks Ago";
                      }
                      else if (publishedDate >= firstDayOfThreeWeeksAgo)
                      {
                          return "Three Weeks Ago";
                      }
                      else if (publishedDate >= firstDayOfThisMonth)
                      {
                          return "This Month";
                      }
                      else if (publishedDate >= firstDayOfLastMonth)
                      {
                          return "Last Month";
                      }
                      else if (publishedDate >= new DateTime(today.Year, 1, 1))
                      {
                          return "This Year";
                      }
                      else if (publishedDate >= new DateTime(today.Year - 1, 1, 1))
                      {
                          return "Last Year";
                      }
                      else if (publishedDate >= new DateTime(today.Year - 1, 1, 1))
                      {
                          return "Two Years Ago";
                      }
                      else
                      {
                          return "Older";
                      }
                  }
              }
          }
      }
      

      Back to Top

    2. Right click the Pages folder, select Add | Razor page to add a new razor page, say OnDemand, and add the following code in the page to search a video from youtube using on-demand loading in ListView.
      Razor
      Copy Code
      @inject IJSRuntime JsRuntime
      @using System.Threading
      @using C1.Blazor.Core
      @using C1.Blazor.ListView
      @using C1.Blazor.Input
        
      <C1TextBox @bind-Text="Filter" Placeholder="Type here to search for videos on YouTube" Style="@("width:640px;margin:8px 0")" />
        
      <C1ListView @ref="list" ItemsSource="@videos" T="YouTubeVideo" ItemStyle="@("height:100px")" ItemTapped="OnItemTapped" LoadingItem="OnLoadingItem" Style="@("max-height:50vh")">
          <ItemTemplate Context="video">
              <table>
                  <tr>
                      <td rowspan="2"><img src="@video.Thumbnail" style="width:120px;height:80px" /> </td>
                      <td style="padding-left:4px;vertical-align:bottom">@video.Title</td>
                  </tr>
                  <tr>
                      <td style="padding-left:4px;font-size:small;color:dimgray;vertical-align:top">@video.ChannelTitle</td>
                  </tr>
              </table>
          </ItemTemplate>
      </C1ListView>
        
      @code
      {
          C1ListView<YouTubeVideo> list;
          string filterValue;
          YouTubeDataCollection videos = new YouTubeDataCollection();
          SemaphoreSlim filterSemaphore = new System.Threading.SemaphoreSlim(1);
        
          public string Filter
          {
              get
              {
                  return filterValue;
              }
              set
              {
                  filterValue = value;
                  OnFilterChanged(value);
              }
          }
          private async void OnFilterChanged(string filter)
          {
              Console.WriteLine($"OnTextChange({filterValue})");
              try
              {
                  filterValue = filter;
                  await Task.Delay(400);
                  await filterSemaphore.WaitAsync();
                  if (filterValue == filter)
                  {
                      await list.ChangeViewAsync(0);
                      await videos.SearchAsync(filterValue);
                  }
              }
              finally
              {
                  filterSemaphore.Release();
              }
          }
        
          private void OnItemTapped(object sender, ListViewInputEventArgs e)
          {
              var video = videos[e.Range.Row] as YouTubeVideo;
              if (video != null)
              {
                  JsRuntime.InvokeVoidAsync("open", video.Link, "_blank");
              }
          }
        
          private void OnLoadingItem(object sender, ListViewItemStyleEventArgs e)
          {
              e.ItemStyle["cursor"] = "pointer";
          }
      }
      

    Back to Top