2013年2月12日火曜日

【WinRT】ListView(GridView)にボタンを配置


要するにSkyDriveの転送ポップアップの×ボタンみたいにしたいわけだ.
あのポップアップがListViewかどうかは置いといて.
SkyDriveのアップロードポップアップ


例としてこのSkyDriveと同じようにローカルからWebへの転送を考える.
DataContextを用いたデータバインドも説明するけどわかりづらいかもしれない.
本題の回答は最後に書いてある.

ここでボタンを押さずにリストクリックでキャンセル…なら,ListViewのItemClickイベントに任せるだけでOKだった.
ItemClickイベントではどのリストがクリックされたかを返してくれるし,そのリストにひもづけられたアイテムも得ることができた.
今回はListView内にボタンを配置し,ボタンクリックでキャンセル出来るようにする.

まずはListViewにバインドするためのアイテムクラスを作る.
つまりこのクラスのオブジェクト1つがListViewのビュー1つ分になる.

かなーり簡略化.必要なところのみ.
本来ならプログレスバー用パーセントだとか進捗(サイズ表記)だとか
現在転送待ちなのか転送中なのか転送完了なのか失敗済みなのか等というステータスだとか
キャンセルするメソッドにしてもステータスを確認してからキャンセルさせるだとかいろいろ必要だが
混乱のもとなので.

次にそのアイテムクラスをバインドするUIはListViewとして,
ListViewやGridViewにはItemTemplateといって各リストに対してテンプレートを適用させることができる.
ListViewを作ってやるとすると

このような感じで指定する.
そのListViewのテンプレート:ItemTemplateの引数TransferTemplateを作る.
今回はファイル名とボタンのみ作成するが,先にも述べたとおり
プログレスとかサイズとかの表記もあったほうが当然親切である.

そして,このUIクラスのソースコードの方で

こんなかんじでデータのバインドを行う.

AndroidからWinRT(WPF)へ来た時にこのDataContextというバインド方法が
とてつもなく便利に思えた一方で,
理解するのに時間がかかったし,多分未だにちゃんと理解できていない.

ここのDataContext = collectionがUI側では
ListViewのItemsSource={Binding}で受け止められる.
すなわち,
ObservableCollection <TransferItem> collection ⇒ ListView
となる.

ListViewでObservableCollection <TransferItem> collectionが展開されて,
たくさんのTransferItemオブジェクトが一つ一つのリストになる.

さて,TransferTemplateのButtonにも{Binding}があるが,
ListViewの{Binding}とは受け取る情報が違う.
ListViewの{Binding}は前述したとおり,ObservableCollection <TransferItem>を受け取っていたが,
TransferTemplateのButtonにつけた{Binding}はListViewで展開された一つのTransferItemを受け取る.

つまり,ButtonのTagフィールドにはTransferItemのオブジェクトが代入される
DataTemplate下でのBindingはListViewに与えたリストを展開した(Foreach?)1つ分である.
Tagフィールドはobjectクラスのフィールドで,なんでも適当に入れていいよという程度に捉えている.

TextBlockの{Binding Name}ではTransferItem.Nameが代入される
ListViewで展開されたTransferItemのNameフィールドが入れられるということ.

{Binding}がキモで,場所場所に依って何を指すかが変わってくるが,
理解出来ればCSファイル上で代入しなくてすむため,強力なツールとなる.


話を本題に戻して,
ButtonにつけたTagフィールドが今回の解決法で
クリックした時のイベントButton_Clickedメソッドで
このように記述するとボタンクリックでキャンセルさせることができる.

多少可読性は下がるが一行でこう書ける.

0 件のコメント:

コメントを投稿