简体   繁体   中英

ASP.NET DataGrid is empty

I have a ASP.NET datagrid which is on a user control. I have a main page which adds the user control ( sometimes multiple copies of the user control ) and restores them when a post back occurs.

The dataGrid has insert / edit / delete links. I can add multiple copies of the user control to the page and the insert / edit delete functionality works perfectly for each separate control.

Yesterday I added some property binding to the main page to which are unrelated to the user control using the format Text='<%# DocumentTitle %>'. Initially I couldn't get this to work until I added Page.DataBind(); to the main page's Page_Load method. At this point the property binding started working correctly but then I noticed the insert functionality had stopped working in the datagrid within each user control....I debugged and found that when the following line executes it finds the text fields in the controls within the dataGrid to be empty or "":

eInfo.Ref = ((TextBox)gvEG.FooterRow.FindControl("txtEmployeeName")).Text;

If I remove the page.DataBind() method from the main page then the property binding stops working but the dataGrid(s) in the userControl start working.

My question is two fold i) Why does the seemingly unrelated change effect the dataGrid and ii) what do I do to get this working?

I've added the relevant sections of my code below...or at least what I think are the relevant sections.

Default.aspx

    <div class="general">        
    <asp:TextBox Width="488" runat="server" placeholder="Document Title"  Text='<%# DocumentTitle %>'></asp:TextBox>
    </div>

Default.aspx.cs

protected void Page_Load(object sender, EventArgs e)
    {           
        if (!IsPostBack)
        {
            // Create an empty user control for the first requirements section.
            EmployeeSectionUserControl myUserControl1 = (EmployeeSectionUserControl )LoadControl("~/EmployeeSectionUserControl .ascx");


            // Add it to the panel control holding all the user controls.
            MainPanel.Controls.Add(myUserControl1);

            DocumentTitle = "I am the default document title and I'm bound.";
        }
        else
        {
            // Do nothing
        }            
        Page.DataBind();
    }

EmployeeSectionUserControl.ascx

<asp:GridView ID="gvEG" runat="server" AutoGenerateColumns="False" CssClass="grid"
AlternatingRowStyle-CssClass="gridAltRow" RowStyle-CssClass="gridRow" ShowFooter="True"
EditRowStyle-CssClass="gridEditRow" FooterStyle-CssClass="gridFooterRow" OnRowCancelingEdit="gvEG_RowCancelingEdit"
OnRowCommand="gvEG_RowCommand" OnRowDataBound="gvEG_RowDataBound" OnRowDeleting="gvEG_RowDeleting"
OnRowEditing="gvEG_RowEditing" OnRowUpdating="gvEG_RowUpdating" DataKeyNames="Id" ShowHeaderWhenEmpty="true">
<Columns>
    <asp:TemplateField HeaderText="Id" HeaderStyle-HorizontalAlign="Left" ControlStyle-Width="50px">
        <ItemTemplate>
            <%# Eval("Id")%>
        </ItemTemplate>
    </asp:TemplateField>

    <asp:TemplateField HeaderText="Ref" HeaderStyle-HorizontalAlign="Left" ControlStyle-Width="90px">
        <EditItemTemplate>
            <asp:TextBox ID="txtEmployeeName" runat="server" Text='<%# Bind("Ref") %>'
                Width="90px"></asp:TextBox>                
        </EditItemTemplate>
        <FooterTemplate>
            <asp:TextBox ID="txtEmployeeName" runat="server" Width="90px"></asp:TextBox>                
        </FooterTemplate>

EmployeeSectionUserControl.ascx.cs

protected void gvEG_RowCommand(object sender, GridViewCommandEventArgs e)
    {
        if (e.CommandName.Equals("Insert"))
        {
            employeeInfo eInfo = new employeeInfo();
            eInfo.Id = 999;// Convert.ToInt32(((TextBox)gvEG.FooterRow.FindControl("Id")).Text);

            // If we're inserting from the EmptyDataTemplate( ie an empty table ) of the gridview then we need to retreive the data differently.
            // So we perform a check on the gridView FooterRow and if it's null then we can assume it's an empty table.
            if (gvEG.FooterRow == null)
            {
                TextBox referenceTxtBox = (((Control)e.CommandSource).NamingContainer).FindControl("txtEmployeeName") as TextBox;
                eInfo.Ref = referenceTxtBox.Text;                    
            }
            else
            {                    
                eInfo.Ref = ((TextBox)gvEG.FooterRow.FindControl("txtEmployeeName")).Text;
                eInfo.Need = 
            }

            // Store Update and Re-bind data to grid.
        }           
    }

Page.DataBind() calls DataBind on it's children, so it updates DocumentTitle in the text box but it also DataBinds your grid. I didn't see a DataSource set in your grid, like an EntityDataSource, so I am assuming you are doing the smart retrieving (and preparation) of the data yourself in code and set the DataSource yourself:

gvEg.DataSource = someCollection;
gvEg.DataBind();

On the get your are loading the user-control and probably call this DataBind with specifying the DataSource. It binds and then you call Page.DataBind() which probably also triggers another DataBind for gvEg but since DataSource is set it shows the same.

On the post back you shouldn't do a DataBind() before handling events. Your call of Page.DataBind() does that. It triggers a DataBind() without a DataSource. Then the rowCommand comes and checks for the TextBox in the Footer which is cleared due to a DataBind with no elements.

What you should do is: You shouldn't use Page.DataBind(). If you do so, you need todo it at a moment when all DataSources are set correctly and it shouldn't be kicked of during a post back. In general, I would not recommend using it because it makes it more complex and it's probably only helping a bit if you haven't set up your application correctly. In your case it's definitely not necessary. Your textBox is a server control that's not part of any binding (GridView, Repeater, ListView). So your textBox is immediately available in your code behind. So you should:

  1. Give the textBox an ID you can use like txtDocumentTitle

      <asp:TextBox Width="488" ID="txtDocumentTitle" runat="server" placeholder="Document Title"></asp:TextBox> 
  2. Replace setting DocumentTitle (unless you need it for something else too) with:

      txtDocumentTitle.Text = "I am the default document title and I'm bound."; 
  3. Remove Page.DataBind();

So access server controls you have access immediately since they are also properties in your page or control.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM