ObservableCollectionの要素をItemTemplateでかっこよく見せたい

こんにちは鹿島です。
今週末に中間報告として研究の進み具合やらを書いて先生に提出する必要があるのですが、まあそれはそれは進捗がグエッ

というのは置いといて、やるべきことを残しておいてよいということには決してならないと思いますので、それ以上に私が残しているのが嫌なので手軽に書いてサクッと終わらせましょう。比較的今回の記事も短いですよ(当社比)。

WPFなりでListBoxに要素をバインドするというシチュエーションはよくあることかと思います。
でもListBoxにそのまま入れるとちゃんと見れない…stringでバインドするしか…?とかいうのはたいへん悲しいので任意型Tを持つObservableCollectionを表示していきましょう。

再びViewModel作ろうぜ!の話はしたくないので必要なら 最近書いた記事のほうをご参照ください。

ところでObservableCollectionって何?というのはhttps://msdn.microsoft.com/ja-jp/library/ms668604(v=vs.110).aspxを見ていただければ、見てもわからない、あっはい。
ViewModelの値変更を行ったことをUIに伝えるのにINotifyPropertyChangedを使ったことはご存じだと思いますが、あれは「このプロパティの値どっか変わったで!」しか言ってくれません。
ではこれをコレクションで行ってみましょう。要素数10万のコレクションに値を追加しました!おーっとUI選手どこが変わったかわからない! なんと最初からオブジェクトにアクセスし始めてしまいました!
とかいうどうでもいい話はさておき、オブジェクトの変更をINotifyPropertyChangedで通知するのは圧倒的に非効率です。そのためコレクションの変更通知にはINotifyCollectionChangedというものを使います。
INotifyCollectionChangedではどの位置にアイテムが追加されましたーとかアイテムが消えましたーとかを通知できます。これ以上の理解は面倒なだけなのでしなくていいです。
そしてINotifyCollectionChangedを実装した汎用的コレクションクラスがObservableCollectionというわけです。

なげえ!って方はバインドするコレクションにはObservableCollectionとでも思っておくとよいでしょう。

で、長くなりましたがListBoxにObservableCollectionをバインドしていきます。
ViewModelは以下のように作っていきます。

public class MainViewModel : INotifyPropertyChanged
{
    public ObservableCollection<MainListItem> ListItems { get; set; } = new ObservableCollection<MainListItem>();

    public event PropertyChangedEventHandler PropertyChanged;
}

public class MainListItem : INotifyPropertyChanged
{
    public MainListItem(string main, string sub)
    {
        this._mainText = main;
        this._subText = sub;
    }

    private string _mainText = "";
    public string MainText
    {
        get { return _mainText; }
        set
        {
            _mainText = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("MainText"));
        }
    }

    private string _subText = "";
    public string SubText
    {
        get { return _subText; }
        set
        {
            _subText = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SubText"));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

いろいろ冗長ですがまあいいです。
任意型を使うということでMainListItemとかいう謎クラスを使っていきます。MainTextとSubTextの二つのstringが持てます。

ListBoxはこんな感じにしていきましょう。

<ListBox ItemsSource="{Binding ListItems}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" HorizontalContentAlignment="Stretch" x:Name="listBox"  />

ListBoxとかへのコレクションのバインドにはItemsSourceを使います、というのだけ新しい情報かなぁ。
他のプロパティはTextWrappingするため用。

で、DataContextを設定したうえで実行するとこの通りです。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-11-15-15-49-41

とまあこれは当然の話なんですけどもたいへん残念ながら表示できません。
というのも表示する方法についても何も決めていないからですね。
ListBoxは既定ではobject.ToStringした値を使います、そしてToStringを実装していない。ここから導き出される結論とは…!

ん? じゃあToStringをオーバーライドしてやれば万事解決? それは正しいのですが話が終わってしまうので「MainTextとSubTextの二つを表示」することを目標とします。
(ついでに言うとToStringをオーバーライドしてしまうと値の変更ができない。)

そこでItemTemplateの出番というわけです。
ItemTemplateでは、各アイテムに対してどのようなUIを作るかを指定できます。
ListBoxの各アイテム部分にどのようなxamlを表示するかが指定できるわけですね。
よくわからない!という場合はTwitterのタイムラインを思い浮かべるとよいでしょう。ツイートオブジェクトに含まれている名前やら本文を決まった位置に表示するためのxamlが書けるよ!っていうようなのです。

説明が面倒になった百聞は一見になんとやらというので実際に作ってみましょう。
Visual StudioのXAMLデザイナーでListBoxを右クリックして”追加テンプレートの編集”→”生成されたアイテムの編集 (ItemTemplate)”→”空のアイテムの作成”を押しましょう。
次の画像のような位置です。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-11-15-15-53-37

適当に名前を付けたら生成されるDataTemplateなるやつの中のGridを次のように変更します。

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="1*" />
        <RowDefinition Height="1*" />
    </Grid.RowDefinitions>
    <TextBlock Text="{Binding MainText}" TextWrapping="Wrap" />
    <TextBlock Text="{Binding SubText}" TextWrapping="Wrap" Grid.Row="1" />
</Grid>

縦に積んでるだけですね。
DataTemplateの中では、ObservableCollectionのTの各要素がDataContextとして使用できます。なのでBindingを使う場合はTのプロパティが使えます。

これで実行するとこのようになります。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-11-16-20-18-20

というように縦に二つのプロパティの値が並びました。
特に初期化処理は書いていないので好きに指定した値が出るとは思います。

こんな感じでListBoxの各要素の見せ方もカスタマイズできるよ!というお話でした。
タイトルはかっこよく見せるはずなのに全然かっこよくない? 皆さんが作るのはかっこいいと信じてるので…きっと私のよりかっこいいので…。

それではまた

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Google フォト

Google アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中