マスター ページからコンテンツ ページと対話する (VB)
マスター ページのコードからコンテンツ ページのメソッドを呼び出し、プロパティの設定などを行う方法について説明します。
はじめに
前のチュートリアルでは、コンテンツ ページから、マスター ページの操作をプログラムで行う方法について説明しました。 その際、最後に追加された 5 つの製品を一覧表示する GridView コントロールを追加してマスター ページを更新しました。 それから、ユーザーが新しい製品を追加できるコンテンツ ページを作成しました。 そのコンテンツ ページでは、新しい製品を追加すると、追加されたばかりの製品が含まれるように GridView を更新することをマスター ページに指示する必要がありました。 この機能は、GridView にバインドされたデータを更新するパブリック メソッドをマスター ページに追加し、コンテンツ ページからそのメソッドを呼び出すことで実現しました。
コンテンツ ページとマスター ページの対話の最も一般的な形式は、コンテンツ ページから発生します。 とはいえ、マスター ページで現在のコンテンツ ページを動作させることも可能です。ユーザーがコンテンツ ページに表示されるデータを変更できるようにするユーザー インターフェイス要素がマスター ページに含まれている場合は、このような機能が必要になる可能性があります。 GridView コントロールに製品情報を表示するコンテンツ ページと、クリックするとすべての製品の価格を 2 倍にする Button コントロールを含むマスター ページについて考えてみましょう。 前のチュートリアルの例と同様に、価格を 2 倍にするボタンをクリックすると新しい価格が表示されるように GridView を更新する必要がありますが、このシナリオでは、マスター ページでコンテンツ ページを動作させる必要があります。
このチュートリアルでは、コンテンツ ページで定義された機能をマスター ページから呼び出す方法について説明します。
イベントとイベント ハンドラーを使用したプログラムによる操作の開始
マスター ページからコンテンツ ページの機能を呼び出すことは、他の方法よりも困難です。 コンテンツ ページには 1 つのマスター ページしかないため、コンテンツ ページからプログラムによる操作を開始すると、どのようなパブリック メソッドとプロパティが使用できるかがわかります。 しかし、マスター ページには、それぞれに独自のプロパティとメソッドのセットが存在する、複数の異なるコンテンツ ページが含まれることがあります。 実行されるまでどのコンテンツ ページが呼び出されるかがわからないとすると、どうしたらそのコンテンツ ページで何らかのアクションを実行するコードをマスター ページに記述できるでしょうか?
ASP.NET Web コントロール (Button コントロールなど) について考えてみましょう。 Button コントロールは、任意の数の ASP.NET ページに表示できますが、クリックされたことをページに知らせるメカニズムが必要になります。 これには "イベント" を使います。 Button コントロールがクリックされると、Click
イベントを発生させます。そのボタンを含む ASP.NET ページは、必要に応じて "イベント ハンドラー" を介してその通知に応答できます。
この同じパターンを使用して、コンテンツ ページにマスター ページのトリガー機能を設定できます。
- マスター ページにイベントを追加します。
- マスター ページがコンテンツ ページと通信する必要が生じると、その都度イベントを発生させます。 たとえば、ユーザーが価格を 2 倍にしたことをマスター ページがコンテンツ ページに伝える必要がある場合、価格が 2 倍にされたら、すぐにそのイベントを発生させます。
- 何らかのアクションを実行する必要があるイベント ハンドラーをコンテンツ ページに作成します。
このチュートリアルの残りの部分では、「概要」で例として示されている、データベース内の製品を一覧表示するコンテンツ ページと、価格を 2 倍にする Button コントロールを含むマスター ページを実装します。
手順 1: コンテンツ ページに製品を表示する
最初に行う手順は、Northwind データベースの製品を一覧表示するコンテンツ ページを作成することです (前のチュートリアル「コンテンツ ページからマスター ページと対話する」で Northwind データベースをプロジェクトに追加しました)。新しい ASP.NET ページを Products.aspx
という名前の ~/Admin
フォルダーに追加し、Site.master
マスター ページにバインドします。 図 1 は、このページが Web サイトに追加された後のソリューション エクスプローラーを示しています。
図 01: Admin
フォルダーに新しい ASP.NET ページを追加します (クリックするとフルサイズの画像が表示されます)
「マスター ページでタイトル、メタ タグ、その他の HTML ヘッダーを指定する」チュートリアルで、ページのタイトルが明示的に設定されていない場合に生成する BasePage
という名前のカスタム ベース ページ クラスを作成したことを思い出してください。 Products.aspx
ページの分離コード クラスに移動し、(System.Web.UI.Page
からではなく) BasePage
から派生させます。
最後に、この新しいレッスンのエントリを含むように Web.sitemap
ファイルを更新します。 [コンテンツ ページからコンテンツ ページと対話する] レッスンの <siteMapNode>
の下に、次のマークアップを追加します。
<siteMapNode url="~/Admin/Products.aspx" title="Master to Content Page Interaction" />
この <siteMapNode>
要素の追加は、レッスンの一覧に反映されます (図 5 参照)。
Products.aspx
に戻ります。 MainContent
のコンテンツ コントロールで、GridView コントロールを追加し、名前を ProductsGrid
にします。 GridView を ProductsDataSource
という名前の新しい SqlDataSource コントロールにバインドします。
図 02: GridView を新しい SqlDataSource コントロールにバインドします (クリックするとフルサイズの画像が表示されます)
Northwind データベースを使用するようにウィザードを構成します。 前のチュートリアルを行っている場合は、既に Web.config
に NorthwindConnectionString
と名前が付けられた接続文字列があるはずです。 図 3 に示すように、ドロップダウン リストからこの接続文字列を選択します。
図 03: Northwind データベースを使用するように SqlDataSource を構成します (クリックするとフルサイズの画像が表示されます)
次に、ドロップダウン リストから Products テーブルを選択し、ProductName
と UnitPrice
列を返して、データ ソース コントロールの SELECT
ステートメントを指定します (図 4 を参照)。 [次へ]、[完了] の順にクリックして、データ ソースの構成ウィザードを完了します。
図 04: Products
テーブルから ProductName
と UnitPrice
フィールドを返します (クリックするとフルサイズの画像が表示されます)。
これですべて完了です。 ウィザードを完了すると、Visual Studio は GridView に 2 つの BoundField を追加して、SqlDataSource コントロールによって返される 2 つのフィールドをミラーリングします。 GridView コントロールと SqlDataSource コントロールのマークアップは次のとおりです。 図 5 にブラウザーで表示した場合の結果を示します。
<asp:GridView ID="ProductsGrid" runat="server" AutoGenerateColumns="False"
DataSourceID="ProductsDataSource">
<Columns>
<asp:BoundField DataField="ProductName" HeaderText="ProductName"
SortExpression="ProductName" />
<asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice"
SortExpression="UnitPrice" />
</Columns>
</asp:GridView>
<asp:SqlDataSource ID="ProductsDataSource" runat="server"
ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"
SelectCommand="SELECT [ProductName], [UnitPrice] FROM [Products]">
</asp:SqlDataSource>
図 05: 各製品とその価格が GridView に表示されます (クリックするとフルサイズの画像が表示されます)。
Note
必要に応じて GridView の外観を整えてください。 表示される UnitPrice 値を通貨として書式設定する、背景色やフォントを使用してグリッドの外観を改善するなど、いくつかのお勧めの設定があります。 ASP.NET でのデータの表示と書式設定の詳細については、「データの操作」チュートリアル シリーズをご覧ください。
手順 2: マスター ページに価格を 2 倍にするボタンを追加する
次の手順は、Button Web コントロールをマスター ページに追加することです。このコントロールをクリックすると、データベース内のすべての製品の価格が 2 倍になります。 Site.master
マスター ページを開き、ツールボックスからデザイナーにボタンをドラッグし、前のチュートリアルで追加した RecentProductsDataSource
SqlDataSource コントロールの下に配置します。 ボタンの ID
プロパティを DoublePrice
に設定し、その Text
プロパティを "Double Product Prices" に設定します。
次に、マスター ページに SqlDataSource コントロールを追加し、名前を DoublePricesDataSource
にします。 この SqlDataSource は、UPDATE
ステートメントを実行してすべての価格を 2 倍にするために使用されます。 具体的には、その ConnectionString
と UpdateCommand
プロパティを適切な接続文字列と UPDATE
ステートメントに設定する必要があります。 次に、DoublePrice
ボタンがクリックされたときに、この SqlDataSource コントロールの Update
メソッドを呼び出す必要があります。 ConnectionString
と UpdateCommand
プロパティを設定するには、SqlDataSource コントロールを選択し、プロパティ ウィンドウに移動します。 ConnectionString
プロパティは、ドロップダウン リストの Web.config
に既に格納されている接続文字列を一覧表示します。図 6 に示すように、NorthwindConnectionString
オプションを選択します。
図 06: NorthwindConnectionString
を使用するように SqlDataSource を構成します (クリックするとフルサイズの画像が表示されます)
UpdateCommand
プロパティを設定するには、プロパティ ウィンドウで UpdateQuery オプションを見つけます。 このプロパティを選択すると、省略記号付きのボタンが表示されます。このボタンをクリックすると、図 7 に示す [コマンドおよびパラメーター エディター] ダイアログ ボックスが表示されます。 ダイアログ ボックスのテキスト ボックスに次の UPDATE
ステートメントを入力します。
UPDATE Products SET UnitPrice = UnitPrice * 2
このステートメントを実行すると、Products
テーブルの各レコードの UnitPrice
値が 2 倍になります。
図 07: SqlDataSource の UpdateCommand
プロパティを設定します (クリックするとフルサイズの画像が表示されます)
これらのプロパティを設定すると、Button コントロールと SqlDataSource コントロールの宣言型マークアップは次のようになります。
<asp:Button ID="DoublePrice" runat="server"
Text="Double Product Prices" />
<asp:SqlDataSource ID="DoublePricesDataSource" runat="server"
UpdateCommand="UPDATE Products SET UnitPrice = UnitPrice * 2"
ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"
ProviderName="<%$ ConnectionStrings:NorthwindConnectionString.ProviderName %>">
</asp:SqlDataSource>
あとは、DoublePrice
ボタンをクリックしたときに、Update
メソッドが呼び出されるようにすることです。 DoublePrice
ボタンの Click
イベント ハンドラーを作成し、次のコードを追加します。
Protected Sub DoublePrice_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles DoublePrice.Click
' Double the prices
DoublePricesDataSource.Update()
End Sub
この機能をテストするには、手順 1 で作成した ~/Admin/Products.aspx
ページにアクセスし、[Double Product Prices] ボタンをクリックします。 このボタンをクリックするとポストバックが発生し、DoublePrice
ボタンの Click
イベント ハンドラーが実行され、すべての製品の価格が 2 倍になります。 その後、ページが再レンダリングされ、マークアップが返され、ブラウザーに再表示されます。 ただし、コンテンツ ページの GridView には、[Double Product Prices] ボタンがクリックされる前と同じ価格が表示されます。 これは、最初に GridView に読み込まれたデータの状態がビュー状態で格納されていたため、特に指示がない限りポストバックでは再読み込みされないためです。 別のページにアクセスして ~/Admin/Products.aspx
ページに戻ると、更新された価格が表示されます。
手順 3: 価格が 2 倍になったときにイベントを発生させる
~/Admin/Products.aspx
ページの GridView は価格の倍額をすぐに反映しないため、ユーザーは [Double Product Prices] ボタンをクリックしなかったか、機能しなかったと考える可能性があります。 ボタンを何度もクリックして、価格を何度も 2 倍にしてしまうかもしれません。 この問題を解決するには、コンテンツ ページのグリッドに、2 倍に設定された直後に新しい価格が表示されるようにする必要があります。
このチュートリアルで既に説明したように、ユーザーが DoublePrice
ボタンをクリックするたびにマスター ページでイベントを発生させる必要があります。 イベントは、あるクラス (イベント発行者) が別の一連のクラス (イベント サブスクライバー) に、関係する何かが発生したことを通知する方法です。 この例では、マスター ページがイベント発行者で、DoublePrice
ボタンがクリックされたときに、検知するコンテンツ ページがサブスクライバーです。
クラスは、"イベント ハンドラー" を作成して、イベントをサブスクライブします。このイベント ハンドラーは、発生するイベントに応答して実行されるメソッドです。 パブリッシャーは、"イベント デリゲート" を定義することによって発生するイベントを定義します。 イベント デリゲートは、イベント ハンドラーが受け入れる必要がある入力パラメーターを指定します。 .NET Framework では、イベント デリゲートは値を返さず、次の 2 つの入力パラメーターを受け取ります。
- イベント ソースを識別する
Object
System.EventArgs
の派生クラス
イベント ハンドラーに渡される 2 番目のパラメーターには、イベントに関する追加情報を含めることができます。 基本 EventArgs
クラスは情報を渡しませんが、.NET Framework には EventArgs
を拡張して追加のプロパティを扱う、多くのクラスが含まれています。 たとえば、CommandEventArgs
インスタンスは Command
イベントに応答するイベント ハンドラーに渡され、2 つの情報プロパティ (CommandArgument
と CommandName
) を含みます。
Note
イベントの作成、発生、処理の詳細については、「イベントとデリゲート」と「単純な英語でのイベント デリゲート」をご覧ください。
イベントを定義するには、次の構文を使用します。
Public Event eventName As eventDelegate
ユーザーが DoublePrice
ボタンをクリックし、他の追加情報を渡す必要がない場合にのみコンテンツ ページに通知する必要があるため、イベント デリゲート EventHandler
を使用できます。このデリゲートは、2 番目のパラメーターとして System.EventArgs
型のオブジェクトを受け入れるイベント ハンドラーを定義します。 マスター ページでイベントを作成するには、マスター ページの分離コード クラスに次のコード行を追加します。
Partial Class Site
Inherits System.Web.UI.MasterPage
Public Event PricesDoubled As EventHandler
...
End Class
上記のコードは、PricesDoubled
という名前のマスター ページにパブリック イベントを追加します。 価格が 2 倍になった後、このイベントを発生させる必要があります。 イベントを発生させるには、次の構文を使用します。
RaiseEvent eventName(sender, eventArgs)
sender と eventArgs は、サブスクライバーのイベント ハンドラーに渡す値です。
DoublePrice
Click
イベント ハンドラーを次のコードで更新します。
Protected Sub DoublePrice_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles DoublePrice.Click
' Double the prices
DoublePricesDataSource.Update()
' Refresh RecentProducts
RecentProducts.DataBind()
' Raise the PricesDoubled event
RaiseEvent PricesDoubled(Me, EventArgs.Empty)
End Sub
以前と同様に、Click
イベント ハンドラーは、DoublePricesDataSource
SqlDataSource コントロールの Update
メソッドを呼び出して、すべての製品の価格を 2 倍にすることから始めます。 その後、イベント ハンドラーに 2 つの点が追加されます。 まず、RecentProducts
GridView のデータが更新されます。 この GridView は、前のチュートリアルのマスター ページに追加され、最近追加された 5 つの製品が表示されます。 これらの 5 つの製品の 2 倍にされた価格が表示されるように、このグリッドを更新する必要があります。 その後、PricesDoubled
イベントが発生します。 マスター ページ自体 (Me
) への参照がイベント ソースとしてイベント ハンドラーに送信され、空の EventArgs
オブジェクトがイベント引数として送信されます。
手順 4: コンテンツ ページでのイベントの処理
この時点で、DoublePrice
Button コントロールがクリックされるたびに、マスター ページは PricesDoubled
イベントを発生させます。 しかし、これはまだ半分にすぎません。サブスクライバー内のイベントを処理する必要があります。 これには、イベント ハンドラーを作成し、イベント接続コードを追加する 2 つの手順が含まれます。この手順によって、イベントの発生時にイベント ハンドラーが実行されます。
まず、Master_PricesDoubled
という名前のイベント ハンドラーを作成します。 マスター ページで PricesDoubled
イベントを定義した方法のため、イベント ハンドラーの 2 つの入力パラメーターの型は、それぞれ Object
と EventArgs
である必要があります。 イベント ハンドラーで ProductsGrid
GridView の DataBind
メソッドを呼び出して、データをグリッドに再バインドします。
Private Sub Master_PricesDoubled(ByVal sender As Object, ByVal e As EventArgs)
' Rebind data to ProductsGrid
ProductsGrid.DataBind()
End Sub
イベント ハンドラーのコードは完了しましたが、マスター ページの PricesDoubled
イベントをこのイベント ハンドラーにまだ接続していません。 サブスクライバーは、次の構文を使用してイベント ハンドラーにイベントを接続します。
AddHandler publisher.eventName, AddressOf methodName
publisher はイベント eventName を提供するオブジェクトへの参照であり、methodName はサブスクライバーで定義されているイベント ハンドラーの名前です。
このイベント接続コードは、最初のページ アクセスと後続のポストバックで実行する必要があり、イベントが発生する前のページ ライフサイクルの時点で発生する必要があります。 イベント接続コードを追加するのに適したタイミングは、ページ ライフサイクルの非常に早い段階で発生する PreInit ステージです。
~/Admin/Products.aspx
を開いて Page_PreInit
イベント ハンドラーを作成します。
Protected Sub Page_PreInit(ByVal sender As Object, ByVal e As EventArgs) Handles Me.PreInit
' TODO: Put event wiring logic here
End Sub
この接続コードを完了するには、コンテンツ ページからマスター ページへのプログラムによる参照が必要です。 前のチュートリアルで説明したように、これを行うには 2 つの方法があります。
- 緩い型指定の
Page.Master
プロパティを適切なマスター ページの種類にキャストする .aspx
ページに@MasterType
ディレクティブを追加し、厳密に型指定されたMaster
プロパティを使用する
ここでは後者のアプローチを使用してみましょう。 ページの宣言型マークアップの先頭に次の @MasterType
ディレクティブを追加します。
<%@ MasterType VirtualPath="~/Site.master" %>
次に、Page_PreInit
イベント ハンドラーに次のイベント接続コードを追加します。
Protected Sub Page_PreInit(ByVal sender As Object, ByVal e As EventArgs) Handles Me.PreInit
AddHandler Master.PricesDoubled, AddressOf Master_PricesDoubled
End Sub
このコードを配置すると、DoublePrice
ボタンがクリックされるたびにコンテンツ ページの GridView が更新されます。
図 8 と 9 は、この動作を示しています。 図 8 は、最初にアクセスした時点のページを示しています。 RecentProducts
GridView (マスター ページの左側の列) と ProductsGrid
GridView (コンテンツ ページ内) の両方の価格の値に注目してください。 図 9 は、DoublePrice
ボタンがクリックされた直後の同じ画面を示しています。 ご覧のように、新しい価格は両方の GridView に瞬時に反映されます。
図 08: 最初の価格の値 (クリックするとフルサイズの画像が表示されます)
図 09: 2 倍の価格が GridView に表示されています (クリックするとフルサイズの画像が表示されます)
まとめ
理想は、マスター ページとそのコンテンツ ページは互いに完全に分離されており、対話のレベルは必要ないことです。 しかし、マスター ページまたはコンテンツ ページで、マスター ページまたはコンテンツ ページから変更できるデータを表示している場合は、データが変更されたときに表示を更新できるように、マスター ページからコンテンツ ページに通知する (またはその逆) ことが必要になる可能性があります。 前のチュートリアルでは、プログラムでコンテンツ ページをマスター ページと対話させる方法について説明しました。このチュートリアルでは、マスター ページで対話を開始する方法について考慮しました。
コンテンツ ページとマスター ページの間のプログラムによる対話は、コンテンツ ページまたはマスター ページから発生しますが、使用される対話パターンは開始する場所によって異なります。 この違いは、コンテンツ ページには 1 つのマスター ページしかありませんが、マスター ページにはさまざまなコンテンツ ページが存在する可能性があることに起因します。 マスター ページをコンテンツ ページと直接対話させるのではなく、マスター ページでイベントを発生させ、何らかのアクションが実行されたことを通知させる方法をお勧めします。 アクションを検知するコンテンツ ページで、イベント ハンドラーを作成できます。
プログラミングに満足!
もっと読む
この記事で説明したトピックの詳細については、次のリソースを参照してください。
作成者について
複数の ASP/ASP.NET 書籍の著者であり、4GuysFromRolla.com の創設者である Scott Mitchell は、1998 年から Microsoft Web テクノロジに取り組んでいます。 Scott は、独立したコンサルタント、トレーナー、ライターとして働いています。 彼の最新の著書は、「Sams Teach Yourself ASP.NET 3.5 in 24 Hours」です。 Mitchell 氏には、mitchell@4GuysFromRolla.com から、または http://ScottOnWriting.NET で彼のブログを介して連絡できます。
特別な感謝
このチュートリアル シリーズは、多くの役に立つ校閲者によってレビューされました。 このチュートリアルのリード レビュー担当者は Suchi Banerjee でした。 今後の MSDN の記事を確認することに関心がありますか? ご希望なら、mitchell@4GuysFromRolla.com でメッセージをお送りください