Добавление PostBackTriggers и AsyncPostBackTriggers в UpdatePanel для динамически генерируемых элементов управления внуков - PullRequest
5 голосов
/ 20 января 2011

У меня есть страница с 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 найти соответствующие элементы управления.Я могу использовать либо идентификатор элемента управления, либо его уникальный идентификатор, и он не работает, и я получаю сообщение об ошибке

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

Итак, мне интересно, нужно ли регистрировать триггеры в клиенте?вместо этого используя ASP.NET Ajax.Я нашел эту страницу , которая в основном объясняет как.Однако я не знаю, как принять EventName во внимание.Примеры, которые я видел до сих пор, просто добавляли нажатия на кнопки, но я не знаю, как обрабатывать событие SelectedIndexChanged из DropDownList.

Любая помощь здесь?Есть ли примеры, которые я пропустил?Конечно, не помогает, что метод в приведенной мной ссылке выглядит «неофициальным», поэтому я не вижу никаких документов MSDN по этому вопросу.

Спасибо!

1 Ответ

6 голосов
/ 24 января 2011

Мое предложение состояло бы в том, чтобы вытянуть все ваши элементы управления, включая эту UpdatePanel, из этой UpdatePanel в UserControl.Определите события в вашем пользовательском контроле, которые возникают при нажатии кнопок или изменении выбранного индекса выпадающего меню.Обработайте эти события на своей странице, которая содержит заполнитель (в одной UpdatePanel, условно, без триггеров).Вызовите метод Update главной панели обновлений вручную, если вы добавите 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>

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

На этом пути у вас не будет проблем с 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
    

Если вы выставили свойствоText1 в UserControl:

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

Второй вариант является наиболее чистым и читаемым.

Обновление : Согласно вашему комментарию: вы должны поместить UpdateProgress вUserControl внутри UpdatePanel, который обновляется.Не забудьте правильно установить 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> 
...