Silverlightの基本機能
今回は、図1中の上部にある.NET Framework for Silverlightの部分を掘り下げて、Silverlightがどのように業務アプリケーションで利用できるかを解説していきます。
Silverlightと.NET Framework
Silverlightでは図1や表1で紹介したように、.NET Framework 2.0で登場したジェネリックや.NET Framework 3.5で登場したLINQといった.NET Frameworkの最新技術を使用してプログラミングを行うことができます。ここでは簡単に、業務アプリケーションで使用する上で役に立ちそうなSilverlightの基本機能について紹介します。
ジェネリック
「ジェネリック」は.NET Framework 2.0で導入された機能で総称型とも呼ばれます。
ジェネリックでは、型付けされたコレクションを簡単に利用できます。型付けされたコレクションを使うことで、予期しない型のインスタンスがコレクションを追加することができなくなるため、プログラムの堅牢性が向上し、不要なキャストが必要なくなるためコレクションの操作も高速になります。
リスト2では、wingsUsersというWingsUser型のコレクションを作成し要素を追加していますが、偽WingsUserはstring型のインスタンスであるため、コレクションに追加することはできません。
var wingsUsers = new List<WingsUser>{ new WingsUser { Name = "山田" }, new WingsUser { Name = "かるあ" }, }; wingsUsers.Add("偽WingsUser"); // コンパイルエラー
wingsUserがどんな型のインスタンスでも受け入れるコレクションだったらどうなるでしょう。プログラムコードでは、要素の一つ一つに対し、それが想定している型のインスタンスかをチェックし、キャストしてからアクセスする必要があります。ジェネリックを使うことで想定していない動作防ぐことができプログラムの堅牢性が向上します。
スレッド
ボタンがクリックされた際に、時間がかかる処理を行っているため、UIが操作を受け付けず固まったようなアプリケーションを見たことはありませんか? これはUIスレッドで時間のかかる処理を行っているため、UI側に処理が返却されないことが原因で起こる問題です。JavaScriptの場合、リスト3のようにsetTimeout
関数を使って疑似的にスレッドを表現します。
function button1_Click() { setTimeout(重い処理, 1); } function 重い処理() { // 重い処理 }
setTimeout
関数は指定時間後に定義した処理を実行する関数です。この場合、1ミリ秒後に重い処理()
を実行しますが、UIスレッド自体はbutton1_Click
メソッドを終了してUIに処理を戻しているため、重い処理()
が別スレッドで動作しているように見えます。
Silverlightでは.NET Frameworkのスレッドをサポートしているため、リスト4のようにBackgroundWorkerなどのクラスを使うことで簡単にスレッドに対応したアプリケーションを作成することができます。
private void Button_Click(object sender, RoutedEventArgs e) { var 重い処理を行うスレッド = new BackgroundWorker(); 重い処理を行うスレッド.DoWork += 重い処理; 重い処理を行うスレッド.RunWorkerAsync(); } private void 重い処理(object sender, DoWorkEventArgs e) { // 重い処理 }
スレッドによるプログラミングではUI要素へのアクセスで注意が必要です。WindowsFormではUIスレッド以外のスレッドからUIの要素にアクセスすることは禁止されていました。Silverlightも同様に、UIスレッド以外からUIの要素にアクセスすると、UnauthorizedAccessException例外が発生します。
WindowsFormアプリケーションでは、各コントロールに用意されているInvoke
メソッドを使って非同期に各コントロールにアクセスしますが、SilverlightではコントロールはInvoke
メソッドをサポートしていません。SilverlightでUIスレッド以外からUI要素にアクセスするためには、リスト5のようにScriptObjectが公開するDispatcher
プロパティのBeginInvoke
メソッドを使用してUI要素へアクセスします。
private void 重い処理(object sender, DoWorkEventArgs e) { // 重い処理 // UI への書き込み Dispatcher.BeginInvoke(delegate() { result.Text = "重い処理終了"; }); }
LINQ
LINQ(Language INtegrated Query)は.NET Framework 3.5で導入された機能で言語統合クエリとも呼ばれています。LINQでは、オブジェクトやXMLといったコレクションに対して検索や更新、オブジェクトの付け替えを簡単に行える機能が提供されています。
Silverlightはクライアント側の技術であるため、データベースに格納されたデータの表示、更新といった作業はサーバー側プログラムとの連携を行って実現する必要があります。このため、クライアント側にダウンロードしたデータの表示内容をカスタマイズしたり、キャッシュしたデータに対し再検索するといった機能が重要になります。
LINQを使用することで、ダウンロードしたオブジェクトに対する検索や、データの表示内容の変更といった作業をシンプルにコーディングすることができるようになります。
例えばリスト6では、GetUsers
メソッドがサーバーからユーザーの一覧を取得するメソッドだったとして、その後のコードで、習得したデータに対して再検索を行っています。
var serviceResult = GetUsers(); // 検索結果の再検索、並び替え var query1 = from user in serviceResult where user.Name.StartsWith("か") orderby user.Name ascending select user;
データグリッドを使った検索画面や、更新処理などのリストデータを扱うシナリオを考えた場合、サーバーとの通信で取得したデータに対し、検索や更新を行うことでパフォーマンスの向上を図ることができます。
実際のサーバーサイドアプリケーションとの連携に関しては次回以降の連載で詳しく解説します。
JSON形式のデータをサポート
JSON(JavaScript Object Notation)はJavaScriptにおけるデータの表現方法の一つです。例えば先ほど例に挙げたWingsUserの一覧をJSONではリスト7のように表すことができます。
var members = [ { name; '山田'}, { name: 'かるあ' }, ];
JSONでは、配列を[]で、オブジェクトを{}でそれぞれ定義します。
この場合、members変数にはnameというプロパティを持つオブジェクトの配列が格納されます。このようにJSONを使うことでシンプルな構文でデータ表現が行えるため、この頃ではXMLの代わりにJSONによるデータ表現を使ったWebServiceも増えています。
SilverlightではJSON形式のデータをCLR型にマッピングすることが可能です。
リスト8では、JSON形式で宣言されたオブジェクトをデシリアライズしてWingsUsreの配列にマッピングしています。
List<WingsUser> GetUser() { var textReader = new System.IO.StringReader( "[ { name: 'かるあ' }, { name : 'やまだ' } ]" ); var jsonData = (JsonArray)JsonArray.Load(textReader); var query = from member in jsonData select new WingsUser { Name = member["name"] }; return query.ToList(); }
JsonArray.Load
メソッドは、引数に渡されたストリームからJSON形式のデータをロードし、CLRの型にマッピングします。以降のプログラムではロードされたデータに対し、ディクショナリからデータを取り出してプログラミングを行います。
Load
メソッドで取得したデータに対しては、"name"などの文字列を使ってデータにアクセスする必要があるため、キーの指定間違いなどで実行時エラーが発生する可能性があります。JSONを使ったプログラミングでは、直接JsonArray型やJsonObject型に対してプログラミングをするのではなく、リスト8のように一度.NETのクラスにマッピングしてからデータにアクセスすることで、実行時エラーの範囲を小さくすることができます。