秘密結社ぎゅう☆ぎゅう倶楽部でタグ「Silverlight」が付けられているもの

 何かとお世話になるDispacher.BeginInvokeですが、DispacherプロパティはDependencyObjectのメンバーであるため、DependencyObjectを継承していないクラスなどでBeginInvokeを使いたくなった時に困ってしまうことがしょっちゅう...というほどではありませんが、極稀にあります。
 「そもそも設計が間違っている」というご指摘には、「ごもっともです」と深くうなだれるより他にありませんが、絶対に無理かというとそうでもなく、それが正しい解法なのかどうかはともかくとして、とりあえず何とかなってしまったりします。

Deployment.Current.Dispacher.BeginInvoke

 余りにもブログを更新していなかったので、昔の下書きにちょっと手を入れてそのまま公開してみました。
 そのため、自分でも上記内容がほんとうに正しいのかどうか確信が持てない状況ですので、良い子は決して真似しないよう、くれぐれもよろしくお願いいたします。

 残念ながらできません。

 アプリケーション起動時にIsolatedStorage内のデータを読み込んで削除し、終了時に再度すべて保存し直すという方法も検討しましたが、コントロールパネルからアンインストールされた際には結局データが残ってしまいますし、アプリケーションが正常終了しなかった場合に全保存データが失われてしまうというリスクもあるため、今回は実装を見合わせました。

 これは是非なんとかして欲しいんですが、Silverlight5ではどうなってるんでしょう?

 Windows7で高DPI設定にした時だけ、OOB(Out-of-browser)アプリケーションウインドウ内のコンテンツが、ウインドウからはみ出してしまうという現象が発生してしまいました。
 DPIの変更自体にはXPから対応しているのですが、どうしてWindows7でだけ問題が生じるのですか?ボクカナシイ

 特別な設定でしか発生しない現象なら、別に対応しなくても良いよね!なんて思っていたのですが、聞いたところによると、標準で125%(120DPI)に設定されているPCもあるとかで、仕方なく調査に乗り出したのでした。(第一部・完)

 最初は、ものすごく面倒な対応を強いられるのではないかと思っていたのですが(全コントロールのサイズをDPI比から算出して再設定するとか)、調査をはじめて三日目の晩、実家の茶の間に飾られた白黒写真でしか見たことのない曽祖父が夢枕に立ち、「SettingsクラスのEnableAutoZoom プロパティ」と呟いたところではっと目が覚めた僕は、早速以下の一行をAppクラスのコンストラクタに追記してみました。

Host.Settings.EnableAutoZoom = false;

 上記の一行加えただけで、見た目は標準のDPI(96DPI)設定時と同じように表示されるようになり、動作上も今のところは特に問題なさそうです。

 本当はちゃんと解像度設定に従うような実装を心がけるべきなんでしょうが、今さらもうどうしようもない!なんて時はとりあえずこんな感じで対応するのもやむなしってことで、僕は引き続き「マルマルモリモリ」の振り付けを覚える仕事に戻りたいと思います。

 ホントは環境による処理の振り分けなんてしたくはないんですが、Silverlight側のバグへの対応という話になると、そう悠長なことも言っていられません。

 兄ちゃん、なんでMacの時だけWebBrowserコントロール消えてしまうん?

 ということで、Macの時だけ力技で対応することにしたのですが、Macかどうかの判定は以下のように行なっています。

if (Environment.OSVersion.Platform == PlatformID.MacOSX)
{
  // Macだけの処理
}

 本当にちなみにですが、MacでWebBrowserが消えてしまう(再描画されない)不具合への対応方法は、こちらのページを参考にしました。

 GIF画像の表示くらい普通に対応してくれればいいのにー!
 なんて文句を言っていても仕方が無いので、MS謹製ライブラリ「ImageTools」を使ってGIF画像を表示することにしたのですが、つまらないことで少しだけはまってしまったのでメモ。
 ImageToolsの入手は以下の公式サイトから。ライセンスはMs-PLです。
 http://imagetools.codeplex.com/

/*
▼AddReferencesが必要なDLL
ImageTools.dll // 当然必要なライブラリ本体
ImageTools.IO.Gif.dll // これを忘れる人はいないでしょう
ImageTools.IO.Png.dll // これが必要だと気づかずにはまった
ImageTools.Utils.dll // ToBitmapするのに必要
*/

// 初期化の際に一度だけ必要な処理
ImageTools.IO.Decoders.AddDecoder<GifDecoder>();

ExtendedImage eximg = new ExtendedImage();
// GIF画像読み込み完了時の処理
eximg.LoadingCompleted += (sender, args) =>
{
 Dispatcher.BeginInvoke(() =>
 {
  // image = XAML側に配置してあるImage
  image.Source = eximg.ToBitmap();
 });
};
// GIF画像読み込み開始
eximg.UriSource = new Uri("http://hoge.com/foo.gif", UriKind.Absolute);

 サーバからのデータ取得を行うたびに、IEのメモリ使用量が増えて行くという現象が発生してしまっていたので、SilverlightのメモリリークについてGoogle先生と一緒にいろいろ調べてみました。
 以下はその時に試してみた方法のメモですが、内容については無保証ですので(このブログのエントリー全てそうですがw)、試される方は自己責任でお願い致します。

Silverlight application memory leaks detector

リークが発生しているかを確認したいクラスのコンストラクタで

MemoryProfiler.AddReference(this);
を呼び出せば、MemoryProfiler.checkを呼び出すことによって、使用メモリと、メモリ上に残っているAddRefferenceしたオブジェクトのインスタンス数を確認することができます。

Silverlight Spy

 Silverlightアプリケーションのメモリ使用量を含む、さまざまなデータを参照することができます。99ユーロ(個人使用なら69ユーロ)はちょっと高いけど、会社で買ってくれるっていうなら有ってもいいかも。

Finding Memory Leaks In Silverlight With WinDbg

 Microsoftが提供しているデバッグツール"WinDbg"(32bit版/64bit版)を使用した、Silverlightのメモリリーク検出方法。
 手順を簡単にメモ。

  1. IE上でSilverlightアプリケーションを起動
  2. WinDbgを起動する(スタート→プログラム→Debugging Tools for Windows)
  3. WinDbgのメニューから[File]→[Attach to a Process]を選択し、プロセス一覧から"iexplore.exe"を選択してOKをクリック
  4. 画面下部のコマンド入力欄に以下のコマンドを入力してsos.dllをロード
    .load C:\\Program Files\\Microsoft Silverlight\\3.0.40818.0\\sos.dll
    (※ パスは環境によって変わります/※2 先頭の"."を忘れずに)
  5. 以下のコマンドで、Silverlightアプリケーション内のインスタンス名、数、使用メモリが一覧表示されます。("SilverlightApplicationName"の部分は適宜編集してください)
    !dumpheap -stat -type SilverlightApplicationName
 あとはメニューのDebugから、Go→Break→一覧表示を繰り返して、メモリリークの原因を突き止めましょう。
 さらに詳しい情報はこことかこことか。

【 結 論 】
メモリリークはなくてもブラウザのメモリ使用量は時間とともに増加する...らしい?

 DateTimeクラスのTicksプロパティは、0001年1月1日00:00:00からの経過時間を100ナノ秒単位で返してくれる便利な奴ですが、ミリ秒程度ならともかく、マイクロ秒を飛ばしていきなり「ナノ秒」なんて言われても、ぱっと計算できるものではありません。

 ということで、100ナノ秒単位で返って来る値を秒単位に変換する計算式(というほどでもないけどw)をメモ。

int seconds = DateTime.Now.Ticks / 10000000;

 やっとSilverlight3に触っています。

 最近すっかりJQueryにはまっている会長です。
 かつてのブラウザ&OS依存により、JavaScript1.2だかなんだかあたりの某案件以来、極度のJavaScript嫌いに陥っていた僕ですが、必要に迫られて使うことになったJQueryのおかげで、今ではすっかりJavaScriptが楽しくて仕方がありません。
 とりあえず、このブログにも、JQueryだけでも入れちゃっておこうかな。

 というどうでもいい話はさておき、Silverlightコンテンツから、POST送信によるページ遷移を行う必要に迫られ、いろいろ調べてみたのですが、POSTリクエストを送信する方法はたくさん見つかったのですが、ページ遷移となるとなかなか情報が見つからなくて、途方に暮れていました。
 そんな中、ふと思いついて試してみた方法が、予想以上にうまくいってしまいました。
 もしかしたら、他にちゃんとした方法があるのかもしれませんが、同じ疑問を持っている方の参考になればと思い、以下にその方法を記録しておこうと思います。
 もし間違っていたりしたら、親切な誰かが、正しい方法を教えてくれるしね(^^;

 Flex等では、"System.gc()"を呼び出すことによって、強制的にガベージコレクションを実行することができますが、Silverlightにはそういうのないのかな、と思っていたら、ちゃんと存在していたんですね。

GC.Collect();

 呼び出しはたったのこれだけ。
 パフォーマンスが著しく低下するから、呼び出さない方が良いよ、なんて言われても、どうしても呼び出したい時というのはあるものです。
 でも、くれぐれも使いどころにはお気を付けください。

 もう書いたと思っていたのにエントリーが見当たらなかったので改めてメモ。
 方法自体はとっても簡単なのでとりあえずソースだけ。

StreamResourceInfo sri =
 App.GetResourceStream(new Uri("/assemblyName;component/filename.jpg", UriKind.Relative));
BitmapImage bi = new BitmapImage();
bi.SetSource(sri.Stream);
Image img = new Image(){ Source = bi };

 見難くてごめんなさい。

 とあるアプリケーションが、MacのSafariで正常に動作しないという報告がクライアントからありました。

 多少条件判定処理が多いくらいで、それ以外はどう考えてもごくごく普通の処理をしているだけの個所なのに、確かに動作がおかしかったので、前回のエントリーで書いたSilverlightとJavaScriptの連携を使ってログを吐きつつ調査をしてみたところ、恐ろしいことに気づいてしまいました。

 double型って==演算子で比較しちゃダメなの?(´・ω・`)

 明らかに等しいdouble値の==演算子の比較が常にfalseになっているようだったので、試しにEqualsで比較するようにしてみたら、正常に動作するようになりました。
 確かにEqualsメソッドもあるけど、別に==で比較しても良いんじゃないの?ヽ(`Д´)ノ
 何も明らかに等しい値を、しかもMacのSafariだけでスルーしなくても良いと思う(´;ω;`)

 ということで、今後はdouble型の比較には、==演算子じゃなくてEqualsメソッドを使いましょう、というお話しでした。

 でも忘れちゃいそうだなー( ;^ω^)

 SilverlightアプリケーションからアプリケーションをホストしているHTMLファイルに記述されたJavaScriptのファンクションを呼び出す方法はこんな感じ。

ScriptObject jsFunction =
  (ScriptObject)HtmlPage.Window.GetProperty("jsFunctionName");
if(jsFunction != null)
{
  jsFunction .InvokeSelf(parameter);
}

 引数を問題なく渡せることは確認しましたが、どんな型が渡せるのかとか、返り値もちゃんと渡って来るのかとか、外部JSファイルのファンクションはどうなんだ、とかいうのはまだ試していません。
 JavaScriptからSilverlightアプリケーション内のメソッドを呼び出すこともできるのですが、それはまた次回。

 これまで、XMLファイルをWebClientで読み込む処理は結構あったのですが、XAP内に同梱されたXMLを読み込んだことはなかったので、最初はどうすればいいかちょっと悩んでしまいました。
 でも方法さえわかってしまえばとっても簡単。

 プロジェクトにXMLファイルを追加して、"Build Action"を"Content"に設定してしまえば、あとは以下のような感じで読み込むことができます。

//data.xmlがSilverlightプロジェクト直下に配置されている場合
XmlReader reader = XmlReader.Create("data.xml");

 僕の場合は、この後XDocument.Load(reader)して、LINQ to XMLでモニャモニャすることが多いです。

 何かと便利なSilverlight.jsのリファレンスと、最新版の入手先と、さらに、いつか必要になりそうなSilverlight.supportedUserAgent.jsなんてものも発見したので併せてメモ。

■Silverlight.js

・最新版ダウンロード
http://code.msdn.microsoft.com/silverlightjs
・日本語版リファレンス
http://msdn.microsoft.com/ja-jp/library/cc838126(VS.95).aspx

■Silverlight.supportedUserAgent.js

・最新版ダウンロード
http://code.msdn.microsoft.com/SLsupportedUA

Silverlightで自分自身の絶対URIを取得するために使用するプロパティ。

▽XAPファイルの絶対URI
Application.Current.Host.Source.AbsoluteUri

▽HTMLファイルの絶対URI
HtmlPage.Document.DocumentUri.AbsoluteUri

 数値を表す文字列を数値に変換したい場合は、各数値型クラスのスタティックメソッド「Parse」を使用すれば良いわけですが、文字列が"FFFF"とか"F3C8"(←これにピンと来た人はおっさん)みたいに、16進数表記だった場合はどうすればいいんだろうという部分で行き詰まってしまいました。

 最初は、VBのValやCInt的なノリで、int.Parse("0xFF");とかやってみたのですが、残念ながらうまくいかず、調べたところ、オーバーロードされたParseの第二引数"NumberStyles"に秘密があったようです。
 いろいろなスタイルを指定できるようですが、16進数表記の文字列を変換する場合は、"NumberStyles.AllowHexSpecifier"を指定すれば良いようです。

int num = int.Parse("FF",NumberStyles.AllowHexSpecifier);

 上記の例でわかる通り、文字列には16進数を表す"0x"などを付けてはいけません。

 XAMLのサンプルはいろいろなところで見つかったのですが、C#のコードで直接追加する方法がなかなか見つからなかったのでメモしておきます。
 見つけるまでは多少手間取りましたが、見つけてしまえば方法自体はいたって簡単です。

ToolTipService.SetToolTip(targetObject,
             new TextBlock() { Text = "秘密結社ぎゅう☆ぎゅう倶楽部" });

 次に調べなければならないのは、ツールチップのスタイルのカスタマイズ方法です。
 WPFでXAMLを使用したサンプルを見つけたので、こちらもとりあえずメモ。

 WPF Custom ToolTip Example(theWPFblog

 あるタイミングで、Ctrl キー、Shift キー、Alt キーなどの修飾キーの状態を取得したいというのは良くあることですが、SilverlightではKeyboard.Modifiersを使用して、上記の情報を得ることが出来ます。
 Shiftキーの状態を取得する場合は、C#だとこんな感じ

using System.Windows.Input;
...
if ((Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift)
{
  //Shiftキーが押されていた時の処理
}

 やっと本格的にSilverlight2に携わることになりましたが、Silverlight以前にC#での開発自体がほぼ初めてなので、だいぶ苦戦しています。

 ちょっと油断している間に、Silverlight2β2が公開されていました。

 ランタイムライブラリの他に、Visual Studio 2008 用 Microsoft Silverlight Tools Beta 2(silverlight_chainer) 、Silverlight SDKと、XAMLを作成する上で欠かせないExpression Blendが併せて公開されています。

 早速ダウンロードしてインストールしてみたところ、ランタイムライブラリとBlendは問題なかったのですが、VisualStudioでSilverlightプロジェクトを新規作成したり、既存のプロジェクトを開こうとすると、エラーメッセージが表示されるようになってしまいました。

 明日またいろいろと試してみようと思います。

 ということで早速ですが「裏」です。
 といってもまだテスト用エントリーですが。

 テストついでに「裏ってなんだ?」という疑問にお答えすると、会長の仕事に関連する技術的な情報をメモ書き程度にまとめていく予定です。
 具体的にどんな内容になるかは成り行き任せですが、今のところは「Microsoft Silverlight」や「Adobe Air」に関する内容が多くなりそうです。
 そんなに高度な内容を取り扱う予定はありませんが(そもそもそんな知識もありませんが)、多少なりとも同じような部分でつまずいた方々の参考になればいいなー、なんて思っています。

 とりあえず最初の仕事は、「裏」カテゴリのエントリーを、インデックスページに表示させないようにMovableTypeをカスタマイズすることですが、それすら果たしてうまくいくのかどうか...。

タグ