Solved

Why does DataGrid lose ItemCommand event after postback

Posted on 2003-11-24
19
1,376 Views
Last Modified: 2011-10-03
Should I have to rebind a datagrid for its events to fire?

If I  DataBind the grid every page load, the ItemCommand Event fires no problem.  If I don't databind, it wont' fire.  I thought that DataBinding flushed out the event list of the datagrid!  What's the correct way to use this control?


I've got the following code:

public class testgrid : System.Web.UI.Page
      {
            protected System.Web.UI.WebControls.DataGrid DataGrid1;
      
            private void Page_Load(object sender, System.EventArgs e)
            {
                  LoadGrid();

                  // Works
                  BindData(DataGrid1);

                  // Doesn't work
                  // if(!Page.IsPostBack)
                  //       BindData(DataGrid1);
            }

            private void LoadGrid()
            {
                  DataGrid1.ItemCommand += new DataGridCommandEventHandler(DataGrid1_ItemCommand);

                  ButtonColumn bc = new ButtonColumn();
                  bc.CommandName = "Edit";
                  bc.DataTextField = "UserID";

                  BoundColumn user = new BoundColumn();
                  user.DataField = "UserName";
                  user.HeaderText = "User";

                  DataGrid1.Columns.Add(bc);
                  DataGrid1.Columns.Add(user);

                  DataGrid1.DataSource = DbWrapper.ExecuteDataSet("select * from _Users where userid < 1000");

            }

            private void BindData(DataGrid g)
            {
                  g.DataBind();
            }

            private void DataGrid1_ItemCommand(object sender, DataGridCommandEventArgs e)
            {
                  switch(e.CommandName)
                  {
                        case "Edit":
                              break;
                        default:
                              break;
                  }
            }

      }

L'Ordinateur
0
Comment
Question by:lordinateur
  • 8
  • 5
  • 4
  • +1
19 Comments
 
LVL 28

Expert Comment

by:mmarinov
ID: 9813919
you have to bind data to datagrid after each operation
0
 

Expert Comment

by:JasonRichard
ID: 9814070
Not really sure why this isn't working for you.  Try using the DataGrid1.DataBind() method within LoadGrid.

if(!Page.IsPostBack)
{
      LoadGrid();
}

private void LoadGrid()
{
      ButtonColumn bc = new ButtonColumn();
      bc.CommandName = "Edit";
      bc.DataTextField = "UserID";

      BoundColumn user = new BoundColumn();
      user.DataField = "UserName";
      user.HeaderText = "User";

      DataGrid1.Columns.Add(bc);
      DataGrid1.Columns.Add(user);

      DataGrid1.DataSource = DbWrapper.ExecuteDataSet("select * from _Users where userid < 1000");

      DataGrid1.DataBind();
}


As for the line of code below, I don't think you need it in the code behind file (whatever.aspx.cs).
DataGrid1.ItemCommand += new DataGridCommandEventHandler(DataGrid1_ItemCommand);

Just do this as an attribute of the DataGrid tag of the code file (whatever.aspx)

<asp:DataGrid ID="DataGrid1" ... OnItemCommand="DataGrid1_ItemCommand">

0
 

Expert Comment

by:JasonRichard
ID: 9814098
Oops...Postback check needs to be in the Page_Load method.

private void Page_Load(object sender, System.EventArgs e)
{
    if(!Page.IsPostBack)
    {
        LoadGrid();
    }
}
0
 

Author Comment

by:lordinateur
ID: 9814217
Thank you for you reply, Jason.  

I tried to just add the OnItemCommand event in the aspx file and I get an error stating that the _ItemCommand method is inaccessible due to its protection level.  It apparently wants me to make this method protected rather than private.  Why??

At any rate, your suggestions don't seem to retain the event either.  Can anybody get the code I posted to work properly?  That is, not require another databind to retain events.
0
 

Expert Comment

by:JasonRichard
ID: 9814350
You need to make the method public, private methods can only be accessed within the class itself.

public void DataGrid1_ItemCommand(object sender, DataGridCommandEventArgs e)
{
}
0
 
LVL 28

Expert Comment

by:mmarinov
ID: 9814366
i think that the problem is not in the Page_load.
the problem is after your first databinding
when itemcommand fires you don't bind the datagrid

you have to write this

 private void DataGrid1_ItemCommand(object sender, DataGridCommandEventArgs e)
          {
               switch(e.CommandName)
               {
                    case "Edit":
                         break;
                    default:
                         break;
BindData(DataGrid1);

               }

          }

and in the Page_load write just
if(!Page.IsPostBack)
  BindData(DataGrid1);
0
 

Author Comment

by:lordinateur
ID: 9814448
I don't want to make the event methods public or protected.  I don't see why I shouldn't be able to do all this in the code-behind.  

mmarinov: I don't think that's it.  I never even get into the ItemCommand event so I can't bind the data again there.  It works just fine if I bind the data in Page_Load but I don't want to make more round trips to the datasource than I need to.


Maybe this is harder than I thought it would be...I'm increasing the points on this question to 300.

0
 

Expert Comment

by:JasonRichard
ID: 9814453
I ran into problems when I tried to do everything in code behind as well, it is more confusing.
0
 

Author Comment

by:lordinateur
ID: 9814477
I come from a non-ASP background so I'm inclined to think the opposite, I prefer working in the code-behind.  

It is more confusing...but it shouldn't be.  As far as I've gathered, the page life-cycle should be able to recognize and rebuild the state of any controls you add but in practice this is harder than it sounds.  Anything created dynamically has been a crapshoot.
0
Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 28

Expert Comment

by:mmarinov
ID: 9814514
So i've try the code and everything works fine
When you use
if(!Page.IsPostBack)
 BindData(DataGrid1);

the datagrid is binded in the first time but when you want to fire up the ItemCommand nothing happend because in the ItemCommand function you don't bind the datagrid again. all the stuff you want to do in the ItemCommand is done but it is not shown because the datagrid is not binded

After the ItemCommand is executed once nothing will happen

B..G
0
 

Author Comment

by:lordinateur
ID: 9814719
I don't understand how you got it to work.  Can you post the exactly what you have?  When I run the following code, it never enters the itemcommand method:


public class testgrid : System.Web.UI.Page
      {
            protected System.Web.UI.WebControls.DataGrid DataGrid1;
      
            private void Page_Load(object sender, System.EventArgs e)
            {
                  
                  LoadGrid();
                  if(!Page.IsPostBack)
                        BindData(DataGrid1);
                        
            }

            private void LoadGrid()
            {
                  
                  ButtonColumn bc = new ButtonColumn();
                  bc.CommandName = "Edit";
                  bc.DataTextField = "UserID";

                  BoundColumn user = new BoundColumn();
                  user.DataField = "UserName";
                  user.HeaderText = "User";

                  DataGrid1.Columns.Add(bc);
                  DataGrid1.Columns.Add(user);

                  DataGrid1.DataSource = DbWrapper.ExecuteDataSet("select * from rz_User where userid < 1011");

                  
            }

            private void BindData(DataGrid g)
            {
                  g.DataBind();
            }

            private void DataGrid1_ItemCommand(object sender, DataGridCommandEventArgs e)
            {
                  switch(e.CommandName)
                  {
                        case "Edit":
                              break;
                        default:
                              break;
                  }
                  BindData(DataGrid1);
            }

            #region Web Form Designer generated code
            override protected void OnInit(EventArgs e)
            {
                  //
                  // CODEGEN: This call is required by the ASP.NET Web Form Designer.
                  //
                  InitializeComponent();
                  base.OnInit(e);
            }
            
            /// <summary>
            /// Required method for Designer support - do not modify
            /// the contents of this method with the code editor.
            /// </summary>
            private void InitializeComponent()
            {  
                  DataGrid1.ItemCommand += new DataGridCommandEventHandler(DataGrid1_ItemCommand);
                  this.Load += new System.EventHandler(this.Page_Load);

            }
            #endregion
      }
}
0
 

Author Comment

by:lordinateur
ID: 9814737
this is what I have in my aspx page



<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
      <HEAD>
            <title>testgrid</title>
            <meta name="GENERATOR" Content="Microsoft Visual Studio .NET 7.1">
            <meta name="CODE_LANGUAGE" Content="C#">
            <meta name="vs_defaultClientScript" content="JavaScript">
            <meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">
      </HEAD>
      <body MS_POSITIONING="GridLayout">
            <form id="Form1" method="post" runat="server">
                  <asp:DataGrid id="DataGrid1" style="Z-INDEX: 101; LEFT: 32px; POSITION: absolute; TOP: 48px" runat="server"
                        AutoGenerateColumns="False"></asp:DataGrid>
            </form>
      </body>
</HTML>
0
 
LVL 28

Expert Comment

by:mmarinov
ID: 9814756
here is the html

<asp:DataGrid OnItemCommand="DataGrid1_ItemCommand" PagerStyle-Visible="False" ShowFooter="False"                     AutoGenerateColumns="False" AllowCustomPaging="False" AllowPaging="True" id="DataGrid1" style="Z-INDEX: 103" runat="server">
                    <Columns>
                         <asp:BoundColumn DataField="ID1" HeaderText="Attribute" SortExpression="STRING"/>
                         <asp:TemplateColumn HeaderText="VALUE">
                              <ItemTemplate>
                                   <asp:TextBox Runat="server" ID="Textbox1">name</asp:TextBox>
                              </ItemTemplate>
                         </asp:TemplateColumn>
                         <asp:ButtonColumn CommandName="update" ButtonType="PushButton" Text="Update"></asp:ButtonColumn>
                    </Columns>
               </asp:DataGrid>

here is the code behind

public class testgrid : System.Web.UI.Page
{
      protected System.Web.UI.WebControls.DataGrid DataGrid1;
     
      private void Page_Load(object sender, System.EventArgs e)
      {
            LoadGrid();

             if(!Page.IsPostBack)
                  BindData(DataGrid1);
      }

      private void LoadGrid()
      {
            ButtonColumn bc = new ButtonColumn();
            bc.CommandName = "Edit";
            bc.DataTextField = "ID1";

            BoundColumn user = new BoundColumn();
            user.DataField = "UserName";
            user.HeaderText = "User";

            DataGrid1.Columns.Add(bc);
            DataGrid1.Columns.Add(user);


            DataSet ds = new DataSet();
            ds.Tables.Add("aaa");
            ds.Tables[0].Columns.Add("ID1");
            ds.Tables[0].Columns.Add("UserName");

            DataRow dr = ds.Tables[0].NewRow();
            dr[0] = "first custom value";
            dr[1] = "second custom value" ;

            ds.Tables[0].Rows.Add( dr );

            DataGrid1.DataSource = ds ;

      }

      private void BindData(DataGrid g)
      {
            g.DataBind();
      }

      protected void DataGrid1_ItemCommand(object sender, DataGridCommandEventArgs e)
      {
            switch(e.CommandName)
            {
                  case "Edit":
                        break;
                  default:
                        break;
            }
            BindData ( DataGrid1 );
      }

      #region Web Form Designer generated code
      override protected void OnInit(EventArgs e)
      {
            //
            // CODEGEN: This call is required by the ASP.NET Web Form Designer.
            //
            InitializeComponent();
            base.OnInit(e);
      }
            
      /// <summary>
      /// Required method for Designer support - do not modify
      /// the contents of this method with the code editor.
      /// </summary>
      private void InitializeComponent()
      {    
            this.Load += new System.EventHandler(this.Page_Load);

      }
      #endregion
0
 

Author Comment

by:lordinateur
ID: 9817545
Hmm, this is pretty interesting.  I was able to get your code to work but the difference with mine is that I am doing all the column creation in the code behind.  I don't see why this would make a difference considering that I do it on every page load.  

At any rate, if I combine the two techniques, (some declared in aspx page, some in code-behind), if I click on the parts of the DataGrid that were declared in the aspx page, it's fine--itemcommand fires and state is maintained.  However, when I click the columns of the datagrid that I added in the code-behind, the itemcommand does not fire.  And, because I'm not rebinding on Postback I guess, those columns actually disaapear from the datagrid.

Why should one technique work and the other not?
0
 

Author Comment

by:lordinateur
ID: 9866923
Ok, here's the answer, thanks to Scott Mitchell:

whenever you add controls dynamically to an ASP.NET Web page, you have to always recreate the controls upon postback, otherwise they will be lost.
 
So, all you need to do is recreate the columns, regardless of its a postback or not.  Now, this needs to happen BEFORE the ViewState is loaded, so do it in the Page_Init event handler.

------

The problem was that I wasn't recreating the columns in the Page_Init event.
0
 
LVL 28

Expert Comment

by:mmarinov
ID: 9867029
great, you find the answer
B..G
0
 

Author Comment

by:lordinateur
ID: 9867183
Yes, thanks for your help.

L
0
 

Accepted Solution

by:
SpazMODic earned 0 total points
ID: 9888016
PAQed, with points refunded (300)

SpazMODic
EE Moderator
0

Featured Post

Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

Join & Write a Comment

Many of us here at EE write code. Many of us write exceptional code; just as many of us write exception-prone code. As we all should know, exceptions are a mechanism for handling errors which are typically out of our control. From database errors, t…
Wouldn’t it be nice if you could test whether an element is contained in an array by using a Contains method just like the one available on List objects? Wouldn’t it be good if you could write code like this? (CODE) In .NET 3.5, this is possible…
This demo shows you how to set up the containerized NetScaler CPX with NetScaler Management and Analytics System in a non-routable Mesos/Marathon environment for use with Micro-Services applications.
This video explains how to create simple products associated to Magento configurable product and offers fast way of their generation with Store Manager for Magento tool.

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

9 Experts available now in Live!

Get 1:1 Help Now