网格实时刷新
一个经典的场景,在网上至今没有找到一个完美的解决方案。
场景
在一个子网页的 ContentPlaceHolder
(ContentPlaceHolder1
) 中,我放置了以下控件:
- 一个
GridView
控件 (GridView1
),用于显示 Northwind 数据库 Categories 表中的数据行。 - 一个
SqlDataSource
(SqlDataSource1
),用于从数据库中获取数据并绑定到GridView
。 - 一个
LinkButton
(LinkButton1
),允许用户向 Categories 表中插入新数据行。 - 一个
Panel
(Panel1
) 和一个ModalPopupExtender
(ModalPopupExtender1
) 控件,用于提供向数据库表中插入新数据的界面。ModalPopupExtender
的PopupControlID
属性设置为Panel1
。这将导致Panel1
面板在屏幕上弹出。 - 最后,
GridView
被包含在一个UpdatePanel
(UpdatePanel1
) 中。
每次向数据库插入新数据行时,我们希望以平滑的 AJAX 方式刷新 GridView
数据,而无需刷新整个网页。如何做到这一点?请继续阅读以了解详情。
解决方案
要添加新数据行,用户需要单击 LinkButton
。由于 LinkButton
是 ModalPopupExtender
的 TargetControlID
属性的值,因此单击 LinkButton1
会有效地使 Panel1
面板在屏幕上弹出。
Panel1
包含合适的数据输入文本框、OK 按钮 (OkButton
) 和 Cancel 按钮 (CancelButton
)。这两个按钮分别通过 OkControlID
和 CancelControlID
属性连接到 ModalPopupExtender
。此外,OnOkScript="onOkClick()"
属性声明会在用户单击 OkButton
按钮时执行 onOkClick()
JavaScript 函数。
onOkClick()
JavaScript 函数在客户端执行。它收集用户输入,并异步调用 DB Web 服务中的 DB.AddCategory
Web (和脚本) 方法。DB.AddCategory
将新数据行插入数据库。由于这是一个异步调用,因此也定义了成功 (onAddSuccess
) 和失败 (onAddFailure
) 回调函数。
请注意 onAddSuccess
回调函数中的 _doPostBack
调用。这是调用 OkButton
控件的服务器端回发所需的代码。请注意,由于我们在 ContentPlaceHolder
中,OkButton
的 ID 可能是 "ctl00ContentPlaceHolder01OkButton
" 这样的形式,JavaScript 代码必须知道这一点。
此时,将执行 OkButton_Click
方法的服务器端代码。它所做的就是让数据绑定的 GridView
重新绑定到 SqlDataSource
。通常,这将导致整个网页在浏览器中刷新,这是不希望的。我们真正想要的是在不刷新页面的情况下刷新 GridView
。这就是我将 GridView
放置在 UpdatePanel
控件中的原因。
关键问题
现在最大的问题是如何在新数据行插入数据库后立即更新 UpdatePanel
。长话短说,我们所要做的就是设置正确的触发器。但它会是哪个控件呢?
关键答案
如果您认为 LinkButton
应该是触发器,那么您就像我一样,不幸的是,您错了。答案是 Panel1
中的 OkButton
控件必须是触发 UpdatePanel
更新的控件。这就是为什么在异步 Web 服务调用完成后,我们立即调用 OkButton
的回发。回发会导致触发器触发,然后,瞧!UpdatePanel
及其内容 (新数据行会显示为网格行) 会得到更新。设置触发器非常简单。
<Triggers>
<ajax:AsyncPostBackTrigger ControlID="OkButton" EventName="Click" />
</Triggers>
最后但同样重要的是,请确保将 UpdatePanel
的 UpdateMode
属性设置为 "Conditional"。另外,不要忘记使 DB Web 服务可供 JavaScript 代码访问。
<ajax:ScriptManager ID="ScriptManager1" runat="server">
<Services>
<ajax:ServiceReference Path="DB.asmx" />
</Services>
</ajax:ScriptManager>
总结一下,您必须记住以下一系列事件:
(1) 用户单击 LinkButton
-> (2) ModalPopupExtender
弹出 Panel1
。用户输入数据并单击 OK 按钮 -> (3) 执行 onOkClick()
JavaScript 代码。进行异步 Web 服务调用,并将新数据行插入数据库。成功后,控制权返回到 onAddSuccess
回调函数,该函数 -> (4) 触发一个回发以调用 OK 按钮的服务器端代码 -> (5) 由于 OK 按钮是 UpdatePanel
的触发器,回发有效地导致 UpdatePanel
及其内容得到更新。
关注点
- 母版页无处不在。在此场景中,所有控件都放置在子页面的
ContentPlaceHolder
中。这本身就带来了控件 ID 修改的效果。如果您想从 JavaScript 客户端代码调用控件回发,则必须小心。 - 在向数据库插入数据行后,必须刷新数据绑定的
GridView
。由于GridView
位于UpdatePanel
中,因此这等同于更新UpdatePanel
。您只能通过放置适当的触发器来实现这一点。在此场景中,乍一看这可能并不明显。
我为什么写这个
我花了整整一周时间才解决这个问题。在互联网上搜索只能帮助我解决零碎的问题。似乎找不到一个直接而完整的答案。这就是为什么我决定为社区贡献这篇文章。提问很容易,但提供解决方案可能很难。