【问题标题】:Adding PostBackTriggers and AsyncPostBackTriggers to UpdatePanel for dynamically-generated grandchild controls为动态生成的孙控件添加 PostBackTriggers 和 AsyncPostBackTriggers 到 UpdatePanel
【发布时间】:2011-06-12 03:34:29
【问题描述】:

我有一个带有 ScriptManager、通用 HTML 下拉列表 (<select>) 和 UpdatePanel 的页面。 UpdatePanel 包含一个 PlaceHolder(现在)。在 Page_Load 期间,许多用户控件被添加到 PlaceHolder(实际上,它是同一个用户控件的多个实例)。在页面加载之前,要添加的数字是未知的,因此它们确实需要动态加载。下拉列表填充了相同数量的菜单项,并且页面上还有 javascript(使用 jQuery)根据下拉列表的状态一次仅显示一个控件。

每个用户控件都有两个应生成异步回发的按钮、一个应在选定值更改时生成异步回发的下拉列表和一个应生成同步回发的按钮。如果我没有动态生成控件,并且只有一个控件,则结构将类似于:

<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>

当然,ContentTemplate 中的所有控件实际上都是每个用户控件的一部分。

在服务器端添加触发器似乎不起作用,因为似乎没有 ControlID 可以帮助 UpdatePanel 找到相关控件。我可以使用控件的 ID 或控件的 UniqueID,但它不起作用,并且出现如下错误:

A control with ID 'ctl00$ContentPlaceHolder1$ctl01$asyncButton1' could not be
found for the trigger in UpdatePanel 'myUpdatePanel'.

所以,我想知道是否需要在客户端注册触发器,而不是使用 ASP.NET Ajax。我发现this page 基本上解释了如何。但是,我不知道如何考虑 EventName。到目前为止我看到的例子只是添加按钮点击,但我不知道如何处理 DropDownList 中的 SelectedIndexChanged 事件。

这里有什么帮助吗?有没有我错过的例子?当然,我提供的链接中的方法似乎是“非官方的”并没有帮助,因此我没有看到任何有关该主题的 MSDN 文档。

谢谢!

【问题讨论】:

  • 您使用的是 .net framework 4.0 吗?我问是因为现在您可以更好地控制 Control.ClientID:msdn.microsoft.com/en-us/library/…
  • @Tim 不,现在必须是 .NET 3.5。
  • 标记为 3.5。我稍后会去仔细看看。

标签: asp.net asp.net-ajax updatepanel asp.net-3.5


【解决方案1】:

我的建议是将包括此 UpdatePanel 在内的所有控件从此 UpdatePanel 中拉出到 UserControl 中。在您的用户控件中定义在单击按钮或下拉菜单的选定索引发生更改时引发的事件。在包含占位符的页面中处理这些事件(在单个 UpdatePanel 中,有条件,无触发器)。如果添加 UserControls,请手动调用主更新面板的更新方法。

为了澄清我的意思,请看以下示例:

主页aspx:

<asp:UpdatePanel ID="Upd1" runat="server" UpdateMode="Conditional">
  <ContentTemplate>
     <asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>
  </ContentTemplate>
</asp:UpdatePanel>

代码隐藏:

  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 包含您的控件:

<%@ 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>

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

这样您就不会遇到 ClientID 的问题。

补充: 如果您需要访问事件处理程序中的 UserControls 控件,请使用以下两个选项之一:

  1. 将发送者的 NamingContainer 转换为 userControl 的类型:Dim uc As DynamicControls = DirectCast(DirectCast(sender, Control).NamingContainer, DynamicControls)
  2. 将所有出现的(ByVal sender As Object, ByVal e As System.EventArgs) 替换为(uc as DynamicControls)。通过这种方式,您的 UserControl 的引用作为参数添加到事件中,您可以从页面访问它的公共属性,例如:

    dim txt1 as String = uc.Text1
    

如果您在 UserControl 中公开了一个属性 Text1:

Public Property Text1() As String
     Get
         Return textBox1.Text
     End Get
     Set(ByVal value As String)
         textBox1.Text = value
     End Set
 End Property

第二个选项是最干净和最易读的方式。

更新: 根据您的评论:您应该将 UpdateProgress 放在被更新的 UpdatePanel 内的 UserControl 中。记得正确设置AssociatedUpdatePanelID。例如:

<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..." />&nbsp;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..." />&nbsp;please wait...
            </div>
            </ProgressTemplate>
         </asp:UpdateProgress>

         Content

   </asp:Panel>
 </ContentTemplate> 
   <Triggers ></Triggers>
</asp:UpdatePanel> 

【讨论】:

  • 谢谢。我已经调试了应用程序,我认为这或多或少有效。您是否碰巧知道在这种情况下触发其中一个触发器时如何显示 UpdateProgress?我尝试将 UpdateProgress 放在页面和控件中(在这两种情况下都在实际的 UpdatePanel 之外),但在这两种情况下都没有出现。
  • @Andrew;我已经用一个对我有用的样本(为了简化而没有任何内容)更新了我的答案。它在 UserControl 中有两个更新面板。根据您的要求进行调整。
猜你喜欢
  • 2012-09-17
  • 1970-01-01
  • 2010-10-07
  • 2013-11-17
  • 2010-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-04
相关资源
最近更新 更多