1
votes

How does asp.net parse the GridView? Suppose I have defined both EditItemTemplate and ItemTemplate. It seems that I can't do any data bound at the loading time to the controls like dropdownlist in the EditItemTemplate.

And is it true that the data will be bound to the controls in the EditItemTemplate when the Edit mode is activated? If not, how to bind all controls at the loading time in C#?

Thanks, this is actually driving me crazy. I can't find anything about how asp.net execute or evaluate the GridView online.

3

3 Answers

1
votes

You need to bind at when it is put into edit mode. Remember the edit controls do not exist until the it is set to edit mode for a specific row. At that time the controls are available to be bound.

Normally if you have common lookup type data you want to bind at edit mode, I load it into Cache, Session or ViewState (depending on content and situation) the first time it is needed and then bind it from this 'cached' location to save DB calls. I normally implement the OnDataBinding method for each control within the EditItemTemplate that need special binding like a DropDownList.

In your aspx:

<EditItemTemplate>
    <asp:DropDownList ID="yourDropDownList" runat="server" 
        OnDataBinding="yourDropDownList_DataBinding"></asp:DropDownList>
</EditItemTemplate>

Then in your codebehind:

protected void yourDropDownList_DataBinding(object sender, System.EventArgs e) 
{ 
    DropDownList ddl = (DropDownList)(sender);
    // do you databinding code here

    // this is an example
    ddl.DataSource = GetMyDropDownListData();
    ddl.DataBind();
    ddl.SelectedValue = Eval("FieldFromGridData");
}

I prefer to bind this way as it will localizes the code to specific controls and your don't have to go looking for them using FindControl on rows etc...

The yourDropDownList_DataBinding will only fire for the row in edit mode. On your initial bind where nothing is in edit mode, the databinding will not fire but each time you put a row into edit mode it will execute, that is why I say to somehow cache the data you want to bind to a DropDownList the first time you get it.

0
votes

There are a number of options for databinding nested controls in the GridView templates.

The easiest, and the one I use when I can, is to use an ObjectDataSource and bind your dropdownlist to that.

If this isn't an option, then you can bind in the RowDataBound event. The example on MSDN is lacking, but if you follow that example (C#), and where it says:

 // Display the company name in italics.
      e.Row.Cells[1].Text = "<i>" + e.Row.Cells[1].Text + "</i>";

You would have something like:

DropDownList ddlWhatever = e.Row.FindControl("ddlWhatever") as DropDownList;
if(ddlWhatever != null) { /* bind data to it and call ddlWhatever.DataBind(); */ }

Since the EditItemTemplate and the InsertItemTemplate aren't rendered at the same time, I usually keep the control names the same in each template to simplify the databound event in the code behind. But, there's nothing stopping you from having a ddlEditItems and a ddlInsertItems and binding those differently in the databound event.

Another trick I've used before is binding to the DropDownList with the OnInit event of the dropdown. For instance:

// web form
<asp:DropDownList id="ddlWhatever" AutoPostBack="True" 
     runat="server" OnInit="ddlWhatever_Init">

// Code behind
protected void ddlWhatever_Init(object s, EventArgs a)
{       
   object[] years = {
     new { Year = 2009 }, new { Year = 2010 }
   };
   ddlWhatever.DataSource = years;
   ddlWhatever.DataTextField = "Year";
   ddlWhatever.DataValueField = "Year";
   ddlWhatever.DataBind();
}

I've had some people tell me not to do it this last way (i.e. a control shouldn't be responsible for binding itself). I disagree, and don't recall seeing anything related to that claim in Microsoft's Framework Design Guidelines. When it all comes down to it, I like the last way when I can't use an ObjectDataSource, but I do have to also code to the acceptance level of fellow developers. :D

The rules I usually stick with:

  1. Use ObjectDataSource when it's quick and easy
  2. Use GridView RowDataBound when the nested control's items are dependent on other values in the GridView
  3. Use the OnInit method if you're just binding data, keeping in mind that you can't access other controls when this method is fired (e.g. GridView may not have been initialized yet)

I hope that helps, I went through similar frustration with the MSDN's lack of GridView examples.

0
votes

Try set your grid up using Eval to get the data from your gridview's datasource.

    <asp:GridView ID="gv" runat="server" SkinID="gridviewSkin" AutoGenerateColumns="False" DataKeyNames="Id"
                AutoGenerateEditButton="false"
                OnRowEditing="GvItems_RowEditing"
                OnRowCancelingEdit="GvItems_RowCancelingEdit"
                OnRowUpdating="GvItems_RowUpdating"
                OnPageIndexChanging="Gv_PageIndexChanging"
                AllowPaging="true"
                PageSize="20"
        >
    <Columns>
        <asp:CommandField ShowEditButton="True" CausesValidation="true" />
        <asp:TemplateField HeaderText="Name" ItemStyle-Width="200" ItemStyle-VerticalAlign="Top">
            <ItemTemplate>
                <%# Eval("Name")%>
            </ItemTemplate>
            <EditItemTemplate>        
                <asp:TextBox ID="txtName" runat="server" Width="200" Text='<%# Eval("Name") %>' MaxLength="50" />
                <asp:RequiredFieldValidator ID="rfv_txtName" runat="server" ControlToValidate="txtName" Display="Dynamic" ErrorMessage="(Required)" />
            </EditItemTemplate>
        </asp:TemplateField>    
        <asp:TemplateField HeaderText="Active" ItemStyle-Width="100" ItemStyle-HorizontalAlign="Center">
            <ItemTemplate>
                <asp:CheckBox ID="chkActive_Item" runat="server" Checked='<%# (bool)Eval("IsActive")%>' Enabled="false" />
            </ItemTemplate>
            <EditItemTemplate>
                <asp:CheckBox ID="chkActive_Edit" runat="server" Checked='<%# (bool)Eval("IsActive")%>' />
            </EditItemTemplate>
        </asp:TemplateField>        
    </Columns>
    <EmptyDataTemplate>No items exist</EmptyDataTemplate>
</asp:GridView>

To edit, then

protected void GvItems_RowEditing(object sender, GridViewEditEventArgs e)
{
   gv.EditIndex = e.NewEditIndex;

   //also reload and bind the items

}

For loading of dropdown datasources:

        <asp:TemplateField HeaderText="Channel Type" ItemStyle-Width="200" ItemStyle-VerticalAlign="Top">
            <ItemTemplate>
                <%# Eval("ChannelType.Name") %>
            </ItemTemplate>
            <EditItemTemplate>
                <asp:DropDownList ID="ddlChannelType" runat="server" DataSource="<%# GetChannelTypeDropdownBoxDataSource() %>" DataTextField="Name" DataValueField="Id" AppendDataBoundItems="true" SelectedValue='<%# Eval("ChannelId") %>' />
            </EditItemTemplate>
        </asp:TemplateField>

And get your code to return a datasource:

    protected ChannelType[] GetChannelTypeDropdownBoxDataSource()
    {
        return _channelTypeRepository.GetAll();
    }