I\'m having a problem dynamically adding columns to a GridView. I need to change the layout -- i.e. the included columns -- based on the value in a DropDownList. When the
I recently conquered silmilar issues with dynamic columns in gridviews, perhaps this will help.
First turn the viewstate off
Second add the columns programatically in a function fired in the oninit event
Lastly I used the following helper class to cause the checkboxes to instantiate when the RowDataBound event kicked off. Yes some of it is hard coded.
Heck here is all the code. Have at it :) Warrenty as is, blah blah blah...
Finally since I am just getting my feet wet DotNet any tips would be appreciated [IE don't rip me too much :) ]. And yes 'borrowed' the initial code from the web somewhere, sorry I cant remember off the top of my head :(
-- Fire this off in protected override 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;
}
}
-- Helper Class
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
}
Instead of dynamically adding columns, could you define them at the outset and hide/show them as needed (either with Visible="false" or setting the CssClass of the control/header/footer to a class with "display: none;")? I use this method in some of my code, including template columns, with no issues.
diningphilanderer.myopenid.com has a similar approach to what I would recommend.
The problem is that you have to rebind the grid each time a postback occurs and consequently you have to rebuild the columns. I like to have a method called BindGrid() that first clears the Columns GridView1.Columns.Clear(); then adds them programatically, then sets the datasource and calls databind. Make sure you have viewstate disabled for the grid and you have autogeneratecolumns = false;