[英]Adding dynamic columns to an ASP.NET Gridview
我在向GridView动态添加列时遇到问题。 我需要根据DropDownList中的值更改布局 - 即包含的列。 当用户更改此列表中的选择时,我需要删除除第一列之外的所有列,并根据选择动态添加其他列。
我的标记中只定义了一列 - 第0列,一个模板列,其中我声明了一个Select链接和另一个特定于应用程序的LinkButton。 该专栏需要始终存在。 在创建ListBoxSelection时,我删除除第一列之外的所有列,然后重新添加所需的列(在此示例中,我将其简化为始终添加“标题”列)。 以下是代码的一部分:
RemoveVariableColumnsFromGrid();
BoundField b = new BoundField();
b.DataField = "Title";
this.gvPrimaryListView.Columns.Add(b);
this.gvPrimaryListView.DataBind();
private void RemoveVariableColumnsFromGrid() {
int ColCount = this.gvPrimaryListView.Columns.Count;
//Leave column 0 -- our select and view template column
while (ColCount > 1) {
this.gvPrimaryListView.Columns.RemoveAt(ColCount - 1);
--ColCount;
}
}
这段代码第一次运行时,我看到静态列和动态添加的“标题”列。 但是,下次进行选择时,第一列将生成为空(其中没有任何内容)。 我看到了标题栏,我看到它左边的第一列 - 但是里面没有生成任何内容。 在调试器中,我可以看到gvPrimaryListView确实仍然有两列,第一列(索引0)确实是一个模板列。 事实上,该列甚至保留了它的宽度,在下面的标记中设置为165px(用于调试目的)。
有任何想法吗?
<asp:GridView ID="gvPrimaryListView" runat="server" Width="100%" AutoGenerateColumns="false"
DataKeyNames="Document_ID" EnableViewState="true" DataSourceID="odsPrimaryDataSource"
AllowPaging="true" AllowSorting="true" PageSize="10" OnPageIndexChanging="activeListView_PageIndexChanging"
AutoGenerateSelectButton="False" OnSelectedIndexChanged="activeListView_SelectedIndexChanged"
Visible="true" OnRowDataBound="CtlDocList_RowDataBound" Font-Size="8pt" Font-Names="Helvetica">
<Columns>
<asp:TemplateField ShowHeader="false">
<ItemTemplate>
<asp:LinkButton EnableTheming="false" ID="CtlSelectDocRowBtn" runat="server" Text="Select"
CommandName="Select" CssClass="gridbutton" OnClick="RowSelectBtn_Click" />
<asp:ImageButton EnableTheming="false" ID="DocViewBtn" runat="server" ImageUrl="../../images/ViewDoc3.png"
CssClass="gridbutton" CommandName="Select" OnClick="DocViewBtn_Click" />
</ItemTemplate>
<ItemStyle Width="165px" />
</asp:TemplateField>
</Columns>
<EmptyDataTemplate>
<asp:Label ID="Label6" runat="server" Text="No rows found." SkinID="LabelHeader"></asp:Label>
</EmptyDataTemplate>
</asp:GridView>
只是一些额外的信息。
它与第一列无关,而是与它是一个TemplateField这一事实无关。 如果我将一个普通列放在左侧(在标记中)并将TemplateField列向右移动,则第一列呈现正常,而(现在第二列)TemplateField列将消失。
另一个奇怪的事情 - 问题不会发生在第一次回发 - 或第二次 - 但它从第三次回发开始,然后继续进行后续回发。 我很难过。
我最近在gridviews中用动态列征服了silmilar问题,也许这会有所帮助。
首先关闭视图状态
其次,在oninit事件中触发的函数中以编程方式添加列
最后,我使用以下帮助程序类使复选框在RowDataBound事件启动时实例化。 是的,其中一些是硬编码的。
这里是所有代码。 拥有它:) Warrenty原样,等等等等......
最后,因为我只是让我的脚湿了DotNet任何提示将不胜感激[IE不要扯我太多:)]。 是的'借用'来自网络的初始代码,对不起,我不记得我的头顶:(
- 在受保护的覆盖void OnInit中将其关闭
private void GridViewProject_AddColumns()
{
DataSet dsDataSet = new DataSet();
TemplateField templateField = null;
try
{
StoredProcedure sp = new StoredProcedure("ExpenseReportItemType_GetList", "INTRANETWEBDB", Context.User.Identity.Name);
dsDataSet = sp.GetDataSet();
if (sp.RC != 0 && sp.RC != 3000)
{
labelMessage.Text = sp.ErrorMessage;
}
int iIndex = 0;
int iCount = dsDataSet.Tables[0].Rows.Count;
string strCategoryID = "";
string strCategoryName = "";
iStaticColumnCount = GridViewProject.Columns.Count;
// Insert all columns immediatly to the left of the LAST column
while (iIndex < iCount)
{
strCategoryName = dsDataSet.Tables[0].Rows[iIndex]["CategoryName"].ToString();
strCategoryID = dsDataSet.Tables[0].Rows[iIndex]["CategoryID"].ToString();
templateField = new TemplateField();
templateField.HeaderTemplate = new GridViewTemplateExternal(DataControlRowType.Header, strCategoryName, strCategoryID);
templateField.ItemTemplate = new GridViewTemplateExternal(DataControlRowType.DataRow, strCategoryName, strCategoryID);
templateField.FooterTemplate = new GridViewTemplateExternal(DataControlRowType.Footer, strCategoryName, strCategoryID);
// Have to decriment iStaticColumnCount to insert dynamic columns BEFORE the edit row
GridViewProject.Columns.Insert((iIndex + (iStaticColumnCount-1)), templateField);
iIndex++;
}
iFinalColumnCount = GridViewProject.Columns.Count;
iERPEditColumnIndex = (iFinalColumnCount - 1); // iIndex is zero based, Count is not
}
catch (Exception exception)
{
labelMessage.Text = exception.Message;
}
}
- 助手班
public class GridViewTemplateExternal : System.Web.UI.ITemplate
{
#region Fields
public DataControlRowType DataRowType;
private string strCategoryID;
private string strColumnName;
#endregion
#region Constructor
public GridViewTemplateExternal(DataControlRowType type, string ColumnName, string CategoryID)
{
DataRowType = type; // Header, DataRow,
strColumnName = ColumnName; // Header name
strCategoryID = CategoryID;
}
#endregion
#region Methods
public void InstantiateIn(System.Web.UI.Control container)
{
switch (DataRowType)
{
case DataControlRowType.Header:
// build the header for this column
Label labelHeader = new Label();
labelHeader.Text = "<b>" + strColumnName + "</b>";
// All CheckBoxes "Look Up" to the header row for this information
labelHeader.Attributes["ERICategoryID"] = strCategoryID;
labelHeader.Style["writing-mode"] = "tb-rl";
labelHeader.Style["filter"] = "flipv fliph";
container.Controls.Add(labelHeader);
break;
case DataControlRowType.DataRow:
CheckBox checkboxAllowedRow = new CheckBox();
checkboxAllowedRow.Enabled = false;
checkboxAllowedRow.DataBinding += new EventHandler(this.CheckBox_DataBinding);
container.Controls.Add(checkboxAllowedRow);
break;
case DataControlRowType.Footer:
// No data handling for the footer addition row
CheckBox checkboxAllowedFooter = new CheckBox();
container.Controls.Add(checkboxAllowedFooter);
break;
default:
break;
}
}
public void CheckBox_DataBinding(Object sender, EventArgs e)
{
CheckBox checkboxAllowed = (CheckBox)sender;// get the control that raised this event
GridViewRow row = (GridViewRow)checkboxAllowed.NamingContainer;// get the containing row
string RawValue = DataBinder.Eval(row.DataItem, strColumnName).ToString();
if (RawValue.ToUpper() == "TRUE")
{
checkboxAllowed.Checked = true;
}
else
{
checkboxAllowed.Checked = false;
}
}
#endregion
}
通过以下地址在代码项目中添加动态列到网格视图(ASP)的最佳解决方案:请查看: http : //www.codeproject.com/Articles/13461/how-to-create-columns-dynamically-in -a-网格视图
diningphilanderer.myopenid.com与我的推荐方法类似。
问题是每次发生回发时都必须重新绑定网格,因此必须重建列。 我喜欢有一个名为BindGrid()的方法,它首先清除列GridView1.Columns.Clear(); 然后以编程方式添加它们,然后设置数据源并调用数据绑定。 确保您为网格禁用了viewstate,并且您有autogeneratecolumns = false;
我今天早些时候发现了这一点: 当插入BoundFields时,GridView中的TemplateField没有恢复其ViewState 。
看起来像Microsoft不打算修复的错误,因此您必须尝试上述解决方案之一。 我遇到了同样的问题 - 我有一些DataBoundFields和一些TemplateFields,并且在回发后,基于TemplateField的列会丢失它们的控件和数据。
我写了一篇关于类似主题的简短文章,该文章基于用户在CheckBoxList控件中选择的列来处理动态填充GridView列。 希望这对那些寻求简单演示的人有所帮助如何根据用户选择动态生成GridView列? 。
void Page_PreRenderComplete(object sender, EventArgs e)
{
// TemplateField reorder bug: if there is a TemplateField based column (or derived therefrom), GridView may blank out
// the column (plus possibly others) during any postback, if the user has moved it from its original markup position.
// This is probably a viewstate bug, as it happens only if a TemplateField based column has been moved. The workaround is
// to force a databind before each response. See https://connect.microsoft.com/VisualStudio/feedback/details/104994/templatefield-in-a-gridview-doesnt-have-its-viewstate-restored-when-boundfields-are-inserted
//
// This problem is also happening for grid views inside a TabPanel, even if the TemplateField based columns have not
// been moved. Also do a databind in that case.
//
// We also force a databind right after the user has submitted the column chooser dialog.
// (This is because the user could have moved TemplateField based column(s) but ColChooserHasMovedTemplateFields()
// returns false -- ie when the user has moved all TemplateField based columns back to their original positions.
if ((!_DataBindingDone && (ColChooserHasMovedTemplateFields() || _InTabPanel)) || _ColChooserPanelSubmitted || _ColChooserPanelCancelled)
DataBind();
// There is a problem with the GridView in case of custom paging (which is true here) that if we are on the last page,
// and we delete all row(s) of that page, GridView is not aware of the deletion during the subsequent data binding,
// will ask the ODS for the last page of data, and will display a blank. By PreRenderComplete, it will somehow have
// realized that its PageIndex, PageCount, etc. are too big and updated them properly, but this is too late
// as the data binding has already occurred with oudated page variables. So, if we were on the last page just before
// the last data binding (_LastPageIndex == _LastPageCount - 1) and PageIndex was decremented after the data binding,
// we know this scenario has happened and we redo the data binding. See http://scottonwriting.net/sowblog/archive/2006/05/30/163173.aspx
// for a discussion of the problem when the GridView uses the ODS to delete data. The discussion also applies when we
// delete data directly through ClassBuilder objects.
if (_LastPageIndex == _LastPageCount - 1 && PageIndex < _LastPageIndex)
DataBind();
if (EnableColChooser)
{
if (!_IsColChooserApplied)
ApplyColChooser(null, false, false);
else
{
// The purpose of calling ApplyColChooser() here is to order the column headers properly. The GridView
// at this point will have reverted the column headers to their original order regardless of ViewState,
// so we need to apply our own ordering. (This is not true of data cells, so we don't have to apply
// ordering to them, as reflected by the parameters of the call.)
// If we have already processed column reordering upon the column chooser panel being submitted,
// don't repeat the operation.
if (!_ColChooserPanelSubmitted)
ApplyColChooser(null, false, true);
}
}
}
我在文档中的DataControlFieldCollection类下找到了这个小块。
如果您使用的是GridView或DetailsView控件,则自动创建的DataControlField对象(例如,当AutoGenerateColumns属性为true时)不会存储在可公开访问的字段集合中。 您只能访问和操作未自动生成的DataControlField对象。
我想答案是在代码中进行所有列操作,然后你的方法应该可以正常工作。
您可以在开始时定义它们,并根据需要隐藏/显示它们(使用Visible =“false”或将控件/页眉/页脚的CssClass设置为带有“display:none;”的类,而不是动态添加列。 ? 我在我的一些代码中使用此方法,包括模板列,没有任何问题。
对不起,德克尔。 我显然错过了几个关键点.. :)
如果这仍然是一个问题,我想知道你的项目模板中有什么不同? 如果您只是在其中放入一些文本,那么刷新页面几次,文本是否出现在第一次加载,然后不出现在第二次?
此外,当问题出现时,单元格中是否存在任何html标记,或者它们是否完全为空?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.