ダウンロードしたコンテンツの読み込み(2)
フォントの読み込み
フォントをオンデマンドで動的に読み込むのは、アプリケーションの国際対応という面で大きな価値があります。東アジア言語のフォントの中にはサイズが25MBに及ぶものもあるという点を考えると、その有用性は明白です。WebClientクラスを使うと、追加フォントのダウンロードの進行状況を表示できます。追加フォントなどの利用に関して特に留意する必要があるのは、アプリケーションに含めるにはライセンスが必要な場合があるという点です。使用権や使用許諾を得たフォントであれば、コード7のような処理を使い、フォントをオンデマンドで取得できます。
private void RequestContent()
{
Uri address = new Uri("http://www.somedomain.com/somefont.TTF");
WebClient webClient = new WebClient();
webClient.OpenReadCompleted += new
OpenReadCompletedEventHandler(webClient_OpenReadCompleted);
webClient.OpenReadAsync(address); (1)
}
void webClient_OpenReadCompleted(object sender,
OpenReadCompletedEventArgs e)
{
FontSource fontSource = new FontSource(e.Result); (2)
myTextBlock.FontSource = fontSource; (3)
myTextBlock.FontFamily = new FontFamily("webdings");
}
このコードは、フォントを動的に取得してTextBlockオブジェクトに適用する例です。まず、OpenReadAsyncメソッドを使ってフォントのダウンロードを要求します(1)。フォントは一般にはバイナリファイルとして保存されているので、このような処理となります。このファイルの中身はStreamオブジェクトとしてダウンロードされます。Streamのダウンロードが完了したら、フォントを読み込みます。ここからの処理方法が要注目です。
フォントのダウンロードが完了したら、StreamオブジェクトをFontSourceオブジェクトに変換する必要があります。幸い、FontSourceクラスのコンストラクタにはStreamを渡せますので、ダウンロードしたStreamをFontSourceに変換するのは簡単です(2)。このFontSourceのインスタンスを、TextBlockまたはTextBoxのFontSourceプロパティに設定します。上のコードではTextBlockを使用しています(3)。FontSourceプロパティを設定したら、FontFamilyプロパティも忘れず設定してください。これが必要なのは、1つのフォントが複数の書体を持つことが多いからです。FontFamilyを設定すると、テキスト要素のフォントが変わります。
ここまでの例はすべて、1つずつの項目を動的に読み込む処理でした。しかし、複数の項目を同時に読み込むことが必要になるケースは多々あります。例えば、フォトアルバムの写真を表示するアプリケーションを作成する場合なら、アルバムに収録した複数の画像をまとめて表示することになるので、すべて同時に取得するのが理にかなっています。幸い、WebClientでは、圧縮ファイルもダウンロードできるので、そうした処理にも簡単に対応できます。
圧縮ファイルの読み込み
複数のファイルをひとまとまりにしてやり取りしやすくするには、圧縮ファイルが便利です。圧縮ファイルの中で最も広く利用され、Silverlightでもサポートしているのは、.zipファイルです。これはバイナリファイルですので、リモートサーバからオンデマンドでダウンロードするときにはOpenReadAsyncを使います。そして、ダウンロードしたStreamオブジェクトはStreamResourceInfoオブジェクトに読み込みます。WebClientでは圧縮ファイルを直接扱えないため、処理可能なStreamResourceInfoを利用するというわけです。その使用例をコード8に示します。
private void RequestContent()
{
Uri address =
new Uri("http://www.silverlightinaction.com/files.zip");
WebClient webClient = new WebClient();
webClient.OpenReadCompleted += new
OpenReadCompletedEventHandler(webClient_OpenReadCompleted);
webClient.OpenReadAsync(address, "man.png"); (1)
}
void webClient_OpenReadCompleted(object sender,
OpenReadCompletedEventArgs e)
{
Uri part = new Uri(Convert.ToString(e.UserState),
UriKind.Relative); (2)
StreamResourceInfo zipStream = (3)
new StreamResourceInfo(e.Result as Stream, null); (3)
StreamResourceInfo imageStream = (4)
Application.GetResourceStream(zipStream, part); (4)
BitmapImage image = new BitmapImage();
image.SetSource(imageStream.Stream);
myImage.Source = image;
}
このコードは、動的にダウンロードした圧縮ファイルの中から単一のファイルを抽出する例です。.zipファイルの要求はOpenReadAsyncで行います(1)。今回はここで、2つ目のパラメータを渡しています。このパラメータは「パート」ともいい、ダウンロードが完了した後で抽出するファイルを表します。このパラメータには任意のobjectを指定できるので、.zipファイルから複数のファイルを抽出したい場合にはstring[]を渡せばOKです。また、ファイル名の指定では、.zipファイル内での相対パスを指定できます。実際にファイルを取り出すときに有用です。
圧縮ファイルからのファイルの抽出は3つの手順で行います。具体的な処理はコード8で示したとおりですが、その概略を示すと次のようになります。
- 抽出対象となる部分を相対パスの
Uriとして取得する(2)。 - ダウンロードした
Streamオブジェクト(.zipファイル)をStreamResourceInfoのインスタンスに変換する(3)。 - 静的メソッドである
Application.GetResourceStreamメソッドを使って個々の部分を抽出する(4)。
以上の手順を経て、取得したコンテンツを自由に使用できます。このような概略をふまえたうえで、具体的な処理の実装方法について、1つずつ見ていくことにしましょう。
最初の処理は、抽出の対象となるファイルの特定です。つまり、「パート」として渡した部分のことで、これはOpenReadCompletedEventArgsパラメータのUserStateプロパティで取得できます。コード8の場合、UserStateプロパティの値は、OpenReadAsyncメソッドで渡した"man.png"です。前述のとおり、ここには任意のobjectを渡せますので、string[]を使って複数のファイルを取得する場合なら、ここでループなどによる対応が必要となります。必要性の有無に関係なく、最終的には個々のパートを相対パスのUriに変換し、ダウンロードした.zipファイルに対して適用できるようにする必要があります。
次の処理は、ダウンロードした.zipファイルの取得です。この.zipファイルは、OpenReadCompletedEventArgsパラメータのResultプロパティから取得できます。目的の部分を抽出するためには、このStreamをStreamResourceInfoに変換することが必要です。前述のとおり、WebClientクラスは.zipファイルを直接扱えないからです。StreamからStreamResourceInfoへの変換はデフォルトコンストラクタで実行できます。このコンストラクタでは、2番目のパラメータで、コンテンツのMIMEタイプを指定できます。.zipファイルの場合は、ここは単にnullでOKです。
最後の処理は、対象の部分を実際に抽出する処理です。ここでは、静的メソッドのApplication.GetResourceStreamを使い、.zipファイルから個別のファイルを抽出します。最初のパラメータには、.zipファイルを表すStreamResourceInfoを指定し、2番目のパラメータには、.zipファイル内のファイルを表す相対のUriを指定します。.zipファイル内にこのファイルがない場合は、IndexOutOfRangeExceptionがスローされます。このファイルがある場合は、StreamResourceInfoオブジェクトとして返され、適宜利用できます。
この3つの手順で、複数ファイルをグループ化した圧縮ファイルをオンデマンドで読み込む処理を簡単に実装できます。このように扱うファイルとしては、画像、メディアファイル、XAMLコンテンツなどが一般的です。さて、場合によっては、Silverlight Toolkitなどの追加的なUIコンポーネントを必要に応じてその場で取得することが必要になります。あるいは、複雑なアプリケーションロジックのダウンロードが必要になる場合もあります。こうしたものは、アプリケーションライブラリとして保存されているのが一般的です。そこで、WebClientクラスを使って追加的なアプリケーションモジュールを読み込む方法についても見ておくことにしましょう。
