WinUI コントロール
仮想モード
コントロール > FlexGrid > パフォーマンス > 仮想モード

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)
            {
                //フィルタ文字列を設定し、遅延時間を待ちます
                _q = q;
                await Task.Delay(500);
                if (_q != q)//テキストが変更された場合は、別のキーが押されたことを意味します
                    return;
                try
                {
                    await _searchSemaphore.WaitAsync();
                    if (_q != q)//テキストが変更された場合は、別のキーが押されたことを意味します
                        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 code in the page to search a video from YouTube using on-demand loading in FlexGrid.

    <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>
    
     public sealed partial class OnDemand : Window
        {
            YouTubeDataCollection _dataCollection;
            public QuickStart()
            {
                this.InitializeComponent();
                _dataCollection = new YouTubeDataCollection() { PageSize = 10 };
                grid.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();
            }
        }