ホワイトボードアプリケーション
前回に引き続きLive Framework SDKの.NET Kitを使用した開発です。今回は、サンプルアプリケーションとしてホワイトボードアプリケーションを作成します。アプリケーションを実行した画面は図1のようになります。機能はホワイトボードに見立てたウィンドウに黒色で手書きできるという単純なものですが、Live Frameworkを利用して手書きした内容をMeshサービス上へ保存し、同期・共有できるようにします。
本連載ではVisual Studio 2008と言語にVB.NETを使用します。無償のVisual Basic 2008 Express Editionでも同様の内容ものが作成できます。
WPFアプリケーションの作成
最初にホワイトボードアプリケーションの基本的な部分を作成します。Visual Studioを使用して、新しくWPFアプリケーションのプロジェクトを作成します(図2)。
プロジェクトの作成後、Live Framework SDKの.NET Kitのライブラリの参照を追加します。詳しくは、本連載の第4回を参照してください。
InkCanvas
手書きを実現するためInkCanvasというコントロールを使用します。InkCanvasはTablet PC等でスタイラスによる入力を行い、ジェスチャーや文字認識に使用されるコントロールですが、今回はこれをホワイトボードとして利用します。
まずは、プロジェクトにデフォルトで作成されているウィンドウにInkCanvasを配置しましょう。Window1.xamlに対して、直接XAMLの記述を編集します。「<InkCanvas />」という記述を追加したものが図3になります。
この時点で実行するとウィンドウに手書き入力することができます。実際に実行して確認してみましょう。入力により画面上に追加される線は、ひとつひとつが内部ではStrokeクラスのオブジェクトとして保持されています。
コードを記述しない状態で手書き入力が可能になり便利なコントロールですが、これだけでは線の削除もできず機能的に不十分ですので、少しだけコントロールとコードを記述して機能を追加します。
追加する内容は
および消しゴム選択から手書き入力に戻るための
とします。ここでは、ボタンを3個ウィンドウに配置し、ボタンクリック時に以上の各処理を行うよう実装します。
XAMLファイルを以下のように編集します。InkCanvasだけでなくボタンを追加し、Clickイベントの記述を行います。またInkCanvasをコードから参照するためMyInkCanvasという名前を付けています。
続いてボタンのClickイベント処理を記述します。ソリューションエクスプローラからWindow1.xaml.vbを選択してイベント処理のコードを追加します。
ペンと消しゴムの選択はInkCanvasのEditingModeプロパティを使用し、入力動作を指定します。このアプリケーションでは、ペンと消しゴムの動作としてInkCanvasEditingMode.InkとInkCanvasEditingMode.EraseByStrokeを指定することにします。コードは次のようになります。
このEditingModeで指定できる動作には、ほかにも線の選択や、書いた線の一部分を消す動作などがあります。
ホワイトボードのクリアは、InkCanvasが保持しているStrokeオブジェクトのコレクションをクリアします。コードは次のようになります。
以上でホワイトボードとしての処理部分は完了です。実際に実行して各ボタンが機能するか確認してみましょう。
ユーザー定義のデータ
さて、ここで前回までに紹介してきたLive FrameworkのMesh Objectについて、ユーザー定義のデータを読み書きする方法について紹介します。Mesh ObjectはMeshサービス上で同期する単位でリソースのひとつでした。Mesh Objectは、Data Feedというコレクションを持ち、さらにData Feedは、Data Entryというデータを表す最少単位のリソースのコレクションを指し示すことが可能です。
Mesh上へファイルを追加する方法は、第4回で少し紹介しています。この方法を使用するとData Entryへバイナリデータを追加することが可能です。
アプリケーションでバイナリデータを扱う場合はファイル追加のときと同様に処理すればよいですが、アプリケーションで使用する独自のクラスオブジェクトなどの保存には、もう少し便利なメソッドが用意されています。それが、SetUserDataメソッドとGetUserDataメソッドです。
SetUserDataとGetUserDataメソッドは、MeshObject.ResourceとDataEntry.Resourceにあるジェネリックメソッドです。Mesh ObjectまたはData Entryに対して型引数を指定して、クラスオブジェクトやプリミティブな値(StringやIntegerなど)の設定と取得ができます。
コード例を以下に示します。単純にString型の値をMesh Objectに設定および取得するには次のようになります。
続いて独自のクラスを設定する場合です。クラスオブジェクトの場合は、シリアラズ可能なもの(具体的には文字列や数値として表せるもの)に限られます。クラスオブジェクトを設定・取得する例を次に示します。以下のようなクラスを設定するものとします。
先ほどと同じようにこのクラスオブジェクトをMesh Objectのデータとして設定・取得するコードは次のようになります。
シリアライズ可能なものに限られますが、Live Frameworkを利用してアプリケーションのデータを保存や共有する場合、これらのメソッドは有用でしょう。本記事でもこのメソッドを使用してホワイトボードアプリケーションのデータを保存します。
Live Frameworkの利用
それでは、Live Frameworkを利用してホワイトボードアプリケーションへ入力されたStrokeオブジェクトをMesh上へ追加できるようにしてみましょう。今回作成するアプリケーションでは、InkCanvasへStrokeオブジェクトが追加されるたびに すべてのStroke情報をユーザー定義データとしてMesh Objectへ設定・更新するようにします。
LOEへ接続とMesh Objectの作成
最初にLive Operating Environment(LOE)の接続と、Stroke情報を保存するMesh Objectの作成を行います。いずれもウィンドウのLoadイベントで処理することにします。以下にコードを示します。
実用的なアプリケーションにするためには、ユーザーIDとパスワードの入力のためサインインウィンドウなどを用意する必要があるでしょうが、ここではコードに直接記述して済ませています。
上記コードでは、LOEに接続後、ホワイトボードアプリケーションのStroke情報を格納するためのMesh ObjectをMeshから取得しています。ない場合は新たにMesh Objectを作成しています。このときMesh ObjectとのResource.Typeには ほかのアプリケーションと重ならないような適当な値を指定しています。
Stroke情報の保存
InkCanvas.Strokesプロパティ(StrokeCollection型)のSaveメソッドを使用すると、StrokeのコレクションをISF(Ink Serialized Format)という形式で保存することができます。
ただ、この形式はバイナリデータですので少し工夫してStrokeコレクションをXML形式で保存できるようにします。実際に使用するコードは次のようになります。
入力されたStroke情報をMeshへ追加・更新するタイミングは、InkCanvasへStrokeが追加または削除されたときとします。これらのタイミングはStrokeCollectedイベントとStrokeErasedイベントで知ることができます。
XML形式にする部分をメソッド化しMesh Objectの更新処理を追加したコードを以下に示します。
クリアボタンをクリックしたときには上記のイベントは発生しないため、クリアボタンをクリックしたときの処理にもSetStrokesを呼ぶように変更しておきましょう。
以上で、ホワイトボードのStroke情報をMesh Objectへ保存できるようになりました。次は、Mesh Objectの内容からStroke情報を復元できるようにします。
Stroke情報の復元
Mesh ObjectにはXML形式の文字列としてStroke情報を保存していたので、文字列からStroke情報へ復元し、InkCanvasへ反映する作業が必要になります。以下にそのコードを示します。
明示的にMesh ObjectのLoadメソッドを呼び、最新の内容を取得しています。そして取得した文字列の値は、XamlReader.ParseメソッドおよびTryCastを使用してStrokeCollectionに変換しInkCanvasのStrokeコレクションに追加しています。
Stroke情報を復元するタイミングはアプリケーションの起動時とMesh Objectがほかのデバイスからなど外部要因で更新された場合です。起動時に処理するにはウィンドウのLoadイベントの最後にGetStrokesメソッドの呼び出しを追加ます。Mesh Objectの更新通知を受信するには、Mesh ObjectのChangeNotificationReceivedイベントを使用します。
更新通知の受信については前回に紹介していますので、そちらも参照して、より改良してみてください。
以上で今回作成するアプリケーションは完成です。実行してみて動作を確認してみてください。アプリケーションを終了し、再度起動したら前回のホワイトボードの内容が復元されましたか? 複数の場所でアプリケーションを起動するとホワイトボードの内容が同期されましたか?
おわりに
最後に作成したアプリケーションの動作について改良点などを補足しておきます。
実際にアプリケーションを実行してみて気づいたかもしれませんが、Mesh ObjectのUpdateやLoadメソッドなどネットワークの通信部分をすべて同期呼び出ししているため、時間がかかり快適なユーザーインターフェースとは言えません。UpdateやLoadメソッドには非同期呼び出しも用意されています。たとえばUpdateの場合はUpdateAsyncメソッドがあります。
非同期呼び出しをした場合Object型の引数を指定できます。アプリケーションで何らかの状態を管理する必要がある場合に利用します。非同期処理が完了を知るにはイベントを使用します。
非同期処理が完了するまで次の非同期処理のメソッドを呼ぶことはできません。そのため、今回のアプリケーションを単純にUpdate等のメソッドを非同期用のメソッドに置き換えるだけでは動きません。その点も踏まえてぜひ改良してみてください。
また、データの同期・共有はしていますが、現在はユーザー間の共有はできません。よりおもしろいアプリケーションにするには、ユーザー間でのデータ共有が重要になってきます。この点については次回以降でふれたいと思います。