none
gridviewへデータの取得方法 RRS feed

  • 質問

  • いつもお世話になっております。

    現在、VS2013、C#、XAMLでストアアプリの開発を行っております。

    webserviceを作成し、サーバ上のMysqlからデータの取得を行いJsonテキストを保持し

    jsonテキストからGridViewへ表示を行っております。

    データの取得は30件で現在は行っていますが、

    GridViewを横方向へスワイプ(フリック?)した際に追加で+30件とデータを取得したいと考えております。

    GridViewに表示されている最終項目をスワイプした際にデータの再取得を行いたいのですが

    イベントの取り方で行き詰ってしまいました。

    ご教授お願い致します。

    2015年3月26日 11:31

回答

  • GridViewのパネルにVirtualizingStackPanelを使うことで、各項目は表示される時に初めてデータが読み出されます。
    つまり、最終項目が画面に表示されるタイミングを使えばいいという事になります。
    このタイミングでデータを読みに行くことで画面に表示されるまでデータ取得を遅延させることができます。
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <GridView ItemsSource="{Binding}" Height="100">
            <GridView.ItemsPanel>
                <ItemsPanelTemplate>
                    <VirtualizingStackPanel Orientation="Horizontal" />
                </ItemsPanelTemplate>
            </GridView.ItemsPanel>
            <GridView.ItemTemplate>
                <DataTemplate>
                    <Border BorderBrush="Red" Margin="2" BorderThickness="1">
                        <Grid Width="100" VerticalAlignment="Stretch" >
                            <TextBlock Text="{Binding Text}"  />
                        </Grid>
                    </Border>
                </DataTemplate>
            </GridView.ItemTemplate>
        </GridView>
    </Grid>
    namespace App1
    {
        using System.ComponentModel;
        using System.Collections.ObjectModel;
    
        public sealed partial class MainPage : Page
        {
            //コレクション変更通知するためにObservableCollectionを使う
            ObservableCollection<Data> list = new ObservableCollection<Data>();
    
            public MainPage()
            {
                this.InitializeComponent();
    
                //ダミーのデータ(最初の読み出し判定用)
                //この段階ではまだ取得していないので空
                Data d = new Data();
                d.Request += d_Request;
                list.Add(d);
                this.DataContext = list;
            }
    
            async void d_Request(object sender, EventArgs e)
            {
                //データの読み出し要求があったら、非同期で読み込みを行う
                await System.Threading.Tasks.Task.Delay(TimeSpan.FromSeconds(1));
                Data d = (Data)sender;
                d.Text = DateTime.Now.ToString("HH:mm:ss");
                for (int i = 0; i < 29; i++)
                {
                    d = new Data();
                    d.Text = DateTime.Now.ToString("HH:mm:ss");
                    list.Add(d);
                }
    
                //最後に次の読み出し判定用のデータを追加しておく
                //次のデータが無いなら追加しない
                d = new Data();
                d.Request += d_Request;
                list.Add(d);
            }
        }
    
        class Data : INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;
            public event EventHandler<EventArgs> Request;
    
            protected void OnPropertyChanged(string name)
            {
                var pc = PropertyChanged;
                if (pc != null)
                {
                    pc(this, new PropertyChangedEventArgs(name));
                }
            }
    
            private bool _isRequested;
            public void OnRequest()
            {
                if (!_isRequested)
                {
                    _isRequested = true;
                    var r = Request;
                    if (r != null)
                    {//未収得ならリクエストエベントを発行
                        Request(this, EventArgs.Empty);
                    }
                }
            }
    
            public string Text
            {
                get
                {
                    //画面に表示されるタイミングでデータ読み込みが要求される
                    OnRequest();
                    return _Text;
                }
                set
                {
                    if (_Text != value)
                    {
                        _isRequested = true;
                        _Text = value;
                        OnPropertyChanged("Text");//読み込まれたことを通知する
                    }
                }
            }
            private string _Text="Empty";
        }
    }


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    2015年3月26日 12:43
  • > データの取得は30件で現在は行っています

    なぜそのようにしているのでしょう?
    全部を取ってくると通信に時間が掛かりすぎるということでしょうか?
    もしそうであるならば、エンドユーザーがGridViewをスライドさせるのを待つのではなく、30件ずつ取得してはGridViewのデータに追加するという処理をどんどんやってしまえば良いと考えます。

    GridViewは、グループ化しない限りは「UI の仮想化」を行いますので、子コントロールを多数インスタンス化してしまうことはありません。
    https://msdn.microsoft.com/ja-jp/library/windows/apps/xaml/hh780657.aspx

     
    それはさておき…、

    > GridViewに表示されている最終項目をスワイプした際にデータの再取得を行いたいのですが
    > イベントの取り方で行き詰ってしまいました。

    それには、最終項目が表示されたときにイベントが発生するような「仕掛け」を作り込めばよさそうです。

    Windows 8.0 向けになりますが、@okazuki 氏の「GridViewでの遅延読み込みのサンプル(Lazy loading sample)」が参考になると思います。


    biac [ http://bluewatersoft.cocolog-nifty.com/ ]

    2015年3月26日 12:46

すべての返信

  • GridViewのパネルにVirtualizingStackPanelを使うことで、各項目は表示される時に初めてデータが読み出されます。
    つまり、最終項目が画面に表示されるタイミングを使えばいいという事になります。
    このタイミングでデータを読みに行くことで画面に表示されるまでデータ取得を遅延させることができます。
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <GridView ItemsSource="{Binding}" Height="100">
            <GridView.ItemsPanel>
                <ItemsPanelTemplate>
                    <VirtualizingStackPanel Orientation="Horizontal" />
                </ItemsPanelTemplate>
            </GridView.ItemsPanel>
            <GridView.ItemTemplate>
                <DataTemplate>
                    <Border BorderBrush="Red" Margin="2" BorderThickness="1">
                        <Grid Width="100" VerticalAlignment="Stretch" >
                            <TextBlock Text="{Binding Text}"  />
                        </Grid>
                    </Border>
                </DataTemplate>
            </GridView.ItemTemplate>
        </GridView>
    </Grid>
    namespace App1
    {
        using System.ComponentModel;
        using System.Collections.ObjectModel;
    
        public sealed partial class MainPage : Page
        {
            //コレクション変更通知するためにObservableCollectionを使う
            ObservableCollection<Data> list = new ObservableCollection<Data>();
    
            public MainPage()
            {
                this.InitializeComponent();
    
                //ダミーのデータ(最初の読み出し判定用)
                //この段階ではまだ取得していないので空
                Data d = new Data();
                d.Request += d_Request;
                list.Add(d);
                this.DataContext = list;
            }
    
            async void d_Request(object sender, EventArgs e)
            {
                //データの読み出し要求があったら、非同期で読み込みを行う
                await System.Threading.Tasks.Task.Delay(TimeSpan.FromSeconds(1));
                Data d = (Data)sender;
                d.Text = DateTime.Now.ToString("HH:mm:ss");
                for (int i = 0; i < 29; i++)
                {
                    d = new Data();
                    d.Text = DateTime.Now.ToString("HH:mm:ss");
                    list.Add(d);
                }
    
                //最後に次の読み出し判定用のデータを追加しておく
                //次のデータが無いなら追加しない
                d = new Data();
                d.Request += d_Request;
                list.Add(d);
            }
        }
    
        class Data : INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;
            public event EventHandler<EventArgs> Request;
    
            protected void OnPropertyChanged(string name)
            {
                var pc = PropertyChanged;
                if (pc != null)
                {
                    pc(this, new PropertyChangedEventArgs(name));
                }
            }
    
            private bool _isRequested;
            public void OnRequest()
            {
                if (!_isRequested)
                {
                    _isRequested = true;
                    var r = Request;
                    if (r != null)
                    {//未収得ならリクエストエベントを発行
                        Request(this, EventArgs.Empty);
                    }
                }
            }
    
            public string Text
            {
                get
                {
                    //画面に表示されるタイミングでデータ読み込みが要求される
                    OnRequest();
                    return _Text;
                }
                set
                {
                    if (_Text != value)
                    {
                        _isRequested = true;
                        _Text = value;
                        OnPropertyChanged("Text");//読み込まれたことを通知する
                    }
                }
            }
            private string _Text="Empty";
        }
    }


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    2015年3月26日 12:43
  • > データの取得は30件で現在は行っています

    なぜそのようにしているのでしょう?
    全部を取ってくると通信に時間が掛かりすぎるということでしょうか?
    もしそうであるならば、エンドユーザーがGridViewをスライドさせるのを待つのではなく、30件ずつ取得してはGridViewのデータに追加するという処理をどんどんやってしまえば良いと考えます。

    GridViewは、グループ化しない限りは「UI の仮想化」を行いますので、子コントロールを多数インスタンス化してしまうことはありません。
    https://msdn.microsoft.com/ja-jp/library/windows/apps/xaml/hh780657.aspx

     
    それはさておき…、

    > GridViewに表示されている最終項目をスワイプした際にデータの再取得を行いたいのですが
    > イベントの取り方で行き詰ってしまいました。

    それには、最終項目が表示されたときにイベントが発生するような「仕掛け」を作り込めばよさそうです。

    Windows 8.0 向けになりますが、@okazuki 氏の「GridViewでの遅延読み込みのサンプル(Lazy loading sample)」が参考になると思います。


    biac [ http://bluewatersoft.cocolog-nifty.com/ ]

    2015年3月26日 12:46
  • ご回答有難うございました。

    何とか実装できそうです。

    2015年3月31日 5:46