気楽なソフト工房

プログラミングについていろいろな記事を書いています。



mykonos2008

Author:mykonos2008
システムエンジニアとして働いている30代の会社員です。
仕事や趣味でプログラムを書いている方の役に立つ記事を書いていきたいと思っています。
ご意見、ご感想はこちらまで
If you are an english speaker,Please visit my english blog.

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
「Google App EngineとSilverlightによるゲストブックアプリ」の解説の第2弾です。

1回目の解説では、ユーザが入力した訪問記録をデータストアに保存するところまでを解説しました。
今回はデータストアから記録の一覧を抽出し、SilverlightのDataGridに表示するところを解説します。

データストアから訪問記録の一覧を取得する

「Google App Engine」のデータストアからデータを抽出する方法は大きく分けると
Query(SQLではない)とGQLの2通りあるのですが、今回はGQLの方を使用しました。

GQLはSQLと似た文法で記述するデータ抽出用の言語で、「GqlQuery」クラスを介して、実行することが
出来ます。

class Book(db.Model):
  handleName = db.StringProperty();
  comment = db.StringProperty();
  created = db.DateTimeProperty(auto_now_add=True);

class BookList(webapp.RequestHandler):
  def get(self):
    self.response.headers['Content-Type'] = 'text/xml'
    self.response.out.write('')
    self.response.out.write('')

    books = db.GqlQuery("SELECT * FROM Book ORDER BY created DESC LIMIT 100")
    for book in books:
      self.response.out.write('')
      self.response.out.write('%s' % book.handleName)
      self.response.out.write('%s' % book.comment)  ← %sは%の後に続く、文字列の値に置換されます。
      self.response.out.write('%s' % book.created)     C#のString.Format()と同じ役割をします。
      self.response.out.write('')

    self.response.out.write('')

「books = db.GqlQuery」をC#に慣れた方が見ると、dbクラスのGqlQueryメソッドを
コールしているように見えるのですが、実際はパッケージ「google.appengine.ext.db」に定義されている
GqlQueryクラスのインスタンスを生成しています。その戻り値をいきなりfor文で利用しているのは
どういう文法の仕組みなのか理解できません。おそらくC#でもあるようなインデクサを使っているのかと。。

GQL自体はSQLと非常に良く似ています。テーブル名の代わりにModelのクラス名(Book)を、
列名の代わりにModelクラスの属性(createdなど)を指定しています。

結果は、XML形式でクライアントに返します。

■XMLフォーマット

<BookList>
  <Books>
    <Book>
      <HandleName>ハンドル名</HandleName>
      <Comment>コメント</Comment>
      <Created>記録日時<Created>
    </Book>
  </Books>
</BookList>

SilverlightのDataGridに表示する

SilverlightでREST通信する方法は「Silverlight Tips」で紹介していますので、詳しくはそちらを参照していただきたいのですが、
XMLの形式がTipsより少し複雑になっているので、まず、その部分を少し説明します。

今回のXMLのフォーマットは、XML中に複数回出現する可能性がある[Book]要素を含んでいます。
そのため、デシリアライズして生成されるクラスも以下のように2つに分けて定義する必要があります。

    public class BookList
    {
        public Book[] Books { get; set; }
    }

    public class Book
    {
        public String HandleName { get; set; }
        public String Comment { get; set; }
        public String Created { get; set; }
    }

XMLとクラスの両方を見比べると対応していることが分かると思います。

[Page.xaml.cs]
  BookList bookList = null;

  using (StreamReader reader = new StreamReader(stream as Stream))
  {
      //※「System.Xml.Serialization.dll」を参照設定する必要がある
      XmlSerializer serializer = new XmlSerializer(typeof(BookList));

      //XMLからBookListクラスのインスタンスを生成する
      bookList = serializer.Deserialize(reader) as BookList;
      
      foreach (Book book in bookList.Books)
      {
          //UTCを日本時間に変更し、日時のフォーマットを変換する
          book.Created = String.Format("{0:F}", DateTime.Parse(book.Created).ToLocalTime());
      }
  }

デシリアライズの方法は、XMLのフォーマットが複雑になっても変わりません。
また、「Google App Engine」で扱われている時間はUTCなので、ローカルの時間に変更する処理を行っています。

さて、本題のDataGridを使用する方法なのですが、これについてはとても簡単です。

  //画面に取得した値を設定する
  _bookList.ItemsSource = bookList.Books;  ←[_bookList]はDataGridの変数名

「BookList」クラスに定義されている「Book」クラスの配列を
DataGridのItemSourceに設定するだけです。

ItemSourceには列挙できる(foreachできる)タイプのものであれば何でも指定できます。
今回みたいに配列を指定する方法が簡単だと思います。
列名には属性の名前が自動的に設定されます。(もちろん変更する方法もあります。)

バインドされるクラス(今回はBook)の属性の型がboolだったら、セルがチェックボックスになり、
それ以外だったら、TextBoxになります。

今度は「Silverlight」と「Google App Engine」を使った本格的な
アプリ開発にトライしてみたいと思います。

コメント

コメントの投稿

管理者にだけ表示を許可する

トラックバック

http://csfun.blog49.fc2.com/tb.php/39-026183cf

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。