Reputation: 51
I'm trying to create dynamic columns in an asp.net gridview, and within those dynamic columns I need to insert a dynamic dropdownlist. The end result should look something like this:
Notice the top right of this grid where it has HSE1, HSE2, etc. These columns will change meaning in the example above I may have an additional HSE8, HSE9, etc. Basically the columns are dynamic. In order to do that I've done the following, here is my asp.net markup for the gridview:
<asp:GridView ID="gvMain" runat="server"
AutoGenerateColumns="False"
Width="100%" DataKeyNames="AreaLevelCostCenterFunctionID" OnPreRender="gvMain_PreRender" >
<Columns>
<asp:TemplateField HeaderText="JobTitle" >
<ItemTemplate>
<asp:HyperLink CssClass="loaderLink" ID="hlAreaLevel" runat="server" NavigateUrl='<%# "/Views/Training/AreaLevel/Details.aspx?AreaLevelID=" +
Eval("AreaLevelCostCenter.AreaLevelID") %>' Text='<%# Eval( "AreaLevelCostCenter.AreaLevel.AreaLevel1" )%>' ToolTip="Area Level">
</asp:HyperLink>
</ItemTemplate>
<ItemStyle HorizontalAlign="Left"></ItemStyle>
<HeaderStyle HorizontalAlign="Left"></HeaderStyle>
</asp:TemplateField>
<!--HERE'S WHERE I ADD MY DYNAMIC COLUMNS -->
</Columns>
<PagerSettings Position="TopAndBottom" />
</asp:GridView>
In order to fill this gridview (bind it) I use the following:
private void SetGvMainGridData(IEnumerable<AreaLevel> newNameList)
{
if (newNameList != null)
{
BuildGridAdditionalColumns();
gvMain.DataSource = newNameList;
gvMain.DataBind();
upData.Update();
}
}
My issue is every time I page the data or post back to filter the data the number of columns is repeated. It recreates the same columns over and over every time. So I wrote some code to remove this but I dont think it looks very good. The parameter newNameList
is a list of the HSE 1, HSE 2, etc courses. Here is what BuildGridAdditionalColumns
does:
private void BuildGridAdditionalColumns()
{
using (var db = DataCenterAccess.NewConnection())
{
var tManager = new TrainingManager(db, CurrentUser);
//get the courses, THE HSE 1, HSE 2, etc...
var preDefinedCourses = tManager.GetTrainingPredefinedCourses();
if (preDefinedCourses != null && preDefinedCourses.Any())
{
foreach (var course in preDefinedCourses)
{
// Declare the template field
TemplateField bfield = new TemplateField();
//Initalize the DataField value.
bfield.ItemTemplate = new GridViewTemplate(ListItemType.Item, course.TrainingPredefinedCourse1);
//Initialize the HeaderText field value.
bfield.HeaderText = course.TrainingPredefinedCourse1;
//Add the newly created bound field to the GridView.
gvMain.Columns.Add(bfield);
}
}
}
}
Notice how I did bfield.ItemTemplate = new GridViewTemplate(ListItemType.Item, course.TrainingPredefinedCourse1);
I had to create an interface to support this see this stackoverflow post for more info: How to add TemplateField to a gridview in the code behind?
Basically that interface looks like this:
public class GridViewTemplate : ITemplate
{
//A variable to hold the type of ListItemType.
readonly ListItemType _templateType;
//A variable to hold the column name.
readonly string _columnName;
//Constructor where we define the template type and column name.
public GridViewTemplate(ListItemType type, string colname)
{
//Stores the template type.
_templateType = type;
//Stores the column name.
_columnName = colname;
}
void ITemplate.InstantiateIn(Control container)
{
if (_templateType == ListItemType.Item)
{
//Creates a new drop down list control.
DropDownList ddl = new DropDownList {ID = _columnName};
ddl.Attributes.Add("class","chosen-select");
ddl.Width = 70;
//get the data to populate ddl
var tList = Utilities.GetCourseKeys().ToList();
var selectedValues = (from t in tList select new ListItem( t.KeyValue, t.TrainingPredefinedCourseKeyID.ToString())).ToList();
//add empty option to items and bind
selectedValues.Insert(0, new ListItem());
ddl.DataSource = selectedValues;
ddl.DataBind();
// ddl.DataBinding += new EventHandler(tb1_DataBinding); //Attaches the data binding event.
container.Controls.Add(ddl); //Adds the newly created ddl to the container.
}
}
}
I end up with basically two issues when I post back or refresh this data. One issue is the columns end up repeating themselves. The other issue is the binding of the data stops working (that is the x,y value becomes empty).
Upvotes: 3
Views: 2327
Reputation: 35544
It works in my example whn you create the Dynamic TemplateFields in Page_Init
and do the GridView DataBindind in Page_Load
. I've tested it and if there is a PostBack, there are no extra columns added, all the DropDownLists still exist with all their data and their SelectedValues are shown correctly if they were changed before PostBack.
protected void Page_Init(object sender, EventArgs e)
{
//create a loop for the dynamic fields
for (int i = 1; i < 6; i++)
{
//create a new template field
TemplateField field = new TemplateField();
field.HeaderText = "HSE " + i;
//create the new itemtemplate
field.ItemTemplate = new GridViewTemplate(DataControlRowType.DataRow, "HSE_" + i);
//add the field to the grid
GridView1.Columns.Add(field);
}
}
protected void Page_Load(object sender, EventArgs e)
{
//normal use of IsPostBack
if (!IsPostBack)
{
//bind the gridview data
GridView1.DataSource = LoadFromDataBase();
GridView1.DataBind();
}
}
protected void Button1_Click(object sender, EventArgs e)
{
Button1.Text = "PostBack is done!";
}
public class GridViewTemplate : ITemplate
{
private DataControlRowType templateType;
private string columnName;
public GridViewTemplate(DataControlRowType type, string colname)
{
templateType = type;
columnName = colname;
}
public void InstantiateIn(System.Web.UI.Control container)
{
switch (templateType)
{
case DataControlRowType.DataRow:
DropDownList list = new DropDownList();
list.DataSource = LoadFromDataBase();
list.DataTextField = "myText";
list.DataValueField = "myValue";
list.DataBind();
container.Controls.Add(list);
break;
default:
break;
}
}
}
The ASPX to make the example complete
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false"></asp:GridView>
<br />
<br />
<asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" />
Upvotes: 1
Reputation: 54
I think you should create entire grid dynamically look at below code
string tempnum = "txtbox";
TemplateField temp1 = new TemplateField();
temp1.HeaderStyle.Width = Unit.Pixel(101);
temp1.HeaderStyle.CssClass = "headerwidth";
temp1.HeaderText = "txt";
temp1.ItemTemplate = new CreateTextBox(tempnum);
GridView1.Columns.Add(temp1);
Upvotes: 1