C# – GridView RowUpdating does not get the new values

ceventsgridview

I have at the moment a problem with RowUpdating from a GridView and accessing the new values. I add a dynamic DataTable to my GridView.DataSource and bind to it. If I use the update button nothing happens and I get back to my normal GridView.
Here's my Page_Load event:

protected void Page_Load(object sender, EventArgs e)
{
    Control test = GetPostBackControl(Page);
    if (Page.IsPostBack)
    {
        if ((test.ID == "SumbitSearch") && (DropDownListFrom.Text != "") && (DropDownListTo.Text != "") && (SearchField.Text != ""))
        {
            DataTable result = new DataTable();
            string from = null;
            string to = null;

            switch (DropDownListFrom.SelectedIndex)
            {
                case 0:
                    from = DropDownListFrom.Items[0].Value;
                    break;
                case 1:
                    from = DropDownListFrom.Items[1].Value;
                    break;
                case 2:
                    from = DropDownListFrom.Items[2].Value;
                    break;
            }

            switch (DropDownListTo.SelectedIndex)
            {
                case 0:
                    to = DropDownListTo.Items[0].Value;
                    break;
                case 1:
                    to = DropDownListTo.Items[1].Value;
                    break;
                case 2:
                    to = DropDownListTo.Items[2].Value;
                    break;
            }

            result = LoadGridView(from, to);
            GridViewResult.DataSource = result;
            Session["Result"] = result;
            GridViewResult.DataBind();

            GridViewResult.Columns[0].Visible = true;
            GridViewResult.Columns[1].Visible = true;

            GridViewResult.HeaderRow.Cells[0].Width = Unit.Pixel(110);
            GridViewResult.HeaderRow.Cells[1].Width = Unit.Pixel(60);
            GridViewResult.HeaderRow.Cells[3].Text = "Nach: " + from;
            GridViewResult.HeaderRow.Cells[4].Text = "Von: " + to;
        }
    }
    else
    {
        GridViewResult.DataBind();
    }
}

Later, the GridView should only appear if both DropDownLists are used and the SearchField is not empty. I also check if the button which execute the PostBack is the search button.

Here is what I added to the RowUpdating EventHandler:

protected void TaskGridViewResult_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
    GridViewResult.DataSource = (DataTable)Session["Result"];
    for (int i = 0; i < GridViewResult.Columns.Count; i++)
    {
        DataControlFieldCell cell = GridViewResult.Rows[e.RowIndex].Cells[i] as DataControlFieldCell;
        GridViewResult.Columns[i].ExtractValuesFromCell(e.NewValues, cell, DataControlRowState.Edit, true);
    }

    GridViewResult.EditIndex = -1;
    DataBind();
}

What is going wrong?

Last Change: More Information (@jwiscarson)

I’m sorry, I was in hurry. I will try to give you a better view.
In that project, the users could select 2 categories, enter a search string and the result will show in a GridView. The RowUpdating stuff is for the "admin user".
Here is my problem, if the "admin user" click on edit, change the value of the cell and execute the update, the value would not changed in the DataTable.

Without seeing your markup, it's hard for […] based on some search
criteria?

I add GridViewResult as markup in my project.

I'm also not sure why […] within that button's Click event.

Yes, I thought that too! But I read in a blog it is better to put the code into Page_Load(), if you are working with GridViews. I believed him. Is it okay, to put that code into the click event handler from my button? I'm very new to that. I just could read lots of blogs, msdn and ask here.

TaskGridViewResult_RowUpdating is also added as markup to my code. Could I also create this and the GridView in my CreateChildControls()?

As markups I have two DropDownLists, a TextBox for the search string, a search submit Button and the GridView.

At the moment, i havent the exactly code here but the GridView looks like:

<asp:GridView ID="GridView1" runat="server"
    OnRowUpdating="TaskGridViewResult_RowUpdating">
    <!-- // More of that... -->
    <Columns>
        <asp:CommandField ShowEditButton="True" />
        <asp:CommandField ShowDeleteButton="True" />
    </Columns>
</asp:GridView>

I could give you more details tomorrow.

Maybe I forgot this. Before I could click the update button and execute the TaskGridViewResult_RowUpdating event to change the value of the cell. I set the row editable with:

 protected void TaskGridViewResult _RowEditing(object sender, GridViewEditEventArgs e)
  {
    GridViewResult.EditIndex = e.NewEditIndex;
    DataBind();
  }

Next Change:
I added to the GridView few TemplateFields like:

<asp:TemplateField HeaderText="test">
    <EditItemTemplate>
        <asp:TextBox ID="TextBox1" runat="server" Text='<%# Bind("from") %>'>   </asp:TextBox>
    </EditItemTemplate>
    <ItemTemplate>
        <asp:Label ID="Label2" runat="server" Text='<%# Bind("from") %>'></asp:Label>
    </ItemTemplate>
</asp:TemplateField>

This is it, I have access to the new value with:

string test = ((TextBox)row.FindControl("TextBox1")).Text;

in TaskGridViewResult_RowUpdating()

Now, I just have to bind the template dynamically with the values from the dropdown list, and that’s it I think.

Thanks!

Best Answer

Hoo boy.

You didn't ask this in your question, but you've written some smelly code here. I'll try to address your question, but I'm also going through some of the other problems here.

Without seeing your markup, it's hard for me to tell if you've created GridViewResult programmatically or if it's in your markup as well. I'm not exactly sure what TaskGridViewResult is either -- is this an event for GridViewResult? Do you have another GridView on your page, and you want to show GridViewResult based on some search criteria?

I'm also not sure why you put all of your GridView binding code in Page_Load. I see that you're checking GetPostBackControl to find the control that caused the PostBack -- this is a code smell. If your users have to click a specific "Search" button, you should isolate your GridView binding code within that button's Click event.

Anyway, as to TaskGridViewResult_RowUpdating:

It looks like you're trying to update GridViewResult's old values to the new values by setting its DataSource and then iterating through its data. You can't do that. What happens when you change your RowUpdating event to:

protected void TaskGridViewResult_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
    GridViewResult.DataSource = (DataTable)Session["Result"];
    GridViewResult.DataBind();
}

Now, other asides:

Your switch statements are code smells. DropDownLists expose a property called SelectedValue -- if you have some default value that isn't a valid selection (like the first option in your DropDownList), then you can change your original code from:

if ((test.ID == "SumbitSearch") && (DropDownListFrom.Text != "") && (DropDownListTo.Text != "") && (SearchField.Text != ""))
{
    string from = string.Empty;
    string to = string.Empty;

    switch (DropDownListFrom.SelectedIndex)
    {
        case 0:
            from = DropDownListFrom.Items[0].Value;
            break;
        /* other cases */
    }

    switch (DropDownListTo.SelectedIndex)
    {
        case 0:
            to = DropDownListTo.Items[0].Value;
            break;
        /* other cases */
    }
    /* snip */
}

to:

if (test.ID == "SubmitSearch" && DropDownListFrom.SelectedIndex > 0 && DropDownListTo.SelectedIndex > 0 && SearchField.Text != "")
{
    string from = DropDownListFrom.SelectedValue;
    string to = DropDownListTo.SelectedValue;

    /* snip */
}

If you can, please post your markup. I can offer you some more specific help or advice if I can tell what Controls you have on your page, and how they interact.

Edit: I should also add that you should get in the habit of using String.IsNullOrEmpty(string variable), rather than comparing to "". Although this isn't as big of a problem when you're referencing the text from web controls, getting in the habit now will prevent you from serious headaches and inefficiently checking for null and empty later. If you're in .NET 4.0, you should have access to IsNullOrWhiteSpace(), which is (in my opinion) more useful on the web, where users are more likely to try to enter junk data.

Edit 2: In response to your additional details above:

In your RowUpdating event, you need to pull the new values out of the front-end controls, and then re-bind your data. It looks like your source code is pretty close to the MSDN source code here. The difference between your code and the code on MSDN is: - The MSDN code takes the new data from the edited row and updates the appropriate data in the Session variable with that new data. - The MSDN code has a BindData() function -- I'm not sure if this is what your DataBind() function is, however. - The MSDN code updates the GridView by re-binding the GridView to the appropriate data in the Session.

Frankly, I have some issues with the MSDN code. I really, really hate seeing code like: dt.Rows[row.DataItemIndex]["Id"] = ((TextBox)(row.Cells[1].Controls[0])).Text; To me, this is garbage, because it's so highly coupled to the order of your cells.

If I had written the code, I would explicitly create all the front-end controls and use a binding command (if you aren't familiar, it looks like <%# DataBinder.GetPropertyValue(Container.DataItem, "FieldName") %> in the markup -- see more details here). Then, in my RowUpdating event, I'd use e.Row.FindControl("controlName"), and update the Session data from that.

Honestly, if your back-end data isn't changing on a regular basis, I don't see any reason to programmatically create your GridViews. It over-complicates your C# code to go through these steps yourself when you can just set it up once in your markup. If you need to hide one GridView, you can always set its Visible property to false. Then, when you're ready to show it, set Visible = true.

Finally, I've spread my GridView code across so many events (button clicks, RowDataBound events from other GridViews/Repeaters, etc.), I can't imagine why someone would suggest that you only put it in Page_Load.

Related Topic