mikeo_410


Silverlightのリソースの分類

  リソースは意味の広い言葉ですが、プログラミング上はプログラムのコード以外の要素を指すものと思います。コード以外の要素は、データとリソースに分けて考えますが、区分は明瞭ではありません。
  リソースがどこにあって、どんな形式かがプログラミング上の問題ですが、Silverlightアプリケーションの開発では、ResourceDictionary と、リソースファイルに大別されるようです。

ResourceDictionary

  XAMLやコーディングの話題のリソースは、ResourceDictionary のことです。
  XAMLで、<Window.Resources>、<UserControl.Resources> や <Grid.Resources> のように、任意の場所に ResourceDictionary を作って、いろいろなものが格納できます。
  ビハンドコードでは、this.Resources などプロパティとして扱います。Addメソッドがあるので、ビハインドコードでもリソースを追加できます。文字列で表現されない BitmapImage なども追加できます。
  XAMLでの参照は、"{StaticResource res1}" のような記述で行います。
  このResourcesプロパティは、Application、Window、FrameworkElementにあり、表示スタイルの継承の機能を担っています。

リソースファイル

  SilverlightアプリケーションのビルドのターゲットはXAPです。これは、リンカの出力ではなく、フォルダを圧縮したパッケージです。パッケージには、リンカの出力であるDLL以外にファイルを含めることができます。

  通常 SilverlightアプリケーションもHTMLでホストされ、サーバからブラウザに送られます。
  HTMLで記述されたページの場合、イメージやスクリプトなどの参照は、サーバーからファイルをダウンロードすることで解決されます。
  Silverlightアプリケーションでも同様の動作が行われても不思議ではありません。つまり、パッケージ内のリソースファイルではなく、サーバー上にあるファイルを使うと言うことです。
  これをオンデマンドでのリソースファイルの読み込みと言うようです。

オンデマンドでのリソースファイルの読み込み

  HTMLのページの場合、ページの要素のイメージが表示される動作をオンデマンドは言わないと思いますが、Silverlightアプリケーションでは、HTTPでサーバからファイルを読み出すことはオンデマンドのようです。これは、Silverlightアプリケーションでは、パッケージ内のファイルを使うことが標準で、逐次ダウンロードすることは特別だからなのだと思います。
  イメージを表示する場合、プロジェクトにファイルを追加して以下のように記述すれば表示できます。

  1. <Grid x:Name="LayoutRoot" Background="White">
  2.     <Image Source="logo.png"/>
  3. </Grid>

  画像ファイルは、プロジェクトに追加すると、ビルドアクションがResourceとなっています。
  この場合、DLL内に格納され、Silverlightアプリケーションのダウンロードと共に、ブラウザに送られることになります。
  これに対して、以下のようなURLを記述すると、XAMLが評価される時にサーバーからイメージをダウンロードすることになり、オンデマンド動作になります。

  1. <Grid x:Name="LayoutRoot" Background="White">
  2.     <Image Source="http://localhost:4261/logo.png"/>
  3. </Grid>

  同様にURLで音声や動画などのリソースも扱えます。MediaElementのSourceにもURLが記述できます。

  表示コントロールをオンデマンドで読み込んでみます。
  押されたボタンで、ダウンロードするXAMLファイルを切り替えて表示を変えます。

  Silverlightアプリケーションと同じサーバに、2つの .xaml を置きます。
  この2つの .xaml には、赤い Ellipse と、青い Rectangle を記述して置きます。
  ボタンのクリックイベントで、一方を読み込んでインスタンスします。


夏_ctrl.xaml
  1. <Grid
  2.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  4.     <Ellipse Width="100" Height="100" Fill="Red"/>
  5. </Grid>
冬_ctrl.xaml
  1. <Grid
  2.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  4.     <Rectangle Width="100" Height="100" Fill="Blue"/>
  5. </Grid>
  以下のMainPage.xaml の grid1 の 子要素として表示します。

  1. <Grid x:Name="LayoutRoot">
  2. <StackPanel>
  3. <StackPanel Orientation="Horizontal" Name="stackpanel1">
  4. <Button Content="夏" Width="45" Click="夏_Click"/>
  5. <Button Content="冬" Width="45" Click="冬_Click"/>
  6. </StackPanel>
  7. <Grid Name="grid1"/>
  8. </StackPanel>
  9. </Grid>

  ビハインドコードは、以下です。

  1. void wc_DownloadStringCompleted(object sender, 
  2.                     DownloadStringCompletedEventArgs e)
  3. {
  4.     if (e.Error != null)
  5.         Debug.WriteLine(e.Error.Message);
  6.     else
  7.     {
  8.         UIElement rd = XamlReader.Load(e.Result) as UIElement;
  9.         grid1.Children.Clear();
  10.         grid1.Children.Add(rd);
  11.     }
  12. }
  13. private void 夏_Click(object sender, RoutedEventArgs e)
  14. {
  15.     WebClient wc = new WebClient();
  16.     wc.DownloadStringCompleted 
  17.         += new DownloadStringCompletedEventHandler(
  18.                 wc_DownloadStringCompleted);
  19.     wc.DownloadStringAsync(
  20.         new Uri("/夏_ctrl.xaml", UriKind.Relative));
  21. }
  22. private void 冬_Click(object sender, RoutedEventArgs e)
  23. {
  24.     WebClient wc = new WebClient();
  25.     wc.DownloadStringCompleted 
  26.         += new DownloadStringCompletedEventHandler(
  27.                 wc_DownloadStringCompleted);
  28.     wc.DownloadStringAsync(
  29.         new Uri("/冬_ctrl.xaml", UriKind.Relative));
  30. }

  以下のような ResourceDictionary を読み込むのは実行時にエラーになって上手く行きませんでした。

  1. <UserControl.Resources>
  2.     <ResourceDictionary>
  3.         <ResourceDictionary.MergedDictionaries>
  4.             <ResourceDictionary Source="http://localhost:4261/res.xaml"/>
  5.         </ResourceDictionary.MergedDictionaries>
  6.     </ResourceDictionary>
  7. </UserControl.Resources>

  他に、アセンブリ(DLL)をサーバに置くケースが考えられます。
  これには、一旦完成したパッケージからDLLを分離する方法と、はじめから別々に作成し、リンケージはリフレクションや interface を使う方法が考えられます。
  リフレクションを使った例を示します。
  まず、Silverlightクラスライブラリプロジェクトを作成します。Class1.csが作られますが削除します。
  このプロジェクトにSilverlightユーザコントロールを作成します。
  SilverlightControl1.xaml に矩形を描くように設定しました。
  ビハインドコードは何も手を加えませんでした。
  これをビルドすると、SilverlightClassLibrary1.dll ができました。
  これを、サーバに置きます。

  1. <Grid x:Name="LayoutRoot" Background="White">
  2.     <Rectangle Width="100" Height="100" Fill="Blue"/>
  3. </Grid>

  これを使用する Silverlightアプリケーションでは普通は参照追加をしますが、参照追加をすることはパッケージにSilverlightClassLibrary1.dll を含めることになります。したがって、ここでは参照追加をしません。
  MainPage.xaml には Loaded イベントハンドラを記述しておきます。
  ビハインドコードは以下のようにしました。

  1. private void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
  2. {
  3.     WebClient wc = new WebClient();
  4.     wc.OpenReadCompleted 
  5.         += new OpenReadCompletedEventHandler(wc_OpenReadCompleted);
  6.     wc.OpenReadAsync(new Uri("/SilverlightClassLibrary1.dll",UriKind.Relative));
  7. }
  8. void wc_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
  9. {
  10.     if (e.Error != null)
  11.         Debug.WriteLine(e.Error.Message);
  12.     else
  13.     {
  14.         AssemblyPart part = new AssemblyPart();
  15.         Assembly asm = part.Load(e.Result);
  16.         Type[] types=asm.GetTypes();
  17.         object oscl = types[0].InvokeMember(
  18.             null, BindingFlags.CreateInstance, null, asm, null);
  19.         LayoutRoot.Children.Add(oscl as UIElement);
  20.     }
  21. }

パッケージ内のリソース

  Visual Studio の プロジェクトに追加したファイルのプロパティには、「ビルドアクション」があります。
  ビルドアクションによって、独立したファイルやDLL内にリソースファイルが組み込まれます。
  いずれも組み込まれるのはプロジェクトに追加したファイルの単位で、プログラムではStreamとして扱うことになります。
  リソースの名前は、プロジェクトに追加したファイルの名前を含んだものになります。

  詳細は、「Silverlightのビルドアクションとリソース」を参照してください。


mikeo_410@hotmail.com