使用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();
}
希望这有帮助。
答案 0 :(得分:3)
您的Viewstate在回发时“丢失”,因为您更改了GridView的结构。 TemplateField按钮仍然存在,但是......如果在OnInit之后但在GridView数据绑定之前添加/删除列,则不会出现此问题。我认为您的问题虽然在删除列以刷新Viewstate之后需要将数据重新绑定到GridView。
或者,我也发现了这个可能的解决方案,看起来像调用myGridView.Columns.Clear();在添加/删除列之前,可能会为您提供帮助。
答案 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() }