2011-01-20 9 views
5

Mam stronę z ScriptManager, ogólną rozwijaną listą HTML (<select>) i UpdatePanel. UpdatePanel zawiera PlaceHolder (na razie). Podczas Page_Load do PlaceHolder dodawana jest pewna liczba elementów sterujących użytkownika (tak naprawdę jest to kilka instancji tej samej kontrolki użytkownika). Liczba do dodania nie jest znana, dopóki strona się nie załaduje, więc muszą być ładowane dynamicznie. Lista rozwijana zawiera tę samą liczbę pozycji menu, a na stronie jest również javascript (przy użyciu jQuery), aby wyświetlić tylko jedną z kontrolek na raz w zależności od stanu listy rozwijanej.Dodawanie PostBackTriggers i AsyncPostBackTriggers do UpdatePanel dla dynamicznie generowanych kontrolek wnuków

Każdy element sterujący użytkownika ma dwa przyciski, które powinny generować asynchroniczny oddzwonienie, listę rozwijaną, która powinna generować asynchroniczny odświeżenie po zmianie wybranej wartości, oraz przycisk, który powinien generować synchroniczny odświeżenie. Gdybym nie był generowania dynamicznie kontroli, a jeśli była tylko jedna kontrola, struktura będzie coś takiego:

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

Oczywiście, wszystkie kontrole wewnątrz ContentTemplate rzeczywiście być częścią każdej kontroli użytkownika.

Dodanie wyzwalaczy po stronie serwera wydaje się nie działać, ponieważ żaden identyfikator ControlID nie pomaga, aby UpdatePanel znalazł odpowiednie elementy sterujące. Mogę użyć identyfikatora kontrolki lub UniqueID kontrolki, i to nie działa i pojawia się błąd wzdłuż linii

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

tak, to zastanawiam się, czy muszę się zarejestrować wyzwalacze w kliencie zamiast korzystania Ajax ASP.NET. Znalazłem this page, który zasadniczo wyjaśnia, w jaki sposób. Jednak nie wiem, jak wziąć EventName pod uwagę. Przykłady, które do tej pory widziałem, dodawały jedynie kliknięcia przycisków, ale nie wiem, jak obsługiwać zdarzenie SelectedIndexChanged z DropDownList.

Każda pomoc tutaj? Czy istnieją przykłady, które przeoczyłem? Nie pomaga oczywiście, że metoda podana w linku, który podałem, wydaje się "nieoficjalna", więc nie widzę żadnych dokumentów MSDN na ten temat.

Dzięki!

+0

Czy korzystasz z .net framework 4.0? Pytam, ponieważ teraz masz większą kontrolę nad Control.ClientID: http://msdn.microsoft.com/en-us/library/system.web.ui.control.clientid.aspx –

+0

@Tim No, to musi być. NET 3.5 na razie. – Andrew

+0

oznaczony jako 3.5. Później przyjrzę się bliżej. –

Odpowiedz

6

Moja sugestia to wyciągnięcie wszystkich kontrolek zawierających ten UpdatePanel z tego UpdatePanel do UserControl. Zdefiniuj zdarzenia w swojej kontroli użytkownika, które są wywoływane po kliknięciu przycisków lub zmianie wybranego indeksu Dropdown. Przetwarzaj te zdarzenia na stronie, która zawiera symbol zastępczy (w pojedynczym module UpdatePanel, warunkowym, bez wyzwalaczy). Jeśli dodałeś UserControls, wywołaj ręcznie metodę aktualizacji głównego panelu aktualizacji.

Aby wyjaśnić, co mam na myśli, spojrzeć na poniższy przykład:

Main-strona aspx:

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

kodzie:

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 która posiada swoje formanty:

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

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

W ten sposób nie będzie miał problemów z ClientID tych.

Dodatek: Jeśli potrzebujesz dostępu do kontroli swoich UserControls w przypadku-ładowarki, użyj jednej z następujących dwóch opcji:

  1. cast NamingContainer nadawcy do typu usercontrol za: Dim uc As DynamicControls = DirectCast(DirectCast(sender, Control).NamingContainer, DynamicControls)
  2. Zamień wszystkie wystąpienia (ByVal sender As Object, ByVal e As System.EventArgs) na (uc as DynamicControls). Na tej drodze odniesienie Twojego UserControl jest dodawany do zdarzenia jako parametr i można uzyskać dostęp do właściwości publiczne niego ze strony, Fe

    dim txt1 as String = uc.Text1 
    

Jeśli narażona właściwość text1 w UserControl:

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

Druga opcja to najczystszy i najbardziej czytelny sposób.

Aktualizacja: Według komentarza: należy umieścić UpdateProgress w UserControl wewnątrz UpdatePanel, że jest aktualizowany. Pamiętaj, aby prawidłowo ustawić AssociatedUpdatePanelID. Na przykład:

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

Dzięki. Mam debugowanie aplikacji i myślę, że to mniej lub więcej działa. Czy zdajesz sobie sprawę, jak uzyskać UpdateProgress do wyświetlenia, gdy jeden z wyzwalaczy jest, dobrze, wyzwalane w tej sytuacji? Próbowałem umieszczania UpdateProgress na stronie i kontroli (poza rzeczywistą UpdatePanel w obu przypadkach), w żadnym przypadku nie pojawia się. – Andrew

+0

@Andrew; zaktualizowałem swoją odpowiedź próbką (aby uprościć bez żadnych treści), która działa dla mnie. Ma on dwa znaczniki aktualizacji wewnątrz kontrolki UserControl. Dostosuj go do swoich wymagań. –

+0

Dzięki za pomoc! – Andrew