さて、以上のメイン画面の変更により前回で実装した画面遷移が動かなくなっている。画面遷移を実装し直すとともに、今回はデータも渡すようにしてみよう。
「残りのセクションのデータ・バインド」で作り直したListViewコントロール(全部で3箇所ある)の開始タグに、イベント・ハンドラを追加する(次のコード)。
<ListView Width="500"
Tapped="ListViewItem_Tapped"
ItemsSource="{Binding Items}"
>
コードビハインドには、このイベント・ハンドラを処理するメソッドがすでにある(次のコード)。これは前回作成したものだ。
private void ListViewItem_Tapped(object sender, TappedRoutedEventArgs e)
{
//画面遷移(引数無し)
this.Frame.Navigate(typeof(ViewPage));
}
2つ目の画面への遷移が、これで再び動作するようになった。
Navigateメソッドの第2引数を使う。ただし、渡せるデータは文字列や数値などの基本型のみだ*11。
ユーザーがタップした項目に結び付けられているFeedItemオブジェクトをそのまま渡せればよいのだが、基本型しか渡せないので何か工夫が必要だ。主な選択肢は、次の2つ。
FeedItemオブジェクトが持つ情報は少ない(文字列のプロパティが3つだけ)ので、ここでは2番目の方法を使おう。次のコードのように、FeedItemオブジェクトの3つのプロパティ値をタブ文字で結合して、Navigateメソッドの第2引数として渡す。
private void ListViewItem_Tapped(object sender, TappedRoutedEventArgs e)
{
// 画面遷移(引数を渡すように変更)
// 第1引数は、イベントを送信してきたコントロール(=ListViewコントロール)
var lv = sender as ListView;
if (lv == null)
return;
// ListViewコントロールのSelectedItemプロパティには、データ・バインドされたFeedItemオブジェクトが入っている
var item = lv.SelectedItem as AtmarkItReader.DataModel.FeedItem;
if (item == null)
return;
// FeedItemオブジェクトのプロパティの値をタブ文字を区切りとして結合し、それを引数として画面遷移する
var param = string.Join("¥t", item.Title, item.Link, item.PubDate);
this.Frame.Navigate(typeof(ViewPage), param);
}
*11 Navigateメソッドの定義上は、どんなオブジェクトでも渡せる。基本型のみという制限は、プロジェクト・テンプレートに含まれているSuspensionManagerクラス(Commonフォルダ内の「SuspensionManage.cs」ファイル)によるものだ。アプリの中断時/再起動時にSuspensionManagerクラスがアプリの状態を保存/復元するのだが、そのときにシリアライズ/デシリアライズできる型でないといけないのだ。
さて、2つ目の画面の方は、渡されたデータを受け取るように変更する。受け取った文字列からFeedItemオブジェクトを生成して、画面のデータ・コンテキストにセットしてみよう(次のコード)。
private void navigationHelper_LoadState(object sender, LoadStateEventArgs e)
{
// 画面遷移するときに、引数としてTitle/Link/PubDateを渡してもらう
var param = e.NavigationParameter as string;
if (param == null)
return;
// 引数の文字列をバラして、FeedItemオブジェクトを作り直す
var paramArray = param.Split('¥t');
var item = new AtmarkItReader.DataModel.FeedItem(
title: paramArray[0],
link: paramArray[1],
pubDate: paramArray[2]
);
// FeedItemオブジェクトをデータ・コンテキストにセット
this.DataContext = item;
}
以上の変更で、2つ目の画面が表示されるときには、画面のデータ・コンテキストにFeedItemオブジェクトが入っているようになった。あとはデータ・バインドを使って画面に表示できる(次のコード)。
<!--<TextBlock x:Name="pageTitle" Text="{StaticResource AppName}"
Style="{StaticResource HeaderTextBlockStyle}" Grid.Column="1" IsHitTestVisible="false"
TextWrapping="NoWrap" VerticalAlignment="Bottom" Margin="0,0,30,40"/>-->
<!-- ↓バインディングに変更 -->
<TextBlock x:Name="pageTitle" Text="{Binding Title}"
Style="{StaticResource HeaderTextBlockStyle}" Grid.Column="1" IsHitTestVisible="false"
TextWrapping="NoWrap" VerticalAlignment="Bottom" Margin="0,0,30,40"/>
……省略……
<!--<WebView x:Name="webView1" Grid.Row="1"
Source="http://rss.rssad.jp/rss/artclk/2CqtlBidiijV/……省略……qL0QyMbww9"
/>-->
<!-- ↓バインディングに変更 -->
<WebView x:Name="webView1" Grid.Row="1"
Source="{Binding Link}"
/>
以上で今回の実装は完了だ。デザイン時に2つ目の画面のタイトルが表示されないが、必要ならばデザイン時データを画面に追加してほしい*12。
*12 これは読者のみなさんへの宿題としよう。ヒントとしては、「『データ・バインド』による方法」でやったようにしてTextBlockコントロールに「d:DataContext="仮のタイトル"」などとしてもダメだということ。なぜなら、今度は「{Binding Title}」としていて、データ・コンテキストの中の「Title」という名前のオブジェクトにバインドしているからだ。デザイン時データは、単純な文字列ではなく、「Title」という名前のオブジェクトを持ったオブジェクトにしないといけない(FeedItemオブジェクトにすれば後からも分かりやすいだろう)。別途公開するサンプル・コードには例を載せておく。
今回は、データ・バインドの基礎を学び、これまでに作った画面をデータ・バインドに変更した。そして、ダミーのデータを、デザイン時と実行時に表示させる方法も学んだ。また、画面遷移のときにデータを受け渡す実装をした。
次回は「データを取得して表示する」。WebサービスからRSSフィードを実際に取得して、画面に表示させてみる予定だ。いよいよアプリが形になってくる。
Copyright© Digital Advantage Corp. All Rights Reserved.