# On-Demand Loading

ListView uses on-demand loading to load items as the user scrolls through the items and pages.

## Content



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](/componentone/api/blazor/online-blazor/dotnet-api/C1.DataCollection/C1.DataCollection.C1DataCollection-1.html). 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.<br />
    
    ```csharp
    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";
                    }
                }
            }
        }
    }
    ```
    
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
    @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";
        }
    }
    ```