Webからデータを取得するロジックが完成するまで、画面のデザインが確認できなくては困ってしまう。そこで、本来のロジックを使わずに、別途用意したダミーのデータを表示したい。また、VS 2013のXAMLデザイナで見られるようにもしたい。
その方法は、XAMLコードでデザイン時のデータをデータ・コンテキストに設定する方法によって、大きく2通りに分けられる(次の表)。
概要 | 説明 |
---|---|
d:DesignInstanceを使う方法 | DataContextの指定例: d:DataContext="{d:DesignInstance Type=data:SampleDataSource, IsDesignTimeCreatable=True}" 指定例の中の「SampleDataSource」クラスのコンストラクタでダミー・データを生成する。 VS 2012(Win 8アプリ)の[グリッド アプリケーション (XAML)]プロジェクト・テンプレートなどで使われている。 デザイン時と実行時で同じデータ生成コードが使われるので理解しやすい半面、デザイン時だけに使うにはコード量が増えるのが難点 |
d:DesignDataを使う方法 | DataContextの指定例: d:DataContext="{d:DesignData Source=SampleData.xaml}" d:DataContext="{d:DesignData Source=SampleData.json, Type=data:SampleDataSource}" ダミー・データのファイルを、デザイン時にVS 2013が直接読み込んでくれる。データのフォーマットとしては、XAMLとJSONが使える。上の例に示したように、JSONの場合はデータの型(=クラス名)を教える必要がある。VS 2013の[ハブ アプリ (XAML)]プロジェクト・テンプレートなどはこの方式で、JSONを利用している。また、Blend for Visual Studio 2013には、クラス定義からXAML形式のダミー・データを自動生成する機能がある*4。 デザイン時に使うだけなら、この方法が非常に便利だ。実行時にもダミー・データを使おうとすると自分でデータをデシリアライズするコードを書かねばならない |
デザイン時にダミー・データを表示する2通りの方法 |
*4 Blend for Visual Studio 2013でプロジェクトを開き、[データ]ウィンドウ(デフォルトでは右端にある)の上端のバーにあるアイコンのうち、右端から2番目をクリックするとドロップダウンが現れ、[新しいサンプル データ]と[クラスからのサンプル データの作成]という選択肢が提示される。[クラスからのサンプル データの作成]を選び、出てきたダイアログでデータのクラスを指定すると、XAML形式のダミー・データが自動生成される。
ここでは、JSONフォーマットでダミー・データを記述してみよう。ただ、残念なことに、VS 2013では文字コードがANSIのファイルしか利用できない*5。
プロジェクトに「SampleData」というフォルダを新しく作り、そこに新しい項目として[テキスト ファイル]*6を選んで「FeedsDataSample.json」と名前を付ける。ファイルができたら、そのプロパティで[ビルド アクション]を[コンテンツ]に変更しておく。
「FeedsDataSample.json」ファイルの内容は、次のコードのように記述する*7。
{
"Feeds":
[
{
"Title":"Insider.NET ¥u30D5¥u30A9¥u30FC¥u30E9¥u30E0",
"Items":
[
{
"Title":"Item Title 1",
"Link":"http:¥/¥/www.bluewatersoft.jp¥/",
"PubDate":"Fri, 18 Oct 2013 00:00:01 +0900"
},
{
"Title":"Item Title 2",
"Link":"http:¥/¥/www.bluewatersoft.jp¥/",
"PubDate":"Fri, 18 Oct 2013 00:00:02 +0900"
},
{
"Title":"Item Title 3 - long long long long long long long long title",
"Link":"http:¥/¥/www.bluewatersoft.jp¥/",
"PubDate":"Fri, 18 Oct 2013 00:00:03 +0900"
},
……省略("Item Title 4"〜"Item Title 9")……
{
"Title":"Item Title 10",
"Link":"http:¥/¥/www.bluewatersoft.jp¥/",
"PubDate":"Fri, 18 Oct 2013 00:00:10 +0900"
},
]
},
{
"Title":"Feed Title 2",
"Items":
[
{
"Title":"Item Title 2-1",
"Link":"http:¥/¥/www.bluewatersoft.jp¥/",
"PubDate":"Fri, 25 Oct 2013 00:00:01 +0900"
},
]
},
{
"Title":"FAVORITE",
"Items":
[
{
"Title":"Item Title 3-1",
"Link":"http:¥/¥/www.bluewatersoft.jp¥/",
"PubDate":"Fri, 1 Nov 2013 00:00:01 +0900"
},
]
},
]
}
このダミー・データをデザイン時に表示するのは、とても簡単だ(後述する)。実行時に表示するには、ちょっと工夫がいる(次項)。
*5 日本語は、例に示したように「\uNNNN」形式の文字コードで指定しなければならない。ただし筆者の環境では、d:DataContext属性の指定からType指定を削除すると、警告は出るもののなぜか正しく表示された。DataContractJsonSerializerクラス(System.Runtime.Serialization.Json名前空間)のReadObjectメソッドでデシリアライズする場合にはUNICODEの日本語が入っていても問題ないので、VS 2013の実装上の問題だと思われる。なお、XAMLでダミー・データを作る場合は、日本語をそのまま書いても大丈夫だ。
*6 [新しい項目の追加]ダイアログで[Visual C#]のレベルにある。その階層下の[コード]や[データ]のレベルには[テキスト ファイル]が存在しないので注意してほしい。
*7 JSONの書き方がよく分からない場合には、ハード・コーディングで簡単なデータを持つFeedsDataオブジェクトを生成して、それをシリアライズしてみるとよい。本稿では説明しないが、別途公開しているサンプル・コード(冒頭で紹介)のFeedsDataSampleクラスにその例を入れておく。
画面上のハード・コーディングをやめてデータ・バインドにすると、実行時には何も表示されなくなってしまう。もちろん、正式なロジックが完成したら、その結果を画面にデータ・バインドすればよい。しかしそれまでの間はダミー・データを実行時にも表示したいだろう。それには、自前でダミー・データをデシリアライズする仕組みを実装する。
プロジェクトの「DataModel」フォルダに新しいクラスとして「FeedsDataSample.cs」ファイルを作り、次のコードを記述する。
public class FeedsDataSample
{
// ダミー・データのファイル
const string SampleJsonFile = "ms-appx:///SampleData/FeedsDataSample.json";
// このクラスの唯一のインスタンス(ダミー・データは変化しないので1つだけ存在すればよい)
// なお、インスタンス生成時に、ダミー・データが読み込まれる
private static FeedsDataSample _theInstance = new FeedsDataSample();
// 【Dataプロパティ】FeedsDataSample.jsonファイルからのデータが入っているFeedsDataオブジェクト
public static FeedsData Data
{
get { return _theInstance._feedsData; }
}
private FeedsData _feedsData = new FeedsData();
// コンストラクタ:プライベートにして、外部からはインスタンスを作れないようにしてある
// スタティックなフィールド_theInstanceが、唯一のインスタンスになる
private FeedsDataSample()
{
LoadSampleData();
}
// ダミー・データを読み込み、デシリアライズする
private async void LoadSampleData()
{
// ファイルをテキストとして読み込み、byte配列に変換する
var storageFile
= await Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(new Uri(SampleJsonFile)); // ※
string jsonText = await Windows.Storage.FileIO.ReadTextAsync(storageFile); // ※
byte[] jsonBytes = Encoding.Unicode.GetBytes(jsonText);
// JSONのシリアライザを用意する
var serializer
= new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(FeedsData));
// byte配列をFeedsDataオブジェクトにデシリアライズする
FeedsData fd;
using (var sr = new System.IO.MemoryStream(jsonBytes))
fd = serializer.ReadObject(sr) as FeedsData;
// デシリアライズした結果をメンバ変数に格納する
foreach (var feed in fd.Feeds)
_feedsData.Feeds.Add(feed);
}
}
*8 async/awaitキーワードを使った非同期処理の記述:本連載ではC#の知識があることを前提としているので詳しく説明はしない。上のコードを大ざっぱに説明すると、最初のawaitキーワードの行でGetFileFromApplicationUriAsyncメソッドが別スレッドで処理を始め、それと同時にLoadSampleDataメソッドから呼び出し元に制御が戻る。そして、呼び出し元のその後の処理と、GetFileFromApplicationUriAsyncメソッドの処理が、同時に並行して行われる(=非同期)。GetFileFromApplicationUriAsyncメソッドの処理が完了すると、(呼び出し元でのその後の処理が継続中だった場合は割り込みが掛かって)awaitキーワードの続き(=storageFile変数への代入と、その次行以降の処理)が実行される。このようなasync/awaitキーワードを使った非同期処理の詳細については、「連載:C# 5.0&VB 11.0新機能「async/await非同期メソッド」入門」を参照してほしい。
*9 Windowsストア・アプリでのファイルの読み書きは、セキュリティやユーザーの個人的な情報を保護するという観点から、非常に複雑になっている。ファイルの存在場所によって読み書きできなかったり、できても読み書き方法が異なったりするのだ。インストールされたフォルダ配下のファイルを読み取る方法については、「WinRT/Metro TIPS:アプリに同梱したテキスト・ファイルを読むには?[Win 8/WP 8]」を参照してほしい。
Copyright© Digital Advantage Corp. All Rights Reserved.