从母版页与内容页交互 (VB)
检查如何从母版页中的代码调用内容页的方法、设置属性等。
简介
前面的教程介绍了如何以编程方式让内容页与其母版页交互。 回想一下,我们更新了母版页,以包含一个 GridView 控件,该控件列出了最近添加的五个产品。 然后,我们创建了一个内容页面,用户可以从中添加新产品。 添加新产品后,内容页需要指示母版页刷新其 GridView,以便包含刚添加的产品。 此功能是通过向母版页添加公共方法来实现的,该方法刷新绑定到 GridView 的数据,然后从内容页调用该方法。
最常见的内容和母版页交互形式源自内容页。 但是,母版页可能会将当前内容页引入操作,如果母版页包含允许用户修改也在内容页上显示的数据的用户界面元素,则可能需要此功能。 请考虑在 GridView 控件中显示产品信息的内容页,以及包含 Button 控件的母版页,单击该按钮时,该控件将所有产品的价格翻倍。 与上一教程中的示例非常类似,需要在单击双价按钮后刷新 GridView,以便显示新价格,但在这种情况下,母版页需要将内容页投入操作。
本教程探讨如何在内容页中定义母版页调用功能。
通过事件和事件处理程序触发编程交互
从母版页调用内容页功能比另一种方式更具挑战性。 由于内容页具有单个母版页,因此在从内容页发起编程交互时,我们知道有哪些公共方法和属性可以随意使用。 但是,母版页可以具有许多不同的内容页,每个页面都有自己的一组属性和方法。 那么,当我们不知道在运行时之前将调用哪些内容页时,如何在母版页中编写代码以在其内容页中执行某些操作?
请考虑 ASP.NET Web 控件,例如 Button 控件。 Button 控件可以出现在任意数量的 ASP.NET 页上,并且需要一种机制,通过该控件可以提醒页面已单击它。 这是使用 事件完成的。 具体而言,Button 控件在单击时引发其 Click
事件;包含 Button 的 ASP.NET 页可以选择性地通过 事件处理程序响应该通知。
此模式可用于在其内容页中具有母版页触发器功能:
- 将事件添加到母版页。
- 每当母版页需要与其内容页通信时,引发 事件。 例如,如果母版页需要提醒其内容页用户已将价格翻倍,则会在价格翻倍后立即引发其事件。
- 在需要执行某些操作的内容页中创建事件处理程序。
本教程的余下部分将实现简介中概述的示例;即列出数据库中产品的内容页,以及包含 Button 控件的母版页,使价格翻倍。
步骤 1:在内容页中显示产品
我们的第一个业务顺序是创建一个内容页面,其中列出了 Northwind 数据库中的产品。 (我们在上一教程中向项目添加了 Northwind 数据库, 从内容页与母版页交互。) 首先,将新的 ASP.NET 页添加到 ~/Admin
名为 Products.aspx
的文件夹,确保将其 Site.master
绑定到母版页。 图 1 显示了将此页面添加到网站后解决方案资源管理器。
图 01:向文件夹添加新 ASP.NET 页 Admin
(单击以查看全尺寸图像)
回想一下,在 母版页中指定标题、元标记和其他 HTML 标头 教程中,我们创建了一个名为 的 BasePage
自定义基页类,如果未显式设置,该类将生成页面的标题。 转到 Products.aspx
页面的代码隐藏类,使其派生自 BasePage
(而不是 System.Web.UI.Page
) 。
最后,更新 文件以 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:将 SqlDataSource 配置为使用 Northwind 数据库 (单击以查看全尺寸图像)
接下来,通过从下拉列表中选择 Products 表并返回 ProductName
和 UnitPrice
列来指定数据源控件的 SELECT
语句, (请参阅图 4) 。 单击“下一步”,然后单击“完成”以完成“配置数据源”向导。
图 04:从Products
表返回 ProductName
和 UnitPrice
字段 (单击以查看全尺寸图像)
就是这么简单! 完成向导后,Visual Studio 将两个 BoundFields 添加到 GridView 以镜像 SqlDataSource 控件返回的两个字段。 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 中 (单击以查看全尺寸图像)
注意
随意清理 GridView 的外观。 一些建议包括将显示的 UnitPrice 值格式化为货币,以及使用背景色和字体来改善网格的外观。 有关在 ASP.NET 中显示和设置数据格式的详细信息,请参阅我的 使用数据教程系列。
步骤 2:向母版页添加双倍价格按钮
下一个任务是向母版页添加按钮 Web 控件,单击该控件时,该控件将使数据库中所有产品的价格翻倍。 Site.master
打开母版页,将“按钮”从“工具箱”拖到Designer,将其放置在上一教程中添加的 SqlDataSource 控件下RecentProductsDataSource
。 将 Button 的 ID
属性设置为 DoublePrice
,将其 Text
属性设置为“双倍产品价格”。
接下来,将 SqlDataSource 控件添加到母版页,并将其 DoublePricesDataSource
命名为 。 此 SqlDataSource 将用于执行 语句, UPDATE
将所有价格加倍。 具体而言,我们需要将其 ConnectionString
和 UpdateCommand
属性设置为相应的连接字符串 和 UPDATE
语句。 然后,我们需要在单击 Button 时DoublePrice
调用此 SqlDataSource 控件Update
的 方法。 若要设置 ConnectionString
和 UpdateCommand
属性,请选择 SqlDataSource 控件,然后转到属性窗口。 属性 ConnectionString
在下拉列表中列出已存储在 中的 Web.config
连接字符串;选择 NorthwindConnectionString
如图 6 所示的选项。
图 06:将 SqlDataSource 配置为使用 NorthwindConnectionString
(单击以查看全尺寸图像)
若要设置 UpdateCommand
属性,请在属性窗口中找到 UpdateQuery 选项。 此属性在选中时显示一个带有省略号的按钮;单击此按钮可显示“命令和参数编辑器”对话框,如图 7 所示。 在对话框的文本框中键入以下 UPDATE
语句:
UPDATE Products SET UnitPrice = UnitPrice * 2
执行此语句时,会将表中每条记录Products
的值加倍UnitPrice
。
图 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>
剩下的就是在单击 Button 时DoublePrice
调用其Update
方法。 Click
为 DoublePrice
Button 创建事件处理程序并添加以下代码:
Protected Sub DoublePrice_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles DoublePrice.Click
' Double the prices
DoublePricesDataSource.Update()
End Sub
若要测试此功能,请访问 ~/Admin/Products.aspx
我们在步骤 1 中创建的页面,然后单击“双倍产品价格”按钮。 单击该按钮会导致回发并执行 DoublePrice
Button 的 Click
事件处理程序,使所有产品的价格翻倍。 然后重新呈现页面,并返回标记并在浏览器中重新显示。 但是,内容页中的 GridView 列出了与单击“双产品价格”按钮之前相同的价格。 这是因为最初加载在 GridView 中的数据的状态存储在视图状态中,因此除非另有说明,否则不会在回发时重新加载数据。 如果访问其他页面,然后返回到该页面, ~/Admin/Products.aspx
你将看到更新的价格。
步骤 3:价格翻倍时引发事件
由于页面中的 GridView ~/Admin/Products.aspx
不会立即反映价格翻倍,因此用户可以理解地认为他们没有单击“双产品价格”按钮,或者它不起作用。 他们可能会尝试再单击该按钮几次,一次又一次地将价格翻倍。 若要解决此问题,我们需要让内容页中的网格在价格加倍后立即显示新价格。
如本教程前面所述,每当用户单击 DoublePrice
按钮时,我们需要在母版页中引发事件。 事件是一个类 (事件发布者) 通知另一个类 (事件订阅者) 发生了一些有趣的事情的方式。 在此示例中,母版页是事件发布者;那些关注 DoublePrice
何时单击按钮的内容页面是订阅者。
类通过创建 事件处理程序来订阅事件,事件处理程序是一个为响应所引发的事件而执行的方法。 发布者通过定义事件委托来定义他引发 的事件。 事件委托指定事件处理程序必须接受的输入参数。 在.NET Framework中,事件委托不返回任何值,并接受两个输入参数:
Object
标识事件源的 ,以及- 派生自 的类
System.EventArgs
传递给事件处理程序的第二个参数可以包含有关该事件的其他信息。 虽然基EventArgs
类不会传递任何信息,但.NET Framework包含许多扩展EventArgs
和包含其他属性的类。 例如,实例传递给响应事件的Command
事件处理程序,并包含两个CommandEventArgs
信息属性: CommandArgument
和 CommandName
。
若要定义事件,请使用以下语法:
Public Event eventName As eventDelegate
由于我们只需要在用户单击 DoublePrice
“按钮”且不需要传递任何其他信息时向内容页发出警报,因此可以使用事件委托 ,该委托 EventHandler
定义一个事件处理程序,该处理程序接受作为其第二个参数的 类型 System.EventArgs
的对象。 若要在母版页中创建 事件,请将以下代码行添加到母版页的代码隐藏类:
Partial Class Site
Inherits System.Web.UI.MasterPage
Public Event PricesDoubled As EventHandler
...
End Class
上述代码将公共事件添加到名为 的 PricesDoubled
母版页。 我们现在需要在价格翻倍后提高这一事件。 若要引发事件,请使用以下语法:
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
方法,将所有产品的价格加倍。 接下来是事件处理程序的两个新增项。 首先,刷新 RecentProducts
GridView 的数据。 此 GridView 已添加到上一教程中的母版页,并显示最近添加的五种产品。 我们需要刷新此网格,使其显示这五种产品的价格刚刚翻倍。 之后,将 PricesDoubled
引发 事件。 对母版页本身的引用 (Me
) 作为事件源发送到事件处理程序,空 EventArgs
对象作为事件参数发送。
步骤 4:处理内容页中的事件
此时,每当单击 Button 控件时,母版页将DoublePrice
引发其PricesDoubled
事件。 但是,这只是战斗的一半 - 我们仍然需要处理订阅服务器中的事件。 这涉及到两个步骤:创建事件处理程序和添加事件连接代码,以便在引发事件时执行事件处理程序。
首先创建名为 的 Master_PricesDoubled
事件处理程序。 由于我们在母版页中定义 PricesDoubled
事件的方式,事件处理程序的两个输入参数必须分别为 和 EventArgs
类型Object
。 在 事件处理程序中, 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 是对提供 event 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
为了完成此接线代码,我们需要从内容页以编程方式引用母版页。 如上一教程中所述,有两种方法可以执行此操作:
- 通过将松散类型
Page.Master
属性强制转换为适当的母版页类型,或 - 通过在页面中添加
@MasterType
指令.aspx
,然后使用强类型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 显示了首次访问时的页面。 请注意,GridView (母版页) 左列中的价格值 RecentProducts
和 ProductsGrid
内容页) 的 GridView (。 图 9 显示了单击按钮后 DoublePrice
立即显示的同一屏幕。 如你所看到的,新价格会立即反映在这两个 GridView 中。
图 08:初始价格值 (单击以查看全尺寸图像)
图 09:Just-Doubled 价格显示在 GridViews (单击以查看全尺寸图像)
总结
理想情况下,母版页及其内容页彼此完全独立,不需要任何级别的交互。 但是,如果母版页或内容页显示可从母版页或内容页修改的数据,则可能需要让母版页在修改数据时提醒内容页 (,) 反之亦然,以便可以更新显示。 在前面的教程中,我们了解了如何让内容页以编程方式与其母版页交互;本教程介绍了如何让母版页启动交互。
虽然内容和母版页之间的编程交互可以源自内容或母版页,但使用的交互模式取决于来源。 差异是由于内容页具有单个母版页,但母版页可以具有许多不同的内容页。 更好的方法是让母版页引发事件以指示已执行某些操作,而不是让母版页直接与内容页交互。 那些关注操作的内容页可以创建事件处理程序。
编程愉快!
深入阅读
有关本教程中讨论的主题的详细信息,请参阅以下资源:
关于作者
Scott Mitchell 是多本 ASP/ASP.NET 书籍的作者,4GuysFromRolla.com 的创始人,自 1998 年以来一直从事 Microsoft Web 技术工作。 Scott 担任独立顾问、培训师和作家。 他的最新书是 山姆自学 ASP.NET 在24小时内3.5。 可在 上或通过他的博客http://ScottOnWriting.NET联系 mitchell@4GuysFromRolla.com Scott。
特别感谢
本教程系列由许多有用的审阅者查看。 本教程的首席审阅者是 Suchi Banerjee。 有兴趣查看我即将发布的 MSDN 文章? 如果是这样,请在 mitchell@4GuysFromRolla.com
反馈
https://aka.ms/ContentUserFeedback。
即将发布:在整个 2024 年,我们将逐步淘汰作为内容反馈机制的“GitHub 问题”,并将其取代为新的反馈系统。 有关详细信息,请参阅:提交和查看相关反馈