title: ASP.NET GridView TemplateField controls lost after PostBack
body: <p><br>
  solving the problem with the GridView control and template field. I have defined the GridView like this:</p>
  
  <pre><code>&lt;asp:GridView ID="gridView" runat="server" ShowFooter="True" onrowdatabound="onRowDataBound" AutoGenerateColumns="False" onrowcreated="onRowCreated" onrowcommand="onRowCommand" onselectedindexchanged="onSelectedIndexChanged"&gt;
  &lt;Columns&gt;
      &lt;asp:CommandField SelectText="cmdSelectRow" ShowSelectButton="True" /&gt;
      &lt;asp:TemplateField AccessibleHeaderText="treeController"  HeaderText=""&gt;
          &lt;ItemTemplate&gt;
              &lt;asp:ImageButton ID="btnShow" runat="server" ImageUrl="~\\Images\\treePlus.png" CommandName="TreeShow" UseSubmitBehavior="False"/&gt;
              &lt;asp:ImageButton ID="btnHide" runat="server" Visible="False" ImageUrl="~\\Images\\treeMinus.png" CommandName="TreeHide" UseSubmitBehavior="False" /&gt;
          &lt;/ItemTemplate&gt;
      &lt;/asp:TemplateField&gt;
      &lt;asp:BoundField DataField="treeLevel" HeaderText="Tree Level" /&gt;
      &lt;asp:BoundField DataField="parentTaskId" HeaderText="parent_task_id" /&gt;
      &lt;asp:BoundField DataField="taskId" HeaderText="task_id" /&gt;
      &lt;asp:BoundField DataField="groupId" HeaderText="group_id" /&gt;
      &lt;asp:BoundField DataField="hasTiming" HeaderText="" /&gt;
              ... much more BoundFiels ...&lt;/Columns&gt;
  </code></pre>
  
  <p>I suppose you understood that using this gridView I implement the treeView ... those two ImageButtons are buttons to expland/collapse child items.</p>
  
  <p>If I do NOTHING with the grid, works perfect, event after PostBacks. But, because there is a lot of columns, I have customization allowing to adjust the gridView layout defining the order of the columns and visibility. If I do anything with the GridView columns (re-order columns, or just remove the column and insert it at the same position), TemplateField buttons are lost on PostBack. Even if I do nothing with TemplateField column definition but reordering BoundFields columns, TemplateField columns are lost after PostBack.</p>
  
  <p>It looks there is some problem with the ViewState (I do not know). The fact is, that:<br>
  1. I make the GridView customization on Page_Init method<br>
  2. I do Data Binding (because of some reasons) on Page_PreRender method, only if NOT PostBack</p>
  
  <p>I saw several questions solving the issues with TemplateField items after postback, but I did not find the solution.</p>
  
  <p>Does have enybody the idea, where should be the issue? Why it works, when nothing is done with the gridview structure (columns) and DOES NOT WORK when the same column is taken out and reinserted into the grid columns?<br><br></p>
  
  <p>Thank you for any help or ideas.</p>
  
  <p>To demonstrate the "flow" of the page, I am adding more details ...<br>
  The GridView is part of my custom control. </p>
  
  <pre><code>    protected void  Page_Init (object sender, EventArgs e)
      {
         /* customize grid control */
         /* here I load the customization defined by user and change GridView.Columns */
         layoutCustomize(gridControl, accountId);
      }
  </code></pre>
  
  <p>As shown, I am changing the GridView structure (on first page load or postbacks)</p>
  
  <pre><code>    protected override void OnDataBinding(EventArgs e)
      {
          /* declarations */
          DbModel.TaskView [] tasks = null;
          DataTable           tasksTable = null;
          /* call parent method */
          base.OnDataBinding(e);
          /* get data */
          if ((tasks = TasksView.Data) != null)
          {
              /* build data table */
              tasksTable = TsGridView.BuildDataTable(TasksTreeView, tasks, typeof(TaskView));
              /* apply filter */
              DataTable viewTable = Filter(tasksTable);
              /* bound the data source to the gird */
              TasksTreeView.DataSource = viewTable;
              TasksTreeView.DataBind();
          }
      }
  </code></pre>
  
  <p>This is custom control's DataBind event, the main purpose is to bind data to the grid :-)
  The event is triggered by call to DataBind in parent control's Page_PreRender method, like this:</p>
  
  <pre><code>    protected void  Page_PreRender(object sender, System.EventArgs e) 
      {
          /* set active view */
          if (IsPostBack == false)
              SetView(tasksMultiView.ActiveViewIndex);
      }
      protected void  SetView (int viewIndex)
      {
          /* declarations */
          Control     viewControl = null;
          View        selectedView = null;
          ListItem    selectedItem = null;
          /* get control */
          selectedView = tasksMultiView.Views[viewIndex];
          selectedItem = View.Items[viewIndex];
          /* get control */
          if ((viewControl = selectedView.FindControl(selectedItem.Value)) != null)
              /* bind data */
              viewControl.DataBind();
      }
  </code></pre>
  
  <p>Hopes this help.</p>