在PostBack之后,ASP.NET GridView TemplateField控件丢失了

时间:2013-10-12 23:54:46

标签: asp.net gridview


使用GridView控件和模板字段解决问题。我已经像这样定义了GridView:

<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>

我想你明白使用这个gridView我实现了treeView ......这两个ImageButtons是用于解释/折叠子项的按钮。

如果我没有使用网格,那么在PostBacks之后可以完美运行。但是,因为有很多列,我有自定义允许调整gridView布局,定义列的顺序和可见性。如果我对GridView列执行任何操作(重新排序列,或者只删除列并将其插入相同位置),则PostBack上的TemplateField按钮会丢失。即使我没有对TemplateField列定义执行任何操作,但重新排序BoundFields列,也会在PostBack之后丢失TemplateField列。

看起来ViewState存在一些问题(我不知道)。事实是:
1.我在Page_Init方法上进行GridView自定义 2.我在Page_PreRender方法上进行数据绑定(由于某些原因),仅在NOT PostBack

我在回发后看到几个问题解决了TemplateField项目的问题,但我找不到解决方案。

是否有想法,这应该是什么问题?为什么它工作,当gridview结构(列)没有任何操作时,当取出相同的列并重新插入网格列时,它们不工作?

感谢您提供任何帮助或想法。

为了演示页面的“流程”,我正在添加更多细节......
GridView是我的自定义控件的一部分。

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

如图所示,我正在更改GridView结构(在首页加载或回发时)

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

这是自定义控件的DataBind事件,主要目的是将数据绑定到网格:-) 通过在父控件的Page_PreRender方法中调用DataBind来触发该事件,如下所示:

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

希望这有帮助。

3 个答案:

答案 0 :(得分:3)

您的Viewstate在回发时“丢失”,因为您更改了GridView的结构。 TemplateField按钮仍然存在,但是......如果在OnInit之后但在GridView数据绑定之前添加/删除列,则不会出现此问题。我认为您的问题虽然在删除列以刷新Viewstate之后需要将数据重新绑定到GridView。

或者,我也发现了这个可能的解决方案,看起来像调用myGridView.Columns.Clear();在添加/删除列之前,可能会为您提供帮助。

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

答案 1 :(得分:1)

在.aspx页面上将EnableViewState设置为false。我遇到了这个问题,这解决了我的问题。

答案 2 :(得分:0)

根据您添加到问题背后的代码,问题可能是您的绑定数据太晚,GridView无法正常工作。它应该在Page_Load中完成。我认为这里也有一个红旗,你可以在OnDataBinding中调用TasksTreeView.DataBind(),并在SetView中根据ASP.NET生命周期中的事件再次在自定义控件本身中调用DataBind。

另外,为什么要在受保护的覆盖void OnDataBinding中再次调用DataBind。你已经在某个地方调用DataBind来触发OnDataBinding。您是否通过自定义控件对ViewControl.DataBind()的SetView调用,在您的父页面中触发受保护的覆盖void OnDataBinding?如果是这种情况,那就是一些复杂的,不可维护的代码,您应该进行重组,以便您的父页面和自定义控件松散耦合,这样您就可以重用自定义控件,而无需开发人员了解自定义控件的内部工作。

如果您的CustomControl没有一个公共DataBind方法,它以您希望的方式工作,而不是创建一个新的Public方法,该方法模仿GridView DataBind的DataBind参数,然后使用传入的数据参数调用相应的GridView。 / p>

也许您可以重构代码并一起消除SetView方法。您不应该在自定义控件本身中调用DataBind。这应该取决于自定义控件的父用户,当调用DataBind时。改为在自定义控件中覆盖DataBind:

public override void DataBind() {    //...some在这里实施......    base.DataBind() }