連載
» 2013年11月01日 15時41分 公開

連載:Windowsストア・アプリ開発入門:第5回 データを画面に表示する (3/5)

[山本康彦(http://www.bluewatersoft.jp/),BluewaterSoft]

ダミー・データを作る

2通りの実装方法

 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フォーマットでデータを記述する

 ここでは、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"
        },
      ]
    },
  ]
}


ダミー・データの例(JSON)
ここで、JSONの記法を簡単に説明しておく。「:」の左側がオブジェクトの名前で、右側がオブジェクトの内容。複合オブジェクトの内容は「{」と「}」で括り、オブジェクト間を「,」で区切る。オブジェクトの配列は「[」と「]」で括り、やはり「,」で区切る。クラス定義とじっくり見比べてもらえば、同じ構造になっていると分かるだろう。
なお、最初の方に「\u30D5\u30A9\u30FC\u30E9\u30E0」と書いてあるが、これはUNICODEの文字コードを16進表記したもの(復元すると「フォーラム」となる)。前述したように文字コードにはANSIしか使えないので、日本語を使うにはこのようにする。
ところで、この例では全てのLinkのデータを同じにしてしまったが、正しく表示されることを確認するためには異なるデータにしておくべきである。

 このダミー・データをデザイン時に表示するのは、とても簡単だ(後述する)。実行時に表示するには、ちょっと工夫がいる(次項)。

*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);
  }
}

FeedsDataSampleクラス(C#)
上のダミー・データのファイルを読み込んで、FeedsDataオブジェクトにデシリアライズする。デシリアライズされたデータは、Dataプロパティで参照できる。このコードは、日本語を含むUTF-8で書かれたJSONファイルもOKだ。
なお、ファイルの読み込み処理(=コメントに「」印を付けた2行)にはawaitキーワードが使われており、非同期に実行される*8。そのため、初めてDataプロパティを参照したときにはまだデータは入っておらず、デシリアライズの処理が終わってからDataプロパティにデータが入ることになる(これは一見すると不便なようだが、アプリ起動時にユーザーを待たせることなく画面を表示できるというメリットがある)。
また、ファイルの読み込み処理のところには、GetFileFromApplicationUriAsyncメソッドという見慣れないメソッドが使ってある。プロジェクト内のコンテンツ(=インストールされたフォルダ配下に配置される)ファイルを読み取る場合にはこのようにしなければならない*9

*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.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。