2010-12-07 1 views
0

Ich habe seltsames Verhalten bei verschachtelten Gridview-Steuerelementen und Zeilenereignissen festgestellt. Grundsätzlich wird das verschachtelte Gridview-Zeilenereignis nicht ausgelöst, es sei denn, es befindet sich in der letzten Zeile des äußeren Rasters.Verschachteltes GridView-Zeilenereignis Pandemonium

Wenn Sie explizit die Zeilenereigniseigenschaft zum Markup (zB OnRowDeleted = „gvInner_RowDeleted“), dann die Zeilen Ereignis ausgelöst wird für alle verschachtelten Gridviews fügen aber es feuert zweimal für die verschachtelte Gridview in der letzten Reihe des äußeren gridview

EDIT: Ich sollte beachten, dass ich die SqlDataSource für die äußere gridview verwenden, da es auch editierbar ist. Dies ist im Beispiel nicht klar.

Markup:

<asp:GridView ID="gvOuter" DataSourceID="sdsOuter" runat="server" OnRowDatabound="DynamicControlAdder" AutoGenerateColumns="false"> 
    <Columns> 
     <asp:BoundField DataField="Id" ReadOnly="true" /> 
     <asp:TemplateField> 
      <ItemTemplate>   

         <asp:UpdatePanel ID="upInner" runat="server" UpdateMode="Conditional"> 
          <ContentTemplate>         
           <asp:GridView ID="gvInner" DataSourceId="sdsInner" runat="server" DataKeyNames="Id" AutoGenerateColumns="false"> 
            <Columns> 
             <asp:CommandField ShowDeleteButton="true" /> 
             <asp:BoundField DataField="Id" />            
            </Columns> 
           </asp:GridView> 
           <asp:SqlDataSource ID="sdsInner" runat="server" 
            ProviderName="<%$ ConnectionStrings:YourString.ProviderName %>" 
            ConnectionString="<%$ ConnectionStrings:YourString %>" 
            SelectCommand="SELECT * FROM tblInner WHERE OuterTableKey = @OuterTableKey" 
            DeleteCommand="DELETE FROM tblInner WHERE Id = @Id"> 
            <SelectParameters> 
             <asp:Parameter Name="OuterTableKey" DefaultValue="0" Type="Int32" /> 
            </SelectParameters> 
            <DeleteParameters> 
             <asp:Parameter Name="Id" DefaultValue="0" Type="Int32" />            
            </DeleteParameters>           
           </asp:SqlDataSource>             
          </ContentTemplate>     
         </asp:UpdatePanel>  

      </ItemTemplate> 
     </asp:TemplateField> 
    </Columns> 
</asp:GridView> 
<asp:SqlDataSource ID="sdsOuter" runat="server" 
    ProviderName="<%$ ConnectionStrings:YourString.ProviderName %>" 
    ConnectionString="<%$ ConnectionStrings:YourString %>" 
    SelectCommand="SELECT * FROM tblOuter">           
</asp:SqlDataSource> 

Code:

Partial Class Testing 
Inherits System.Web.UI.UserControl 

Protected Sub DynamicControlAdder(ByVal sender As Object, ByVal e As GridViewRowEventArgs) 

    If e.Row.RowType <> DataControlRowType.DataRow Then 
     Exit Sub 
    End If 

    Dim s As SqlDataSource = CType(e.Row.FindControl("sdsInner"), SqlDataSource) 
    s.SelectParameters("OuterTableKey").DefaultValue = e.Row.DataItem("Id").ToString() 

End Sub 

Protected Sub gvInner_RowDeleted(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewDeletedEventArgs) Handles gvInner.RowDeleted 
    //'This never fires unless it is the last row in the outer gridview 
    //'also, if this event is declared in the OnRowDeleted property of the inner gridview, this event fires twice if it is in the last row of the outer grid 
    Dim strFoo As String = "Foo" 
End Sub 
End Class 

Kann das jemand reproduzieren, und wie funktionieren sie um ihn herum?

Antwort

0

Und die Antwort ist ......

Entfernen Sie die Griffe Klausel aus dem RowDeleted Ereignis und stellen Sie die OnRowDeleted Property zum gvInner_RowDeleted-Ereignis.

Aktualisierter Code unten. Ich wünschte nur, ich hätte die letzten 4 Stunden meines Lebens zurück.

Markup:

<asp:GridView ID="gvOuter" DataSourceID="sdsOuter" runat="server" OnRowDatabound="DynamicControlAdder" AutoGenerateColumns="false"> 
    <Columns> 
     <asp:BoundField DataField="Id" ReadOnly="true" /> 
     <asp:TemplateField> 
      <ItemTemplate>   

         <asp:UpdatePanel ID="upInner" runat="server" UpdateMode="Conditional"> 
          <ContentTemplate>         
           <asp:GridView ID="gvInner" DataSourceId="sdsInner" runat="server" DataKeyNames="Id" OnRowDeleted="gvInner_RowDeleted" AutoGenerateColumns="false"> 
            <Columns> 
             <asp:CommandField ShowDeleteButton="true" /> 
             <asp:BoundField DataField="Id" />            
            </Columns> 
           </asp:GridView> 
           <asp:SqlDataSource ID="sdsInner" runat="server" 
            ProviderName="<%$ ConnectionStrings:YourString.ProviderName %>" 
            ConnectionString="<%$ ConnectionStrings:YourString %>" 
            SelectCommand="SELECT * FROM tblInner WHERE OuterTableKey = @OuterTableKey" 
            DeleteCommand="DELETE FROM tblInner WHERE Id = @Id"> 
            <SelectParameters> 
             <asp:Parameter Name="OuterTableKey" DefaultValue="0" Type="Int32" /> 
            </SelectParameters> 
            <DeleteParameters> 
             <asp:Parameter Name="Id" DefaultValue="0" Type="Int32" />            
            </DeleteParameters>           
           </asp:SqlDataSource>             
          </ContentTemplate>     
         </asp:UpdatePanel>  

      </ItemTemplate> 
     </asp:TemplateField> 
    </Columns> 
</asp:GridView> 
<asp:SqlDataSource ID="sdsOuter" runat="server" 
    ProviderName="<%$ ConnectionStrings:YourString.ProviderName %>" 
    ConnectionString="<%$ ConnectionStrings:YourString %>" 
    SelectCommand="SELECT * FROM tblOuter">           
</asp:SqlDataSource> 

Code:

Partial Class Testing 
Inherits System.Web.UI.UserControl 

Protected Sub DynamicControlAdder(ByVal sender As Object, ByVal e As GridViewRowEventArgs) 

    If e.Row.RowType <> DataControlRowType.DataRow Then 
     Exit Sub 
    End If 

    Dim s As SqlDataSource = CType(e.Row.FindControl("sdsInner"), SqlDataSource) 
    s.SelectParameters("OuterTableKey").DefaultValue = e.Row.DataItem("Id").ToString() 

End Sub 

Protected Sub gvInner_RowDeleted(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewDeletedEventArgs) 
    //' Now we're talking 
    Dim strFoo As String = "Foo" 
End Sub 
End Class 
0

Ich glaube nicht, dass Sie tun sollten, was Sie tun, wie Sie es tun.

Hier ist, wie ich tun würde, was Sie versuchen:

  1. einen Repeater für Ihre äußere Databound-Steuerung verwenden, da es effizienter macht und es wird die gleiche Wirkung haben Sie versuchen, mit dem äußeren zu erreichen Gridview-Kontrolle.
  2. In Ihrem Code hinter, holen Sie Ihre Daten für Ihre äußere gridview (die jetzt ein Repeater ist) und laden Sie es in eine Datentabelle und fügen Sie es zu einem Dataset, machen Sie das gleiche für Daten in der inneren Gridview.
  3. Dann eine Beziehung zwischen den Datentabellen innerhalb des Datensatzes mit DataSet.Relations.Add
  4. erstellen Nachdem Sie die Beziehung zwischen den beiden Datentabellen in dem Datensatz erstellen, können Sie die Felder zugreifen können (Spalten) in der zweiten Datentabelle, die verwendet wird um die Daten für das verschachtelte (innere) Gridview-Steuerelement aufzufüllen.

Markup

<asp:Repeater ID="rpt1" runat="server"> 
    <ItemTemplate> 
     <asp:GridView ID="gv1" runat="server" DataSource='<%# Container.DataItem.Row.GetChildRows("relation1") %>' GridLines="None" AutoGenerateColumns="false"> 
      <columns> 
       <asp:TemplateField> 
        <ItemTemplate> 
         <asp:TextBox ID="txt1" runat="server" Text='<%# Container.DataItem("<column>") %>'></asp:TextBox> 
        </ItemTemplate> 
       </asp:TemplateField> 
      </columns> 
     </asp:GridView> 
    </ItemTemplate> 
</asp:Repeater> 

Code hinter

Dim ds As New DataSet 
Dim dt1 As DataTable = obj.<method> 'Outer data 
Dim dt2 As DataTable = obj.<method> 'Inner data 

ds.Tables.Add(dt1) 
ds.Tables.Add(dt2) 

ds.Relations.Add("relation1", ds.Tables(0).Columns("<unique identifier column name>"), ds.Tables(1).Columns("<unique id column name>"), False) 

rpt1.DataSource = dt1 
rpt1.DataBind() 
+0

Danke für die Antwort, aber es gibt Gründe, warum ich es so mache, die außerhalb des Rahmens meiner vereinfachten Beispiel sind . Zum Beispiel nutzen sowohl die innere als auch die äußere Rasteransicht die automatische Editier-/Aktualisierungsfunktionalität von SqlDataSource. Wenn ich einen Repeater verwenden würde, müsste ich die für PostBacks problematischen Steuerelemente dynamisch hinzufügen. – plntxt

+0

Sie können weiterhin eine sqldatasource mit der verschachtelten Gridview verwenden, die eine Beziehung zum untergeordneten Datenelement des Repeater-Steuerelements hat. Der Grund, warum ich darauf hingewiesen habe, war, dass IMO ich dachte, dass Ihr äußeres gridview-Steuerelement nichts aktualisiert hat, nur die verschachtelte Gridview hat Updates verarbeitet. Ich meine, so sieht dein Code aus. –

+0

Wenn Sie nichts geändert haben, müssen Sie den rowIndex der outergridview ermitteln, dann den rowIndex der verschachtelten Gridview abrufen und das Update auf dieser gridviewrow ausführen –