0

So I have a gridview that I'm populating in the code behind, listening to a drop down to know what to populate. That part works fine. But when I fire the rowediting event from the gridview, the databind process throws a NullReferenceException error.

Here is the page:

<asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
    <asp:UpdatePanel ID="UpdatePanel1" runat="server">
        <ContentTemplate>

            <div id="categories">
                <h1>Categories</h1>
                <asp:DropDownList ID="ddlCategories" 
                    runat="server"
                    OnSelectedIndexChanged="ddlCategories_SelectedIndexChanged"          
                    AutoPostBack="true"></asp:DropDownList>
            </div>
            <div id="products">
                <h1>Products</h1>
                <asp:GridView ID="gvProducts" 
                    runat="server"
                    AutoGenerateColumns="false" 
                    OnRowEditing="gvProducts_RowEditing" 
                    AutoGenerateDeleteButton="True" 
                    AutoGenerateEditButton="True"
                    OnRowCancelingEdit="gvProducts_RowCancelingEdit"
                    OnRowUpdating="gvProducts_RowUpdating">
                    <Columns>
                        <asp:BoundField
                            DataField="Category.Name"
                            HeaderText="Category" />
                        <asp:BoundField
                            Datafield="Name" 
                            HeaderText="Name"/>
                        <asp:BoundField
                            Datafield="Description" 
                            HeaderText="Description"/>
                        <asp:BoundField
                            DataField="Price" 
                            HeaderText="Price"
                            DataFormatString="{0:c}" 
                            HtmlEncode="False"/>
                        <asp:ImageField
                            DataImageUrlField="ImageURL"
                            HeaderText="Picture"></asp:ImageField>
                        <asp:CheckBoxField
                            DataField="Active"
                            Text="Active" 
                            HeaderText="Status"/>
                    </Columns>
                </asp:GridView>
            </div>

        </ContentTemplate>
    </asp:UpdatePanel>

And here is the code behind:

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            BindCategoryList();
            BindProductList();
        }
    }

    protected void BindCategoryList()
    {
        ddlCategories.DataTextField = "Name";
        ddlCategories.DataValueField = "CategoryID";
        ddlCategories.DataSource = CategoryDB.GetCategories();
        ddlCategories.DataBind();
        ddlCategories.Items.Insert(0, new ListItem(string.Empty));
        ddlCategories.SelectedIndex = 0;
    }

    protected void BindProductList(int categoryID = 0)
    {
        gvProducts.DataSource = ProductDB.GetProductsByCategory(categoryID);
        gvProducts.DataBind();
    }

    protected void ddlCategories_SelectedIndexChanged(object sender, EventArgs e)
    {
        BindProductList(Int32.Parse(ddlCategories.SelectedValue));
    }

    protected void gvProducts_RowEditing(object sender, GridViewEditEventArgs e)
    {
        gvProducts.EditIndex = e.NewEditIndex;
        BindProductList(Int32.Parse(ddlCategories.SelectedValue));
    }

The error occurs in the BindProductList() method, but only when called from gvProducts_RowEditing. Otherwise, it works fine. When I debug, I can see that it definitely is passing the correct categoryID value, and it does not throw an error until the DataBind call, which means that it can still find gvProducts for the DataSource() call.

Any ideas? Thanks.

Edit: here is the categorydb class and getcategories method.

public class CategoryDB
{
    public static List<Category> GetCategories()
    {
        using (var db = new ProductContext())
        {
            return (from c in db.Categories
                    orderby c.Name
                    select c).ToList<Category>();
        }
    }
Michael
  • 33
  • 1
  • 6

6 Answers6

1

I am not sure but i think you need this for each one of the columns i think you are missing the row to be edited

 <asp:TemplateField headertext="Category.Name">
          <ItemTemplate> <%#Eval("Category.Name")%></ItemTemplate>   
          <EditItemTemplate>
               <asp:TextBox id="txtCategory.Name" runat="server" Enabled="False" text='<%#Eval("Category.Name")%>'/>
          </EditItemTemplate>                
          <FooterTemplate>
         <asp:TextBox ID="Category.Name" runat="server">     </asp:TextBox>           
    </FooterTemplate >
      </asp:TemplateField> 

i am not sure how you are calling the edit but i would sugest another column for it

<asp:TemplateField>
         <ItemTemplate>
              <asp:LinkButton ID="btnedit" runat="server" CommandName="Edit" Text="Edit"/>       
         </ItemTemplate>
          <EditItemTemplate>
              <asp:LinkButton ID="btnupdate" runat="server" CommandName="Update" Text="Update" />
              <asp:LinkButton ID="btncancel" runat="server" CommandName="Cancel" Text="Cancel"/>
              <asp:LinkButton ID="btnDelete" runat="server" CommandName="Delete" Text="Delete"/>
          </EditItemTemplate>
          <FooterTemplate>
            <asp:Button ID="btnInsert" runat="Server" Text="Insert" CommandName="Insert" UseSubmitBehavior="False" />
          </FooterTemplate>
      </asp:TemplateField> 
user2615302
  • 194
  • 2
  • 14
1

The other folks may have already solved your problem but here's another suggestion. I've had trouble with the SelectedValue attribute of ddl's before so you might try using:

BindProductList(Int32.Parse(ddlCategories.SelectedItem.Value));

You said that your function works when called other places though, right? Does it only work on page load or does the selected index change work also?

Out of curiosity, why are you using the ID from the ddl in the Edit event? I would think you would want to use the category derived from the row you are editing.

Lexi847942
  • 71
  • 1
  • 5
  • It works with both page load and when selected index changes. The only time the bind fails is when attempting to edit. I know that it is getting the correct categoryID from the ddl, and I've also tried hard coding an ID to confirm that it is definitely just the DataBind() method that is failing. I'm using the ID to determine what records to show in the gridview. All records displayed must have the same category. – Michael Nov 01 '13 at 13:24
  • The only other thing I can think of, move your EditIndex statement below the DataBind statement? Wonder if there is something weird happening there – dgarbacz Nov 01 '13 at 14:12
0

You might want to set the GridViewEditEventArgs.Cancel property to true.

Abhinav
  • 2,085
  • 1
  • 18
  • 31
0

You have an empty value set as a ListItem here which means that your Dropdown item will be Text="" and Value=""

ddlCategories.Items.Insert(0, new ListItem(string.Empty));

There could be a possibility that your ddlCategories.SelectedValue is "". If the ProductDB.GetProductsByCategory method doesn't come back with any records, it will bind a blank result set, and then try to throw the grid into edit mode on an index that no longer exists.

Check that out and see if it gives you any insight into what might be happening there.

Typically I set my placeholder values in DropDownLists as

ddlCategories.Items.Insert(0, new ListItem("Select a category", "0")) 

or

ddlCategories.Items.Insert(0, new ListItem("", "NULL"))

Then before I do my value parsing I always can do an if statement to ensure they didn't select the placeholder value after selecting something is valid.

In this case if you are always expecting an int, the first statement is probably the better option so you know you're never parsing a blank string or whatever filler value you use as a string as an int.

dgarbacz
  • 962
  • 1
  • 7
  • 17
0

Thought of something else since I realize your grid is in an UpdatePanel. It seems like you're having a similar problem to a problem I had before (not exactly but seems like it could be related) Gridview Row Events not firing in UserControl

Take the Grid out of the update panel and try it, I bet it will work fine. The reference I used to find my problem was this link here

When your DataSource changes and you are rebinding on an async call, there is the potential for their IDs to be overwritten and therefore your ScriptManager loses the reference it had to the previous rows in the callback. Especially if your data source is changing.

I've found that UpdatePanels are just not worth it, especially when dealing with problems like these. If you are still set on using it though, take a look at my question to find out how I managed to solve the problem. It was not very pretty, and my situation dealt with dynamic controls, but maybe it will help.

Community
  • 1
  • 1
dgarbacz
  • 962
  • 1
  • 7
  • 17
  • Just tried removing the script manager, update panel, and content template, but still having the same issue. – Michael Nov 01 '13 at 14:29
  • Check when the Products are fetched that `Category.Name` is actually holding a value. Either in Watch or Immediate Window, check that out and see if it throws the exception on you. – dgarbacz Nov 01 '13 at 14:46
  • Yes, category.name has a value when products are fetched. – Michael Nov 01 '13 at 14:54
  • Is there any extra stack trace information you can add to the question or show which control is actually causing the NullReferenceException? – dgarbacz Nov 01 '13 at 14:55
0

Found it. The error was occurring in the ImageField column. The value from the database was null, which was apparently a problem when trying to edit. It works fine when I comment out the ImageField. I'll have to figure out how to handle that.

Michael
  • 33
  • 1
  • 6