0
votes


solving the problem with the GridView control and template field. I have defined the GridView like this:

<asp:GridView ID="gridView" runat="server" ShowFooter="True" onrowdatabound="onRowDataBound" AutoGenerateColumns="False" onrowcreated="onRowCreated" onrowcommand="onRowCommand" onselectedindexchanged="onSelectedIndexChanged">
<Columns>
    <asp:CommandField SelectText="cmdSelectRow" ShowSelectButton="True" />
    <asp:TemplateField AccessibleHeaderText="treeController"  HeaderText="">
        <ItemTemplate>
            <asp:ImageButton ID="btnShow" runat="server" ImageUrl="~\\Images\\treePlus.png" CommandName="TreeShow" UseSubmitBehavior="False"/>
            <asp:ImageButton ID="btnHide" runat="server" Visible="False" ImageUrl="~\\Images\\treeMinus.png" CommandName="TreeHide" UseSubmitBehavior="False" />
        </ItemTemplate>
    </asp:TemplateField>
    <asp:BoundField DataField="treeLevel" HeaderText="Tree Level" />
    <asp:BoundField DataField="parentTaskId" HeaderText="parent_task_id" />
    <asp:BoundField DataField="taskId" HeaderText="task_id" />
    <asp:BoundField DataField="groupId" HeaderText="group_id" />
    <asp:BoundField DataField="hasTiming" HeaderText="" />
            ... much more BoundFiels ...</Columns>

I suppose you understood that using this gridView I implement the treeView ... those two ImageButtons are buttons to expland/collapse child items.

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.

It looks there is some problem with the ViewState (I do not know). The fact is, that:
1. I make the GridView customization on Page_Init method
2. I do Data Binding (because of some reasons) on Page_PreRender method, only if NOT PostBack

I saw several questions solving the issues with TemplateField items after postback, but I did not find the solution.

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?

Thank you for any help or ideas.

To demonstrate the "flow" of the page, I am adding more details ...
The GridView is part of my custom control.

    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);
    }

As shown, I am changing the GridView structure (on first page load or postbacks)

    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();
        }
    }

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:

    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();
    }

Hopes this help.

3

3 Answers

3
votes

Your Viewstate, is "lost" on postback because you have changed the structure of the GridView. The TemplateField buttons are still there but...If you add/remove columns after OnInit but before your GridView is databound you willnot have this problem. I think for your issue though you will need to rebind the data to the GridView after removing the columns to refresh the Viewstate.

OR, I found this possible solution too, looks like calling myGridView.Columns.Clear(); before adding/removing columns might do the trick for you.

http://forums.asp.net/p/1229438/2216336.aspx#2216336

1
votes

Set EnableViewState to false on your .aspx page. I was having this issue and this resolved the issue for me.

0
votes

Based on the code behind you added to your question, the issue might be that your binding data too late to the GridView to work correctly. It should be done in Page_Load. I think there is a red flag here too that you call TasksTreeView.DataBind() in OnDataBinding and also call DataBind again in the custom control itself, in SetView, based on an event in the ASP.NET Lifecycle.

Also why are you calling DataBind again in protected override void OnDataBinding. You called DataBind somewhere already to trigger OnDataBinding. Are you triggering the protected override void OnDataBinding in your Parent page ultimately via the custom control's SetView call to viewControl.DataBind()? If that is the case, that is some convoluted, unmaintainable code and you should restructure so your parent page and custom control are loosely coupled so you can reuse the custom control without a developer having to have knowledge of the custom control's internal workings.

If your CustomControl does not have a public DataBind method that works the way you want it to than create a new Public method that mimics the DataBind parameters of the GridView DataBind and then call the appropriate GridView with the passed in data argument.

Perhaps you could restructure your code and eliminate the SetView method all together. You shouldn't be calling the DataBind in the custom control itself. That should be up to the parent user of the custom control, when DataBind is called that is. Override DataBind in your custom control instead:

public override void DataBind() { //...some implementation here... base.DataBind() }