読者です 読者をやめる 読者になる 読者になる

Xamarin 日本語情報

Xamarin(ザマリン) の代理店だったエクセルソフト田淵のブログです。主に Xamarin に関するエントリーをアップしていきます。(なるべく正しい有益な情報を掲載していきたいと考えていますが、このブログのエントリーは所属組織の公式見解ではありませんのでご注意ください)

Xamarin.Forms で最後まで表示すると動的にデータが増える ListView を作るには

こんにちは。エクセルソフトの田淵です。

ListView に動的に値を追加する方法をご紹介します。

2015/8/27
Xamarin.Forms で ListView を最後まで表示するとクルクルを表示してその間に処理をするには~その1~ - Xamarin 日本語情報
Xamarin.Forms で ListView を最後まで表示するとクルクルを表示してその間に処理をするには~その2~ - Xamarin 日本語情報
を追記しました。

ListView については Xamarin 公式ページの Working with ListView を一通り読んでいただきたいのですが、注意点というかハマりポイントが分かりましたので共有します。(WPF をやられている皆さんは周知の事実っぽいのが泣けますが)

ListView には ItemsSourceItemTemplate (任意) を指定します。ItemsSource には 配列List<T>, ObservableCollection<T> などを使用できます。私はご覧のとおりズブの素人のため List を主に使っていました。

上記の公式ページで

The above approach will populate the ListView with a list of strings. By default, ListView will call ToString and display the result in a TextCell for each row. To customize how data is displayed, see Cell Appearance.

Because ItemsSource has been sent to an array, the content will not update as the underlying list or array changes. If you want the ListView to automatically update as items are added, removed and changed in the underlying list, you'll need to use an ObservableCollection. ObservableCollection is defined in System.Collection.ObjectModel and is just like List, except that it can notify ListView of any changes:

とあるように、ListView をアップデートする必要がある場合は INotifyCollectionChanged が実装されている(@espresso3389 さんありがとうございます!) ObservableCollection を使いなさいということみたいです。

動きのサンプル

f:id:ytabuchi:20150812002700g:plain:w300

f:id:ytabuchi:20150812002734g:plain:w300

f:id:ytabuchi:20150812002919g:plain:w300

サンプルコード

GitHub

使い方(ListView の用意)

ということで前置きが長くなりましたが、使い方です。

まずは ListView を用意します。

C#:

// ListView のセルを定義します。
var cell = new DataTemplate(typeof(TextCell));
cell.SetBinding(TextCell.TextProperty, "TextItem");
cell.SetBinding(TextCell.DetailProperty, "DetailItem");

// ListView を定義します。
var list = new ListView
{
    ItemsSource = listItems,
    ItemTemplate = cell,
};

XAML:

<ListView x:Name="list"
            ItemsSource="{Binding}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <TextCell Text="{Binding TextItem}" Detail="{Binding DetailItem}" />
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

XAML のコードビハインドには this.BindingContext = listItems; を定義しておきます。

で、この ItemsSource の listItems を ObservableCollection で用意します。今回はサンプルなのでデータを順次追加してます。

using System.Collections.ObjectModel;

ObservableCollection<ListItem> listItems = new ObservableCollection<ListItem>();
void AddListItem(int i)
{
    foreach (var j in Enumerable.Range(i, cellAmount))
    {
        listItems.Add(new ListItem { TextItem = "TextData " + j, DetailItem = "DetailData " + j });
    }
}

使い方 (ItemAppearing のイベントハンドラーを用意)

ListView の ItemAppearing イベントは ListView の各 Item が表示された時に発生するイベントです。ここに、例えば listItems.Last() == e.Item as ListItem など最後が表示された時にデータを追加する処理を記述すれば OK です。後は(多分 ObservableCollection が ListView に NotifyChanged して) ListView が勝手に表示を更新してくれます。

list.ItemAppearing += (object sender, ItemVisibilityEventArgs e) => {
    // ObservableCollection の最後が ListView の Item と一致した時に ObservableCollection にデータを追加する処理を行いましょう。
    if (listItems.Last() == e.Item as ListItem)
    {
        // ObservableCollection にデータを追加する処理
        // ここでは n をインクリメントして cellAmount の 25 ずつデータを追加しています。
        n++;
        AddListItem(cellAmount * n);
    }
};

Twitter クライアントとかインターネットから Json を引っ張ってくるようなアプリではよく使う手法になるかと思います。

ちなみにですが、List<T> で ItemsSource を用意した場合は、List<T> を更新した後で、ItemsSource を再指定して、再度 ItemTemplate = new DataTemplate(typeof( して手動で ListView に更新を伝える必要があります。ちょっと面倒なのでなるべく ObservableCollection を使いたいですね。

Xamarin 気になった方は

いかがでしょうか。こんな簡単に Twitter とかでよく見るアレが実装できるなんて素晴らしいですね!笑

是非 ダウンロード(直接) / ダウンロード(弊社経由) して触ってみてください。 学習用リソースJXUG リンクページ に参考資料を纏めてますので併せてどうぞ。

Xamarin の情報が欲しい方はこのブログも購読いただいたりすると嬉しいです。

以上です。