作成日: 2004/11/27

.NET ユーザコントロールとイベントハンドリング

概要

.NET ユーザコントロールを Web に埋め込んで使っていたのですが、ユーザコントロールで発生したイベントを クライアントサイドの javascript で記述したハンドラで受け取る必要がでてきたため、 ネットであちこち探してたどり着いたのが、この方法です。
通常の Active X コントロールでなら簡単にできることなのですが、.NET から COM の仕組みを利用するには、 少し追加作業が必要でした。なお、元ネタは Microsoft のサポート技術情報 313891 です。
以下では、Windows XP Professional SP2、Microsoft Visual Studio .NET 2003 (C#)、Internet Explorer 6.0 を使用しています。

.NET ユーザコントロールの作成

まず .NET ユーザコントロールを作成します。 ただし、ここではまだ javascript でハンドリングできるイベントは記述せず、通常のユーザコントロールを作成します。
Visual Studio を起動し、メニューから [ファイル] - [新規作成] - [プロジェクト] を選択します。
[新しいプロジェクト] ダイアログが表示されるので、[プロジェクトの種類] に [Visual C# プロジェクト]、 [テンプレート] で [Windows コントロール ライブラリ] を選択します。
[プロジェクト名] は適当に入力してください。ここでは TestCtrlLib としました。
入力が済んだら [OK] をクリックしてください。

新しいプロジェクトダイアログ

デフォルトのユーザコントロールとして UserControl1 が挿入されたプロジェクトが作成されます。

作成されたプロジェクト

ユーザコントロールの名前は適当に変更してください。ここでは、TestCtrl にしています。 なお、Visual Studio 2003 では、ユーザコントロールのファイル名を変更しても、 対応するクラス名などは変更してくれませんので、コードを表示し、クラスの名前とコンストラクタの名前も TestCtrl に変更してください。

ユーザコントロール名を変更した
クラス、コンストラクタ名を変更した

次にコントロール上にボタンを載せ、ボタンの名称を cmdGO にした後、ボタンをダブルクリックし、 イベントハンドラを以下のように記述します。

ボタンを配置する
イベントハンドラのコード

これでとりあえずコントロールはできあがりです (って押されたら「ハロー」っていうメッセージボックス出すだけですが…)。
メニューから [ビルド] - [ソリューションのビルド] を選択して、ビルドしてください。
ここでは Debug ビルドのままですので、ユーザコントロールを格納したファイルは、 [プロジェクトのディレクトリ\bin\Debug\TestCtrlLib.dll] になります。

Web にユーザコントロールを埋め込む

次に、ユーザコントロールを埋め込む先の Web アプリケーションを作成します。
なお、ローカルの IIS を使用しますので、起動しているのを確認しておいてください。
Visual Studio を起動し、メニューから [ファイル] - [新規作成] - [プロジェクト] を選択します。
[新しいプロジェクト] ダイアログが表示されるので、[プロジェクトの種類] に [Visual C# プロジェクト]、 [テンプレート] で [ASP.NET Web アプリケーション] を選択します。
[プロジェクト名] は適当で構いません。ここでは http://localhost/WebTestCtrlApp としました。
[OK] をクリックすると、プロジェクトが新規作成されます。

新しいWebプロジェクトダイアログ

ローカルの IIS をデフォルトのまま使用している場合、 C:\Inetpub\wwwroot\WebTestCtrlApp ディレクトリが作成され、プロジェクトのファイル群が配置されます。 ここにさきほど作成したユーザコントロールのファイルをコピーします。
※コピーする際にはアクセス権に注意してください。ASP.NET から参照できるよう権限を設定してください。

ユーザコントロールのファイルをコピー

次に、デフォルトで作成される WebForm1.aspx にユーザコントロールを埋め込みます。
デザイナで [HTML] を選択し HTML を表示し、<object> タグを使ってユーザコントロールを埋め込みます。
id はこのページでのユーザコントロールの id になります。classid にはユーザコントロールのファイル名と ユーザコントロールのクラス名をネームスペースを含めて # で区切って記述します。

ユーザコントロールを埋め込んだ HTML

これで埋め込み先のページは完成です。ビルドして、実行してください。
埋め込まれたユーザコントロールがページ上に表示され、「ゴー」ボタンを押すと、「ハロー」のメッセージボックスが表示されれば OK です。

ゴーボタンを押した
ユーザコントロールにイベントを実装する

ユーザコントロールにイベントを実装します。
.NET の枠組みの中で IE へのイベント発行ができるかどうかは不明です (色々あさってみたのですが、 資料に行き当たりませんでした…)。ここでは、ユーザコントロールに COM のシンクイベントを実装することで イベント通知を実現しています。

先に作成した、TestCtrlLib プロジェクトを開きます。
以下に追加するコードが利用するので、using System.Runtime.InteropServices を追加します。

using 句

イベントのシグネチャ定義としてのデリゲートを定義します。 ここでは、表示したいメッセージを引数とする HelloEventHandler を定義しました。

デリゲートの定義

シンクイベントインタフェースを定義します。
なお、GuidAttribute の GUID は GUIDGEN.exe などを使って適宜作成してください。
DispIdAttribute はイベントの番号になりますので、これも適当に付番してください。
なお、ここで定義するイベントインタフェースのシグネチャは先のデリゲートのシグネチャと合致している必要があります。

イベントインタフェースの定義

クラスに属性情報を追加します。
属性情報で、イベントのインタフェースを指定し、また、このクラスからのインタフェースを 自動的にディスパッチインタフェースとして扱うよう指定しています (ここでのクラスのインタフェースとは、 このクラスで public 指定されたメンバ変数やメソッドのことです)。

クラス属性情報

イベントインタフェースを実装するため、HelloEvent を格納する変数を定義します。

イベント変数

最後に「ゴー」ボタンが押された際にイベントを発生させるようにします。

イベントハンドラを変更する

以上でユーザコントロール側は完了です。リビルドして、Web アプリケーション下にコピーしてください。

Web ページ側でイベントをハンドリングする

ユーザコントロールで発生させたイベントをハンドリングするために Web ページ側に javascript でハンドラを記述します。
先に作成した WebTestCtrlApp を開き、WebForm1.apsx を HTML の編集画面にし、以下のコードを記述します。
※わざわざ TestCtrl_HelloEvent() を定義して呼び出す必要はなく、イベントハンドラから直接 alert(msg) としても良いです。

イベントハンドラを記述する

Web ページ側はこれで完成です。あとは実行すれば良いだけですが、実行するためには .NET のセキュリティ設定を 変更しておく必要があります。そのままだとたぶん動作しません。
とりあえず私の環境では、http://localhost/ を信頼済みサイトに登録し、.NET のセキュリティで信頼済みサイトを FullTrust に設定しています。

信頼済みサイトの設定は IE のメニューから [ツール] - [インターネット オプション] を選び、 表示される [インターネット オプション] ダイアログで、[セキュリティ] タブを選択し、[信頼済みサイト] をクリックしてから、 [サイト] ボタンをクリックし、[信頼済みサイト] ダイアログを表示します。
[次の Web サイトをゾーンに追加する] の箇所のテキストボックスに http://localhost/ と入力し [追加] ボタンをクリックすると、 入力した URL が [Web サイト] 欄に移動して追加されます。なお、[このゾーンのサイトにはすべてサーバの確認 (https:) を必要とする] チェックボックスは外しておいてください。 追加したら、[OK] をクリックしてダイアログを閉じてください。

信頼済みサイトの設定

.NET セキュリティの設定は .NET Configuration 1.1 を起動し、ツリーから [マイ コンピュータ] - [ランタイム セキュリティ ポリシー] - [コンピュータ] - [コードグループ] から信頼済みサイトのポリシーを選択します。
※私の環境では名称に対応するリソースがうまく読み込めず、コードグループ以下のツリーのノードの名称がおかしくなっています。実働上問題ないので放ってありますが、見にくくてすみません。
[コードグループ プロパティの編集] をクリックし、編集ダイアログが開いたら、[アクセス許可セット] タブで、 [アクセス許可セット] に [FullTrust] を選択し、[OK] をクリックします。

.NET セキュリティの設定

また、イベント通知を COM の仕組みを使って行う関係上、IE の Active X コントロールのセキュリティも設定しておく必要があるようです。
[ツール] - [インターネット オプション] を選び、表示される [インターネット オプション] ダイアログで、 [セキュリティ] タブを選択し、[信頼済みサイト] をクリックしてから、[レベルのカスタマイズ] をクリックし、 [セキュリティの設定] ダイアログを表示します。ActiveX コントロールとプラグインの設定を変更します。
私の環境では、

ActiveX コントロールとプラグインの実行有効にする
ActiveX コントロールに対して自動的にダイアログを表示有効にする
スクリプトを実行しても安全だとマークされていない ActiveX コントロールの初期化とスクリプトの実行ダイアログを表示する
スクリプトを実行しても安全だとマークされている ActiveX コントロールのスクリプトの実行有効にする
バイナリ ビヘイビアとスクリプト ビヘイビア有効にする
署名済み ActiveX コントロールのダウンロード有効にする
未署名の ActiveX コントロールのダウンロードダイアログを表示する

のように設定しています (というかデフォルトのまま)。

ActiveX のセキュリティの設定

以上の設定を確認した後、実行してみてください。イベントがでハンドリングされ、以下のように「ハロー」が表示されれば OK です。

イベントの発生とハンドリング
スレッドからの実行

おまけ的ですが、ユーザコントロールのボタンクリック時にスレッドを起動し、 スレッド側からイベント通知させてみます。
TestCtrlLib を開き、以下のように修正/追加します。

スレッドで試す

リビルドして、Web アプリケーション下にコピーしてから実行してみてください。3 秒の遅延のあと、 「ハロー」と表示されるはずです。
VC などで ActiveX コントロールを作成し、スレッド側からイベント通知しようとした場合、 マーシャリングの処理などを自前でする必要があり、少々ややこしいのですが、 .NET では Invoke() がすべてやってくれるようです。このあたりは .NET の便利さを感じます。
※なお、このサンプルではスレッド実行中に IE を閉じた場合への対処をしていませんのでご注意ください。

サンプルソース
TestCtrlLib.zip (9.48 KB)
作成した .NET ユーザコントロールのソースです。
WebTestCtrlApp.zip (14.3 KB)
作成したユーザコントロールを埋め込む先の Web アプリケーションです。