始めよう!Silverlight

第6回Dynamic SilverlightでHello world

はじめに

前回はC#でのSilverlight 2の開発をご紹介しました。今回は.NET上で動的言語を実行するDynamic Language Runtime(DLR)をSilverlightで動かすためのDynamic Silverlightについてご紹介します。さらに今回はMacでの開発を試みます。

Dynamic Silverlightとは

最初に少し書きましたが、Dynamic Silverlight(DSL)とはDLRをSilverlightと統合し動作させるための技術です。DLRとは動的言語を処理するためのランタイムライブラリで、CLR上で動作します。DSLを使用することで様々な動的言語によってSilverlightのプログラミングを行うことが可能になります。

DSLでは現在、以下の3種類の言語が標準で提供されています。

  • IronPython
  • IronRuby
  • Managed JScript

今後はさらに様々なDLR上で動く言語が登場し、DSLでの言語の選択肢が増えていくことでしょう。

SDKの導入

DSLにはDSL用のSDKが用意されています。以下のサイトよりダウンロードしてください。

ダウンロードが完了したら、適当なフォルダに展開してください。このSDKには大きく分けて以下のものが含まれています。

  • DSLランタイムやIronRuby/IronPythonなどのアセンブリ
  • webサーバーとしての実行とxapの生成を行うChiron.exe
  • 上記のソースコード
  • サンプルアプリケーション

実は、ソースコードやサンプルアプリケーション以外のものは前回導入したSilverlight 2のSDKにも含まれています。さらに、ここにはDSLのSDKには含まれないManaged JScriptのアセンブリも含まれています。しかし、筆者の手元の環境で確かめたところ、微妙にアセンブリのバージョンが異なっていました。

  • Silverlight 2 SDKに含まれるバージョン = 2.0.5.0
  • DSL SDKに含まれるバージョン = 2.0.5.100

今回はDSLのSDKを使用して解説を行います。

開発ツールのChiron.exe

Chiron.exeとはSDKに含まれている開発用のコマンドラインツールです。おもに以下の機能を持っています。

  • 開発用の簡易的なWebサーバー
  • xapファイルの生成

DSLの開発ではChiron.exeを使用して、xapファイルの生成やサーバーを実行して、ブラウザでの動作確認を行います。以下のコマンドでChiron.exeに指定できる引数とその機能が表示されますので、ぜひ確認してみてください。

Chiron.exe -h

Macでの開発

Chiron.exeは.NET Frameworkのオープンソース実装であるMonoでも動作するように作成されています。MonoはMacでも動作します。つまりMonoでChiron.exeを動作させればMac上でDSLによる開発が可能になります。

本稿でもMacを使用して解説を行います。ただし、Windowsで開発した場合との違いはChiron.exeを実行する場合に、コマンドの先頭に"mono"と指定するかどうかだけなので、Windowsで試される場合も問題はありません。

1.Macで実行する場合
mono Chiron.exe -h
2.Windowsで実行する場合
Chiron.exe -h

Monoのダウンロードと導入は以下のサイトの手順に従って行ってください。

DSLのSDKもZIP形式で圧縮されているので、Macにもそのまま導入できます。適当なディレクトリに展開してください。MonoとDSLのSDKの両方とも導入が完了したら、以下のコマンドを実行してください。Chiron.exeの部分はフルパスが必要になりますので、適宜読み替えを行ってください。ヘルプが表示されれば成功です。

mono Chiron.exe -h

IronRubyでHello world

では、まずIronRubyでHello worldを表示してみます。まずはSilverlightをホストするHTMLを作成します。適当なディレクトリを作成して以下の内容をindex.htmlとして保存してください。

index.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
  <head>
    <title>Dynamic Silverlight Sample</title>
    <style type="text/css">
      html, body {
        height: 100%;
        overflow: auto;
      }
      body {
        padding: 0;
        margin: 0;
      }
      #silverlightControlHost {
        height: 100%;
      }
    </style>
  </head>
  <body>
    <div id="silverlightControlHost">
      <object data="data:application/x-silverlight," 
        type="application/x-silverlight-2-b1" 
        width="100%" height="100%">
        <param name="source" value="app.xap"/>
      </object>
    </div>
  </body>
</html>

続いては、いま作成したindex.htmlのおなじ階層にappディレクトリを作成します。そしてその中にapp.xamlというファイルを作成して、以下の内容を記述してください。

app.xaml
<UserControl
  xmlns=http://schemas.microsoft.com/client/2007
  xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
  x:Class="System.Windows.Controls.UserControl"
  x:Name="Page">
  <TextBlock x:Name="TextBlock1" Text="Hello world."
    FontSize="24" />
</UserControl>

これでひな形が完成しました。上記のindex.htmlとapp.xamlはあとで解説するIronPythonでもそのまま使います

では、IronRubyのコードを記述しましょう。app.xamlと同じディレクトリにapp.rbというファイル名で以下のIronRubyのコードを作成してください。

Include System::Windows
Include System::Windows::Controls

control = Application.current.load_root_visual UserControl.new, 'app.xaml'
control.find_name('TextBlock1').mouse_left_button_up do |sender,args|
  sender.text = 'Hello world for IronRuby!'
end

作成できたらターミナルでカレントディレクトリをindex.htmlと同じディレクトリにして以下のコマンドにより、Chiron.exeを実行してください。

mono Chiron.exe /b

以下のようなディレクトリの画面が表示ます。

画像

index.htmlのリンクを選択してください。作成したSilverlightアプリケーションが実行されます。

画像

ここで、⁠Hello world」の上でクリックしてときに、以下のように文字列が「Hello world for IronRuby!」に変わったら成功です。

画像

IronPythonでもHello world

前回からHello world続きですが、懲りずにIronPythonでもHello worldを表示してみます。

index.htmlとapp.xamlは上記のIronRubyのものをそのまま使用してください。また、実行までの手順もIronRubyの場合と同様です。違いはapp.rbがapp.pyに変わるだけです。以下の内容をapp.pyとして保存してください。

app.py
from System.Windows import Application
from System.Windows.Controls import UserControl

def OnClick(sender, args):
  sender.Text = "Hello world for IronPython!"

control = Application.Current.LoadRootVisual(UserControl(), "app.xaml")
control.TextBlock1.MouseLeftButtonDown += OnClick

では、Chironを /b のオプションを付けて起動してください。このとき、理由は後述しますが、app.rbはappディレクトリに無いようにしておいてください。

index.htmlのリンクを開いて、⁠Hello world」をクリックして、最終的に以下の画面が表示されたら成功です。

画像

IronRubyをもう少し簡単(?)

すこし、話がそれてしまいますがIronRubyがfindNameメソッドを用いてxamlのエレメントを取得していたのに対して、IronPytonで記述した場合は、名前をそのままプロパティのように指定して取得できました。こちらのほうがコードもシンプルで読みやすくなるので、IronRubyでも同様の操作が行えるように少し工夫してみます。

Rubyではmethod_missingという特殊なメソッドが定義されています。このメソッドは、呼び出したメソッドが定義されていなかった場合に呼び出されるメソッドになります。例えばcontrol.TextBlock1とした場合に、TextBlcok1メソッドは定義されていないのでmethod_missingが呼ばれます。そこで、通常の場合は例外が発行されます。このmethod_missingをオーバーライドして、引数に失敗したメソッド名が渡されるので、このメソッド名でfindNameした結果を返すようにします。

class FrameworkElement
  def method_missing(m)
    find_name(m.to_s.to_clr_string)
  end
end

FrameworkElementクラスでmethod_missingをオーバーライドしています。全体のコードは以下のようになります。

Include System::Windows
Include System::Windows::Controls

class FrameworkElement
  def method_missing(m)
    find_name(m.to_s.to_clr_string)
  end
end

control = Application.current.load_root_visual UserControl.new, 'app.xaml'
control.TextBlock1.mouse_left_button_up do |sender,args|
  sender.text = 'Hello world for IronRuby!'
end

アプリケーションが実行されるまで

さて、これでIronRubyでもIronPythonでも無事にHello worldを表示できて、動作させることができました。しかし、一点引っかかる部分がありませんか? おこなった手順としては以下です。

  1. index.htmlを作成
  2. app.xamlを作成
  3. app.rbもしくはapp.pyを作成
  4. Chiron.exe /b で実行

これらの手順のなかのどこにもxapファイルを作成する手順がありません。しかし、問題なく動作しています。しかもindex.htmlでapp.xapを指定しているにもかかわらずです。

実はChiron.exeを/bオプションのみで起動した場合、app.xapファイルは実ファイルとしてではなく、メモリ上で動的に作成して、クライアントにダウンロードしてるのです。またAppManifest.xamlも動的に作成しています。/bオプションのみの場合は、以下のように動作します。

  1. 読み込むxapファイルの拡張子を除いたファイル名のディレクトリを検索(今回の例ではapp)
  2. 1.のディレクトリの中のファイルの拡張子から判断して、含めるDLRのアセンブリを決定し、AppManifest.xamlを生成
  3. 1.のディレクトリと2.のAppManifest.xamlをxapファイルにパッケージング

上記で作成された、xapファイルがクライアントにダウンロードされて実行されることになります。

では、アプリケーションがどのスクリプトファイルから実行されるかはどう判断されているのでしょうか? スクリプトファイルが複数含まれる可能性もあるため、必ず判断が必要になります。

これは、DSLが判断しています。DSLは読み込んだxapファイルを展開して含まれるコードファイルの中からapp.拡張子のファイルを検索します。そして、見つかったファイルを最初に実行します。このときに複数の言語でおなじappというファイル名にしている場合に、DSLは例外を発生させます。これがIronPythonでHello worldを表示するときにapp.rbが無いようにしてくださいと書いた理由です。

このappという値を変更するにはSilverlightプラグインを生成するとのinitParamsにstartというキーで値を指定します。たとえば「test」という値に変更したい場合は以下のように指定します。

<param name="initParams" value="start=test" />

これらの内容はすべてソースコードから読み取ることができます。たしかにソースコードを読み込むことはなかなか大変なことですが、是非一度読んでみることをお勧めします。面白い事実を発見できるかもしれません。例えば、Chiron.exeに対してuriに/bye!を指定するとChiron.exeが終了するとか。

http://localhost:2060/bye!

次回予告

記事としては本当に簡単なコードしか書いていませんが、基本的にDSLだからSilverlightのどれそれの機能は使えないということはありません。DSLでも自由に開発が可能です。また、今回紹介した以外にもさまざまな機能があります。たとえば、違う言語同士が同じSilverlightアプリケーション上で動作して、さらに互いにやり取りができたりもします。このあたりの紹介はまた別の機会に譲りたいと思います。

さて次回は、開発には必須のSilverlightでの単体テストを取り上げたいと思います。

おすすめ記事

記事・ニュース一覧