views:

30

answers:

2

Hi All,

I have a GridView and, using a fairly common method, I'm using a FooterRow and TemplateFields to provide the missing insert ability. So far so good.

The footer contains a TemplateField with a LinkButton to provide the postback that does the insertion. In the handler for the LinkButton's click, the Insert() method is called on the ObjectDataSource that the GridView is bound to. The ObjectDataSource's insert parameters are populated in the handler for its Inserting event. The code for all of this (abridged) looks like this:

Markup:

<asp:GridView ID="gvComplexRates" runat="server" AutoGenerateColumns="False" 
                DataKeyNames="id" DataSourceID="odsComplexMileageRates" 
                EnableModelValidation="True" ShowFooter="True">
                <Columns>
                   <asp:TemplateField ShowHeader="False">
                        :
                        :
                        <FooterTemplate>
                            <asp:LinkButton ID="addLinkButton" runat="server" CausesValidation="false"
                                CommandName="Insert" Text="Add"></asp:LinkButton>
                        </FooterTemplate>
                    </asp:TemplateField>
                    :
                    :
</asp:GridView>

Code Behind:

Private Sub gvComplexRates_RowCommand(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewCommandEventArgs) Handles gvComplexRates.RowCommand

    Select Case e.CommandName
        Case "Insert"
            odsComplexMileageRates.Insert()
    End Select
End Sub

Private Sub odsComplexMileageRates_Inserting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.ObjectDataSourceMethodEventArgs) Handles odsComplexMileageRates.Inserting
    Dim fuelTypeDropDown As DropDownList = gvComplexRates.FooterRow.FindControl("ddFuelTypeInsert")
    Dim engineTypeDropDown As DropDownList = gvComplexRates.FooterRow.FindControl("ddEngineTypeInsert")
    Dim rateTextBox As TextBox = gvComplexRates.FooterRow.FindControl("tbRateInsert")
    Dim vatRateTextBox As TextBox = gvComplexRates.FooterRow.FindControl("tbVatRateInsert")

    e.InputParameters("expense_type_id") = ddExpenseTypeSelect.SelectedValue
    e.InputParameters("fuel_type_id") = fuelTypeDropDown.SelectedValue
    e.InputParameters("engine_type_id") = engineTypeDropDown.SelectedValue
    e.InputParameters("rate") = rateTextBox.Text
    e.InputParameters("vat_rate") = vatRateTextBox.Text
End Sub

Two of the fields in my FooterRow are DropDownLists that are populated from other tables. Again this works fine and I can add, edit and remove rows without problem.

The problem comes when I use a modal dialog from this page to insert extra rows into the tables used to populate the DropDownLists in the FooterRow. The insert operations work fine and the modal dialog closes and at this point I use a javascript postback (basically a call to __doPostBack()) so that my FooterRow DropDownLists can be updated. The code for this is:

Protected Sub updateFuelEngineDropdowns()
    odsFuelTypes.Select()
    odsEngineTypes.Select()
    Dim dropDown As DropDownList = gvComplexRates.FooterRow.FindControl("ddFuelTypeInsert")
    dropDown.DataBind()
    dropDown = gvComplexRates.FooterRow.FindControl("ddEngineTypeInsert")
    dropDown.DataBind()
End Sub

This sub, updateFuelEngineDropdowns(), is called from the Page Load event. The first time I called it it worked fine. For some reason in subsequent runs through the debugger I'm getting NullReferenceExceptions. Digging into the debug object viewer it is apparent that the GridView FooterRow is referencing the row above the footer which contains no controls (at least not at this non-editing stage) and so, quite reasonably, gives my the Null reference.

The debug QuickView expressions I use are:
gvComplexRates.FooterRow.Controls(3) DirectCast(gvComplexRates.FooterRow.Controls(3),System.Web.UI.WebControls.DataControlFieldCell).Controls(1)

The first of these shows a tag of td. Which makes sense. The second shows text of "10" which is the content for the row above the footer.

Does anybody know why this is happening?

Thanks Dan

A: 

Where are you "providing the missing insert ability"? You have to rebuild the footer-controls on every postback, the GridView.RowCreated-Event would be a good place.

Update: You have to Databind your GridView after you inserted new rows into your Dropdowns' Tables.

Tim Schmelter
Hi Tom. I've updated the question to show the code that handles the row insert. This works fine. Is there something I'm missing? I add the row to the database and it shows up in the GridView. What else would I need to do?
Dan Kendall
@Dan: updated...
Tim Schmelter
Hi Tim (apologies for calling you Tom btw). Yeah. That's all working fine. See my 'answer' post for an indication of my level of incompetence on this one. Thanks for your time.
Dan Kendall
A: 

Right, this is a bit embarrassing. I gave a little white lie in the original question. By omission rather than a deliberate attempt to mislead. I am not, in fact, using a GridView but a subclass of it that will display rows when the datasource contains no data. This enables the user to insert new rows when the table is empty. This subclass overrides the FooterRow property and, to my shame, it was this that was getting things wrong. So I made two errors here: first I failed to test my GridView subclass properly and second I sought to prevent what I thought would be unnecessary attention on my subclass by not showing its use in the code snippets I included in the question. My bad. Thanks to Tim for taking the time to try and help me.

Dan

Dan Kendall