将 PostBackTriggers 和 AsyncPostBackTriggers 添加到 UpdatePanel 以用于动态生成的孙控件 [英] Adding PostBackTriggers and AsyncPostBackTriggers to UpdatePanel for dynamically-generated grandchild controls
问题描述
我有一个带有 ScriptManager、通用 HTML 下拉列表 () 和 UpdatePanel 的页面.UpdatePanel 包含一个 PlaceHolder(目前).在 Page_Load 期间,许多用户控件被添加到 PlaceHolder(实际上,它是同一个用户控件的多个实例).要添加的数量在页面加载之前是未知的,因此它们确实需要动态加载.下拉列表中填充了相同数量的菜单项,页面上也有 javascript(使用 jQuery)根据下拉列表的状态一次只显示一个控件.>
每个用户控件都有两个按钮,应该生成异步回发,一个下拉列表应该在选定值的更改时生成异步回发,以及一个按钮应该生成同步回发.如果我不是动态生成控件,并且只有一个控件,则结构将类似于:
<asp:UpdatePanel ID="myUpdatePanel" runat="server" UpdateMode="Conditional"ChildrenAsTriggers="false"><内容模板><asp:TextBox ID="textBox1" runat="server"/><asp:TextBox ID="textBox2" runat="server"/><asp:Button ID="asyncButton1" runat="server" Text="Button1"onclick="asyncButton1_Click"/><asp:DropDownList ID="asyncDropDown" ruant="server" AutoPostBack="true"OnSelectedIndexChanged="asyncDropDown_SelectedIndexChanged"/><asp:Button ID="asyncButton2" runat="server" Text="Button2"OnClick="asyncButton2_Click"/><asp:Button ID="syncButton" runat="server" Text="SyncButton"OnClick="syncButton_Click"/></内容模板><触发器><asp:AsyncPostBackTrigger ControlID="asyncButton1" EventName="点击"/><asp:AsyncPostBackTrigger ControlID="asyncButton2" EventName="点击"/><asp:AsyncPostBackTrigger ControlID="asyncDropDown"EventName="SelectedIndexChanged"/><asp:PostBackTrigger ControlID="syncButton"/></触发器></asp:UpdatePanel>
当然,ContentTemplate 中的所有控件实际上都是每个用户控件的一部分.
在服务器端添加触发器似乎不起作用,因为似乎没有 ControlID 可以帮助 UpdatePanel 找到相关控件.我可以使用控件的 ID 或控件的 UniqueID,但它不起作用,我收到了一个错误
ID 为 'ctl00$ContentPlaceHolder1$ctl01$asyncButton1' 的控件不能被在 UpdatePanel 'myUpdatePanel' 中找到触发器.
所以,我想知道是否需要在客户端注册触发器而不是使用 ASP.NET Ajax.我发现 这个页面 基本上解释了如何.但是,我不知道如何考虑 EventName.到目前为止,我看到的示例只是添加按钮点击,但我不知道如何处理来自 DropDownList 的 SelectedIndexChanged 事件.
这里有什么帮助吗?有没有我错过的例子?当然,我提供的链接中的方法似乎是非官方的",这无济于事,因此我没有看到有关该主题的任何 MSDN 文档.
谢谢!
我的建议是将包括此 UpdatePanel 在内的所有控件从该 UpdatePanel 中提取到一个 UserControl 中.在用户控件中定义在单击按钮或更改下拉列表的选定索引时引发的事件.在包含占位符的页面中处理这些事件(在单个 UpdatePanel 中,有条件的,没有触发器).如果添加 UserControl,请手动调用主更新面板的更新方法.
为了澄清我的意思,请看以下示例:
主页aspx:
<内容模板><asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder></内容模板></asp:UpdatePanel>
代码隐藏:
私有属性 UserControlCount() As Int32得到如果 ViewState("UserControlCount") 是什么,那么ViewState("UserControlCount") = 1万一返回 DirectCast(ViewState("UserControlCount"), Int32)结束获取Set(ByVal value As Int32)ViewState("UserControlCount") = 值结束集最终财产Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) 处理 Me.Load重新创建用户控件()结束子私有子 recreateUserControls()For i As Int32 = 1 To Me.UserControlCountDim uc As DynamicControls = DirectCast(Me.LoadControl("DynamicControls.ascx"), DynamicControls)uc.ID = "DynamicControls_" &一世Addhandlers(uc)Me.PlaceHolder1.Controls.Add(uc)下一个结束子Private Sub Addhandlers(ByVal uc As DynamicControls)AddHandler uc.asyncButton1Clicked, AddressOf ucAsyncButton1ClickedAddHandler uc.asyncButton2Clicked, AddressOf ucAsyncButton2ClickedAddHandler uc.syncButtonClicked, AddressOf ucSyncButtonClickedAddHandler uc.asyncDropDownSelectedIndexChanged, AddressOf ucAsyncDropDownSelectedIndexChanged结束子私有子 addUserControl()Me.UserControlCount += 1Dim uc As DynamicControls = DirectCast(Me.LoadControl("DynamicControls.ascx"), DynamicControls)uc.ID = "DynamicControls_" &我.UserControlCountAddhandlers(uc)Me.PlaceHolder1.Controls.Add(uc)Upd1.Update()结束子Private Sub ucAsyncButton1Clicked(ByVal sender As Object, ByVal e As EventArgs)'仅演示如何动态添加控件和更新UpdatePanel'添加用户控件()Me.Upd1.Update()结束子Private Sub ucAsyncButton2Clicked(ByVal sender As Object, ByVal e As EventArgs)结束子Private Sub ucSyncButtonClicked(ByVal sender As Object, ByVal e As EventArgs)结束子Private Sub ucAsyncDropDownSelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs)结束子
保存您的控件的ascx:
<%@ Control Language="vb" AutoEventWireup="false" CodeBehind="DynamicControls.ascx.vb" Inherits="AJAXEnabledWebApplication1.DynamicControls" %><%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="asp" %><asp:UpdatePanel ID="myUpdatePanel" runat="server" UpdateMode="Conditional"ChildrenAsTriggers="false"><内容模板><asp:TextBox ID="textBox1" runat="server"/><asp:TextBox ID="textBox2" runat="server"/><asp:Button ID="asyncButton1" runat="server" Text="Button1"/><asp:DropDownList ID="asyncDropDown" runat="server" AutoPostBack="true"/><asp:Button ID="asyncButton2" runat="server" Text="Button2"/><asp:Button ID="syncButton" runat="server" Text="SyncButton"/></内容模板><触发器><asp:AsyncPostBackTrigger ControlID="asyncButton1" EventName="点击"/><asp:AsyncPostBackTrigger ControlID="asyncButton2" EventName="点击"/><asp:AsyncPostBackTrigger ControlID="asyncDropDown" EventName="SelectedIndexChanged"/><asp:PostBackTrigger ControlID="syncButton"/></触发器></asp:UpdatePanel>
UserControl 的代码隐藏:
公共部分类动态控件继承 System.Web.UI.UserControl公共事件 asyncButton1Clicked(ByVal sender As Object, ByVal e As System.EventArgs)公共事件 asyncButton2Clicked(ByVal sender As Object, ByVal e As System.EventArgs)公共事件syncButtonClicked(ByVal sender As Object, ByVal e As System.EventArgs)公共事件 asyncDropDownSelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs)Private Sub asyncButton1_Click(ByVal sender As Object, ByVal e As System.EventArgs) 处理 asyncButton1.ClickRaiseEvent asyncButton1Clicked(sender, e)结束子Private Sub asyncButton2_Click(ByVal sender As Object, ByVal e As System.EventArgs) 处理 asyncButton2.ClickRaiseEvent asyncButton2Clicked(sender, e)结束子Private Sub syncButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) 处理syncButton.ClickRaiseEvent syncButtonClicked(sender, e)结束子Private Sub asyncDropDown_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) 处理 asyncDropDown.SelectedIndexChangedRaiseEvent asyncDropDownSelectedIndexChanged(sender, e)结束子结束班
这样您就不会遇到 ClientID 的问题.
添加:如果您需要访问事件处理程序中 UserControls 的控件,请使用以下两个选项之一:
- 将发送者的 NamingContainer 转换为 userControl 的类型:
Dim uc As DynamicControls = DirectCast(DirectCast(sender, Control).NamingContainer, DynamicControls)
将所有出现的
(ByVal sender As Object, ByVal e As System.EventArgs)
替换为(uc as DynamicControls)
.通过这种方式,您的 UserControl 的引用作为参数添加到事件中,您可以从页面访问它的公共属性,例如:dim txt1 as String = uc.Text1
如果您在 UserControl 中公开了属性 Text1:
公共属性 Text1() As String得到返回 textBox1.Text结束获取Set(ByVal value As String)textBox1.Text = 值结束集最终财产
第二个选项是最干净、最易读的方式.
更新:根据您的评论:您应该将 UpdateProgress 放在更新的 UpdatePanel 内的 UserControl 中.请记住正确设置 AssociatedUpdatePanelID.例如:
<asp:UpdatePanel ID="UdpForm" runat="server" UpdateMode="conditional" ChildrenAsTriggers="false" ><内容模板><asp:panel ID="FormPanel" runat="server"><asp:UpdateProgress ID="UpdateProgress1" DynamicLayout="true" runat="server" AssociatedUpdatePanelID="UdpForm" DisplayAfter="0" ><进度模板><div class="progress"><asp:Image ID="ImgProgress1" runat="server" ImageUrl="~/images/ajax-loader-arrows.gif" ToolTip="loading..."/> 请稍候...
</ProgressTemplate></asp:UpdateProgress><asp:FormView ID="FormView1" runat="server" DefaultMode="ReadOnly" ><ItemTemplate></ItemTemplate><EditItemTemplate></EditItemTemplate><InsertItemTemplate></InsertItemTemplate><EmptyDataTemplate></EmptyDataTemplate><PagerTemplate ></PagerTemplate></asp:FormView></asp:面板></内容模板></asp:UpdatePanel><asp:UpdatePanel ID="UpdContent" runat="server" UpdateMode="conditional" ChildrenAsTriggers="false" ><内容模板><asp:Panel ID="PnlMain" runat="server"><asp:UpdateProgress ID="UpdateProgress2" DynamicLayout="true" runat="server" AssociatedUpdatePanelID="UpdContent" DisplayAfter="0" ><进度模板><div class="progress"><asp:Image ID="ImgProgress1" runat="server" ImageUrl="~/images/ajax-loader-arrows.gif" ToolTip="loading..."/> 请稍候...
</ProgressTemplate></asp:UpdateProgress>内容</asp:面板></内容模板><触发器></触发器></asp:UpdatePanel>
I have a page with a ScriptManager, a generic HTML drop-down list (<select>
), and an UpdatePanel. The UpdatePanel contains a PlaceHolder (for now). During Page_Load, a number of user controls are added to the PlaceHolder (really, it's several instances of the same user control). The number to add is not known until the page loads, so they do need to be loaded dynamically. The drop-down list is populated with the same number of menu items, and there is javascript on the page also (using jQuery) to show only one of the controls at a time depending on the state of the drop-down list.
Each user control has two buttons that should generate an asynchronous postback, a drop-down list that should generate an asynchronous postback on a change in selected value, and a button that should generate a synchronous postback. If I was not generating the controls dynamically, and if there was only one control, the structure would be something like:
<asp:UpdatePanel ID="myUpdatePanel" runat="server" UpdateMode="Conditional"
ChildrenAsTriggers="false">
<ContentTemplate>
<asp:TextBox ID="textBox1" runat="server" />
<asp:TextBox ID="textBox2" runat="server" />
<asp:Button ID="asyncButton1" runat="server" Text="Button1"
onclick="asyncButton1_Click" />
<asp:DropDownList ID="asyncDropDown" ruant="server" AutoPostBack="true"
OnSelectedIndexChanged="asyncDropDown_SelectedIndexChanged" />
<asp:Button ID="asyncButton2" runat="server" Text="Button2"
OnClick="asyncButton2_Click" />
<asp:Button ID="syncButton" runat="server" Text="SyncButton"
OnClick="syncButton_Click" />
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="asyncButton1" EventName="Click" />
<asp:AsyncPostBackTrigger ControlID="asyncButton2" EventName="Click" />
<asp:AsyncPostBackTrigger ControlID="asyncDropDown"
EventName="SelectedIndexChanged" />
<asp:PostBackTrigger ControlID="syncButton" />
</Triggers>
</asp:UpdatePanel>
Of course, all the controls inside the ContentTemplate would actually be part of each user control.
Adding the triggers on the server side does not seem to work because no ControlID seems to help the UpdatePanel find the relevant controls. I can use either the control's ID or the control's UniqueID, and it does not work, and I get an error along the lines of
A control with ID 'ctl00$ContentPlaceHolder1$ctl01$asyncButton1' could not be
found for the trigger in UpdatePanel 'myUpdatePanel'.
So, I wonder if I need to register the triggers in the client instead using ASP.NET Ajax. I found this page that basically explains how. However, I do not know how to get the EventName taken into consideration. The examples I have seen so far have merely been adding button clicks, but I don't know how to handle the SelectedIndexChanged event from the DropDownList.
Any help here? Are there examples out there I have missed? It doesn't help, of course, that the method in the link I gave appears to be "unofficial," so I don't see any MSDN documents on the subject.
Thanks!
My suggestion would be to pull all your controls inclusive this UpdatePanel out of this UpdatePanel into an UserControl. Define events in your usercontrol that are raised when the buttons are clicked or the Dropdown's selected index get changed. Handle these events in your page that holds the Placeholder(in a single UpdatePanel,conditional,without triggers). Call the Update-method of the main update panel manually if you add UserControls.
To clarify what i mean have a look at following example:
Main-page aspx:
<asp:UpdatePanel ID="Upd1" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>
</ContentTemplate>
</asp:UpdatePanel>
Codebehind:
Private Property UserControlCount() As Int32
Get
If ViewState("UserControlCount") Is Nothing Then
ViewState("UserControlCount") = 1
End If
Return DirectCast(ViewState("UserControlCount"), Int32)
End Get
Set(ByVal value As Int32)
ViewState("UserControlCount") = value
End Set
End Property
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
recreateUserControls()
End Sub
Private Sub recreateUserControls()
For i As Int32 = 1 To Me.UserControlCount
Dim uc As DynamicControls = DirectCast(Me.LoadControl("DynamicControls.ascx"), DynamicControls)
uc.ID = "DynamicControls_" & i
Addhandlers(uc)
Me.PlaceHolder1.Controls.Add(uc)
Next
End Sub
Private Sub Addhandlers(ByVal uc As DynamicControls)
AddHandler uc.asyncButton1Clicked, AddressOf ucAsyncButton1Clicked
AddHandler uc.asyncButton2Clicked, AddressOf ucAsyncButton2Clicked
AddHandler uc.syncButtonClicked, AddressOf ucSyncButtonClicked
AddHandler uc.asyncDropDownSelectedIndexChanged, AddressOf ucAsyncDropDownSelectedIndexChanged
End Sub
Private Sub addUserControl()
Me.UserControlCount += 1
Dim uc As DynamicControls = DirectCast(Me.LoadControl("DynamicControls.ascx"), DynamicControls)
uc.ID = "DynamicControls_" & Me.UserControlCount
Addhandlers(uc)
Me.PlaceHolder1.Controls.Add(uc)
Upd1.Update()
End Sub
Private Sub ucAsyncButton1Clicked(ByVal sender As Object, ByVal e As EventArgs)
'only to demonstrate how to add control dynamically and update the UpdatePanel'
addUserControl()
Me.Upd1.Update()
End Sub
Private Sub ucAsyncButton2Clicked(ByVal sender As Object, ByVal e As EventArgs)
End Sub
Private Sub ucSyncButtonClicked(ByVal sender As Object, ByVal e As EventArgs)
End Sub
Private Sub ucAsyncDropDownSelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs)
End Sub
ascx which holds your controls:
<%@ Control Language="vb" AutoEventWireup="false" CodeBehind="DynamicControls.ascx.vb" Inherits="AJAXEnabledWebApplication1.DynamicControls" %>
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="asp" %>
<asp:UpdatePanel ID="myUpdatePanel" runat="server" UpdateMode="Conditional"
ChildrenAsTriggers="false">
<ContentTemplate>
<asp:TextBox ID="textBox1" runat="server" />
<asp:TextBox ID="textBox2" runat="server" />
<asp:Button ID="asyncButton1" runat="server" Text="Button1" />
<asp:DropDownList ID="asyncDropDown" runat="server" AutoPostBack="true" />
<asp:Button ID="asyncButton2" runat="server" Text="Button2" />
<asp:Button ID="syncButton" runat="server" Text="SyncButton" />
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="asyncButton1" EventName="Click" />
<asp:AsyncPostBackTrigger ControlID="asyncButton2" EventName="Click" />
<asp:AsyncPostBackTrigger ControlID="asyncDropDown" EventName="SelectedIndexChanged" />
<asp:PostBackTrigger ControlID="syncButton" />
</Triggers>
</asp:UpdatePanel>
Codebehind of UserControl:
Public Partial Class DynamicControls
Inherits System.Web.UI.UserControl
Public Event asyncButton1Clicked(ByVal sender As Object, ByVal e As System.EventArgs)
Public Event asyncButton2Clicked(ByVal sender As Object, ByVal e As System.EventArgs)
Public Event syncButtonClicked(ByVal sender As Object, ByVal e As System.EventArgs)
Public Event asyncDropDownSelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs)
Private Sub asyncButton1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles asyncButton1.Click
RaiseEvent asyncButton1Clicked(sender, e)
End Sub
Private Sub asyncButton2_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles asyncButton2.Click
RaiseEvent asyncButton2Clicked(sender, e)
End Sub
Private Sub syncButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles syncButton.Click
RaiseEvent syncButtonClicked(sender, e)
End Sub
Private Sub asyncDropDown_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles asyncDropDown.SelectedIndexChanged
RaiseEvent asyncDropDownSelectedIndexChanged(sender, e)
End Sub
End Class
On this way you won't have problems with ClientID's.
Addition: If you need access to the controls of your UserControls in the event-handlers, use one of following two options:
- cast the sender's NamingContainer to the userControl's type:
Dim uc As DynamicControls = DirectCast(DirectCast(sender, Control).NamingContainer, DynamicControls)
replace all occurences of
(ByVal sender As Object, ByVal e As System.EventArgs)
with(uc as DynamicControls)
. On this way the reference of your UserControl is added to the event as parameter and you could access public properties of it from the page, f.e.:dim txt1 as String = uc.Text1
If you have exposed a property Text1 in the UserControl:
Public Property Text1() As String
Get
Return textBox1.Text
End Get
Set(ByVal value As String)
textBox1.Text = value
End Set
End Property
The second option is the cleanest and most readable way.
Update: According to your comment: you should place the UpdateProgress in the UserControl inside of the UpdatePanel that gets updated. Remember to set the AssociatedUpdatePanelID correctly. For example:
<asp:UpdatePanel ID="UdpForm" runat="server" UpdateMode="conditional" ChildrenAsTriggers="false" >
<ContentTemplate>
<asp:panel ID="FormPanel" runat="server">
<asp:UpdateProgress ID="UpdateProgress1" DynamicLayout="true" runat="server" AssociatedUpdatePanelID="UdpForm" DisplayAfter="0" >
<ProgressTemplate>
<div class="progress">
<asp:Image ID="ImgProgress1" runat="server" ImageUrl="~/images/ajax-loader-arrows.gif" ToolTip="loading..." /> please wait...
</div>
</ProgressTemplate>
</asp:UpdateProgress>
<asp:FormView ID="FormView1" runat="server" DefaultMode="ReadOnly" >
<ItemTemplate></ItemTemplate>
<EditItemTemplate></EditItemTemplate>
<InsertItemTemplate></InsertItemTemplate>
<EmptyDataTemplate>
</EmptyDataTemplate>
<PagerTemplate >
</PagerTemplate>
</asp:FormView>
</asp:panel>
</contenttemplate>
</asp:UpdatePanel>
<asp:UpdatePanel ID="UpdContent" runat="server" UpdateMode="conditional" ChildrenAsTriggers="false" >
<ContentTemplate>
<asp:Panel ID="PnlMain" runat="server">
<asp:UpdateProgress ID="UpdateProgress2" DynamicLayout="true" runat="server" AssociatedUpdatePanelID="UpdContent" DisplayAfter="0" >
<ProgressTemplate>
<div class="progress">
<asp:Image ID="ImgProgress1" runat="server" ImageUrl="~/images/ajax-loader-arrows.gif" ToolTip="loading..." /> please wait...
</div>
</ProgressTemplate>
</asp:UpdateProgress>
Content
</asp:Panel>
</ContentTemplate>
<Triggers ></Triggers>
</asp:UpdatePanel>
这篇关于将 PostBackTriggers 和 AsyncPostBackTriggers 添加到 UpdatePanel 以用于动态生成的孙控件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!