Dynamic GridView Columns


H

Harry Keck

According to the example given in the MSDN documentation, I can call
GridView.Columns.Add during the postback phase of a page. This seems to work
properly. However, if I call GridView.Columns.Insert during the postback
phase, the grid does not render properly, particulary, nothing displays in my
TemplateField columns.

It seems that the only time I can use GridView.Columns.Insert is during the
Init phase of the page lifecycle, but that means that I do not have access to
ViewState or any other ui controls in order to determine what columns I want
to dynamically add. Is this behavior as designed by Microsoft? It would
seem from the GridView.Columns.Add documentation that this type of
manipulation should be available from postback, but clearly it is not, and it
is really putting a hamper on how dynamic my grid columns can really be.

Has anyone found a good workaround for this? Particulary, I want to be able
to use GridView.Columns.Insert during a phase of a page's lifecycle where I
have access to the other UI controls, so that I can alter columns based on
user input.
 
Ad

Advertisements

A

Angel

Harry,

Maybe I misunderstood your message but what I think you said is not entirely
correct

If you a gridview control to a page bind it to a datasource

Then drop a button you can do the following

Protected sub Button1_click...
Dim bf as new BoundField
bf.HeaderText="My col"
GridView1.Columns.Add(bf)
GridView1.DataBind()
end sub

I actually did and I could add as many columns as I wanted simply by
clicking the button. so you might say that's fine but I want to doit from
inside the grid and the answer still the same.

I added a command button "Select" and in the SelectedIndexChanged event I
adde the same code and it worked exactly the same way. The only thing
missing is logic to give the columns meaning but other than that it works.

Is that what you want to do or did I miss something?
 
H

Harry Keck

As I said, Add does appear to work ok, Insert is the problem, and you might
not even notice that it does not work if you do not have any template columns
on the grid. So, create a grid with two template columns in it, where each
of those has a button declared in the template. Then, call your same button
click method, but with Insert. The buttons that you declared in your
template will mysteriously not be rendered. I can not get away with using
Add, since I have some columns already statically declared in the grid and I
need to be able to position the new dynamic columns in between them, so
Insert is a must, and it seems to only work during the Init stage of the page.
 
A

Angel

Oh, I get it... what I am doing is appending a column but you want to insert
the column in between existing columns.

Interesting... I will work on that concept and will let you know if I come
up with anything reasonable.

Regards,
 
P

Phil H

As I said, Add does appear to work ok, Insert is the problem, and you might
not even notice that it does not work if you do not have any template columns
on the grid.  So, create a grid with two template columns in it, where each
of those has a button declared in the template.  Then, call your same button
click method, but with Insert.  The buttons that you declared in your
template will mysteriously not be rendered.  I can not get away with using
Add, since I have some columns already statically declared in the grid andI
need to be able to position the new dynamic columns in between them, so
Insert is a must, and it seems to only work during the Init stage of the page.













- Show quoted text -

It would be much simpler (and predictable) to create the extra
column(s) in the Designer and set the Visible property to false. The
when you wish to render them just set the Visible property to true.
 
H

Harry Keck

I agree that that would be a simpler approach, but then it would be too
simple to meet my requirements. I do not know what the possible columns are
ahead of time. This is truley a dynamic grid where the users can define what
columns to include, and they can even invent new fields, so I can never know
all possiblities during design time.
 
Ad

Advertisements

A

Angel

Harry,

It turns out that I had absolutely no problem inserting columns either

Basically the same thing I showed you

Dim bf as new BoundField
bf.HeaderText = “my Colâ€
GridView1.Columns.Insert(2, bf)
GridView1.DataBind

The Magic number has to be replaced with application logic but other than
that I do not see the problem. Please help me understand what your problem
is. Perhaps let me see you code.

The above I placed in a page and it worked flawlessly.
 
H

Harry Keck

OK, here is a test scenario I created. There is a codebehind and html
section you can paste into a webform. Notice that the first time the page
loads, there are buttons in the template fields. Even after clicking the
Insert Column button once, it all looks like it is working just fine.
However, click that button once more, and mysteriously, the buttons from the
template fields have disappeared. If you see something in here that I just
totally screwed up, please let me know, because I can not find anything wrong
with the logic.

CodeBehind:

protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
BindGridToData();
}
}

private void BindGridToData()
{
DataSet datasetGrid = new DataSet();
datasetGrid.Tables.Add("GridDataTable");
datasetGrid.Tables[0].Columns.Add("1");

datasetGrid.Tables[0].Rows.Add("value 1");
datasetGrid.Tables[0].Rows.Add("value 2");

m_gridviewTest.DataSource = datasetGrid.Tables[0];
m_gridviewTest.DataBind();

}

private void InsertBoundField()
{
BoundField boundFieldNew = new BoundField();
boundFieldNew.DataField = "1";
m_gridviewTest.Columns.Insert(1, boundFieldNew);
}

protected void m_buttonInsertColumn_OnClick(object sender, EventArgs
e)
{
InsertBoundField();
BindGridToData();
}

HTML:

<form id="form1" runat="server">
<div>
<asp:Button runat="server" Text="Insert Column"
ID="m_buttonInsertColumn" OnClick="m_buttonInsertColumn_OnClick" />
<asp:GridView ID="m_gridviewTest" runat="server"
AutoGenerateColumns="False">
<Columns>
<asp:TemplateField HeaderText="Select" >
<ItemTemplate>
<asp:Button ID="buttonSelect" Text="Select"
runat="server"></asp:Button>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Delete" >
<ItemTemplate>
<asp:Button ID="buttonDelete" Text="Delete"
runat="server"></asp:Button>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
</form>
 
L

Lars

Hi

Let's see if I got it right. When you press (click) a button you make a post
back. The page is posted back. When you click a button the page is reloaded.
As I get it you don't bind the data since you check weather it's apost back
or not. Shouldn't this be done every time if you want the page to reload
every time.

In the function where you insert columns you do call BindGridToData(); You
don't do that in the other functions.


Lars

Harry Keck said:
OK, here is a test scenario I created. There is a codebehind and html
section you can paste into a webform. Notice that the first time the page
loads, there are buttons in the template fields. Even after clicking the
Insert Column button once, it all looks like it is working just fine.
However, click that button once more, and mysteriously, the buttons from
the
template fields have disappeared. If you see something in here that I
just
totally screwed up, please let me know, because I can not find anything
wrong
with the logic.

CodeBehind:

protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
BindGridToData();
}
}

private void BindGridToData()
{
DataSet datasetGrid = new DataSet();
datasetGrid.Tables.Add("GridDataTable");
datasetGrid.Tables[0].Columns.Add("1");

datasetGrid.Tables[0].Rows.Add("value 1");
datasetGrid.Tables[0].Rows.Add("value 2");

m_gridviewTest.DataSource = datasetGrid.Tables[0];
m_gridviewTest.DataBind();

}

private void InsertBoundField()
{
BoundField boundFieldNew = new BoundField();
boundFieldNew.DataField = "1";
m_gridviewTest.Columns.Insert(1, boundFieldNew);
}

protected void m_buttonInsertColumn_OnClick(object sender,
EventArgs
e)
{
InsertBoundField();
BindGridToData();
}

HTML:

<form id="form1" runat="server">
<div>
<asp:Button runat="server" Text="Insert Column"
ID="m_buttonInsertColumn" OnClick="m_buttonInsertColumn_OnClick" />
<asp:GridView ID="m_gridviewTest" runat="server"
AutoGenerateColumns="False">
<Columns>
<asp:TemplateField HeaderText="Select" >
<ItemTemplate>
<asp:Button ID="buttonSelect" Text="Select"
runat="server"></asp:Button>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Delete" >
<ItemTemplate>
<asp:Button ID="buttonDelete" Text="Delete"
runat="server"></asp:Button>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
</form>
 
A

Angel

Okay, not only did I see the problem in your code but one added the
templates with the buttons to mine I was able to duplicatate the problem in
mine as well. I am not going to analyze the merit of your code or design but
let me spend a while looking at this problem. I will get back to you. or
you get back to me whoever gets there first.

This sounds like a bug but let's not jump ahead of ourselves.

regards,
--
aaa


Harry Keck said:
OK, here is a test scenario I created. There is a codebehind and html
section you can paste into a webform. Notice that the first time the page
loads, there are buttons in the template fields. Even after clicking the
Insert Column button once, it all looks like it is working just fine.
However, click that button once more, and mysteriously, the buttons from the
template fields have disappeared. If you see something in here that I just
totally screwed up, please let me know, because I can not find anything wrong
with the logic.

CodeBehind:

protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
BindGridToData();
}
}

private void BindGridToData()
{
DataSet datasetGrid = new DataSet();
datasetGrid.Tables.Add("GridDataTable");
datasetGrid.Tables[0].Columns.Add("1");

datasetGrid.Tables[0].Rows.Add("value 1");
datasetGrid.Tables[0].Rows.Add("value 2");

m_gridviewTest.DataSource = datasetGrid.Tables[0];
m_gridviewTest.DataBind();

}

private void InsertBoundField()
{
BoundField boundFieldNew = new BoundField();
boundFieldNew.DataField = "1";
m_gridviewTest.Columns.Insert(1, boundFieldNew);
}

protected void m_buttonInsertColumn_OnClick(object sender, EventArgs
e)
{
InsertBoundField();
BindGridToData();
}

HTML:

<form id="form1" runat="server">
<div>
<asp:Button runat="server" Text="Insert Column"
ID="m_buttonInsertColumn" OnClick="m_buttonInsertColumn_OnClick" />
<asp:GridView ID="m_gridviewTest" runat="server"
AutoGenerateColumns="False">
<Columns>
<asp:TemplateField HeaderText="Select" >
<ItemTemplate>
<asp:Button ID="buttonSelect" Text="Select"
runat="server"></asp:Button>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Delete" >
<ItemTemplate>
<asp:Button ID="buttonDelete" Text="Delete"
runat="server"></asp:Button>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
</form>
 
H

Harry Keck

There is a databind happening every time you click the Insert Column button.
You do not have to rebind the grid just because the page posted back, only
when you change the grid. Even when I comment out the test for IsPostback so
that the grid rebinds every single time, the same thing happens. The buttons
in the TemplateFields disappear.
 
Ad

Advertisements

A

Angel

Wow!

Try this instead...

// ==================================================
using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;

public partial class CodeFrmHarry : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
BindGridToData();
}
}

private void BindGridToData()
{
DataSet datasetGrid = new DataSet();
datasetGrid.Tables.Add("GridDataTable");
datasetGrid.Tables[0].Columns.Add("1");

datasetGrid.Tables[0].Rows.Add("value 1");
datasetGrid.Tables[0].Rows.Add("value 2");

m_gridviewTest.DataSource = datasetGrid.Tables[0];
m_gridviewTest.DataBind();

}

private void InsertBoundField()
{
BoundField boundFieldNew = new BoundField();
boundFieldNew.DataField = "1";
m_gridviewTest.Columns.Insert(1, boundFieldNew);
}

protected void m_buttonInsertColumn_OnClick(object sender, EventArgs e)
{
InsertBoundField();
BindGridToData();
}

}

Markup source

<form id="form1" runat="server">
<div>
<asp:Button runat="server" Text="Insert Column"
ID="m_buttonInsertColumn" OnClick="m_buttonInsertColumn_OnClick" />
<asp:GridView ID="m_gridviewTest" runat="server"
AutoGenerateColumns="False">
<Columns>
<asp:ButtonField ButtonType="Button" Text="Select" />
<asp:ButtonField ButtonType="Button" Text="Delete" />
</Columns>
</asp:GridView>
</div>
</form>
// =================================================

Templates have always been Twitchy. Some really bizarre stuff happens when
you have multiple templates and viewstate is on. I have some articles I
titled “Why is everything so darned declarative†which deals with these kinds
of issues.

I am not giving up on finding the answer for you but in the end, I suspect
you are going to have to work around this with something like what I have
given you.

Try what I sent you let me know if you think you can use this instead. I
will continue to research this and will let you know if I come up with
something.

Regards,

--
aaa


Harry Keck said:
OK, here is a test scenario I created. There is a codebehind and html
section you can paste into a webform. Notice that the first time the page
loads, there are buttons in the template fields. Even after clicking the
Insert Column button once, it all looks like it is working just fine.
However, click that button once more, and mysteriously, the buttons from the
template fields have disappeared. If you see something in here that I just
totally screwed up, please let me know, because I can not find anything wrong
with the logic.

CodeBehind:

protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
BindGridToData();
}
}

private void BindGridToData()
{
DataSet datasetGrid = new DataSet();
datasetGrid.Tables.Add("GridDataTable");
datasetGrid.Tables[0].Columns.Add("1");

datasetGrid.Tables[0].Rows.Add("value 1");
datasetGrid.Tables[0].Rows.Add("value 2");

m_gridviewTest.DataSource = datasetGrid.Tables[0];
m_gridviewTest.DataBind();

}

private void InsertBoundField()
{
BoundField boundFieldNew = new BoundField();
boundFieldNew.DataField = "1";
m_gridviewTest.Columns.Insert(1, boundFieldNew);
}

protected void m_buttonInsertColumn_OnClick(object sender, EventArgs
e)
{
InsertBoundField();
BindGridToData();
}

HTML:

<form id="form1" runat="server">
<div>
<asp:Button runat="server" Text="Insert Column"
ID="m_buttonInsertColumn" OnClick="m_buttonInsertColumn_OnClick" />
<asp:GridView ID="m_gridviewTest" runat="server"
AutoGenerateColumns="False">
<Columns>
<asp:TemplateField HeaderText="Select" >
<ItemTemplate>
<asp:Button ID="buttonSelect" Text="Select"
runat="server"></asp:Button>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Delete" >
<ItemTemplate>
<asp:Button ID="buttonDelete" Text="Delete"
runat="server"></asp:Button>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
</form>
 
L

Lars

Does it help to add BindGridToData() to the functions.

Since you cut out the prvious message I can't remeber exact what you where
doing.

Does the DataSource connected to the DataGrid repopulate it self at reload?
I haven't figured out how this work yet.
private void InsertBoundField()
{
BoundField boundFieldNew = new BoundField();
boundFieldNew.DataField = "1";
m_gridviewTest.Columns.Insert(1, boundFieldNew);
}

Since you change the m_gridviewTest here it make sence to rebound the grid
again which you don't do.

Do you have to rebid the grid when you add colums to it? Could that be the
case of the unwanted behaiviour?

Lars
 
H

Harry Keck

Your example does work, but as you've guessed this will not take care of my
situation. I simply used a button in my template fields for the purpose of
creating an example. My real world scenario has much more complicated
templates, which can not be replicated with simple columns.
 
A

Angel

I understand…

Even though the example appeared to works it does not solve the problem.
You're having an issue primarily with viewstate and page life cycle. This is
a very common problem and difficult to solve. It becomes particularly acute
when using template because the extra level of indirection that exacerbate
the problem.

Unfortunately, I have not yet come up with the full answer but in part it
has to do we controls and how they refresh themselves. When you add controls
dynamically they are not saved in the control viewstate and therefore become
your responsibility to render them again.

Don’t believe me…

Try this in the code you originally sent me.

1 – take bindGridToData out of the if block in Load event

2 – Disable the gridview viewstate
EnableViewState = false
You can do this from property box
Note the behavior now.

I sort of have an understanding of the problem but not enough to tell you
what to do as of yet. Maybe, someone else this problem fresher in his/her
mind can contribute but if not then we will figure out. The point of this
long winded explanation is to get your mind thinking as well.

I have to go now but I will get on this early tomorrow or tonight when I
come back.

Regards,
--
aaa


Harry Keck said:
Your example does work, but as you've guessed this will not take care of my
situation. I simply used a button in my template fields for the purpose of
creating an example. My real world scenario has much more complicated
templates, which can not be replicated with simple columns.

Angel said:
Wow!

Try this instead...

// ==================================================
using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;

public partial class CodeFrmHarry : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
BindGridToData();
}
}

private void BindGridToData()
{
DataSet datasetGrid = new DataSet();
datasetGrid.Tables.Add("GridDataTable");
datasetGrid.Tables[0].Columns.Add("1");

datasetGrid.Tables[0].Rows.Add("value 1");
datasetGrid.Tables[0].Rows.Add("value 2");

m_gridviewTest.DataSource = datasetGrid.Tables[0];
m_gridviewTest.DataBind();

}

private void InsertBoundField()
{
BoundField boundFieldNew = new BoundField();
boundFieldNew.DataField = "1";
m_gridviewTest.Columns.Insert(1, boundFieldNew);
}

protected void m_buttonInsertColumn_OnClick(object sender, EventArgs e)
{
InsertBoundField();
BindGridToData();
}

}

Markup source

<form id="form1" runat="server">
<div>
<asp:Button runat="server" Text="Insert Column"
ID="m_buttonInsertColumn" OnClick="m_buttonInsertColumn_OnClick" />
<asp:GridView ID="m_gridviewTest" runat="server"
AutoGenerateColumns="False">
<Columns>
<asp:ButtonField ButtonType="Button" Text="Select" />
<asp:ButtonField ButtonType="Button" Text="Delete" />
</Columns>
</asp:GridView>
</div>
</form>
// =================================================

Templates have always been Twitchy. Some really bizarre stuff happens when
you have multiple templates and viewstate is on. I have some articles I
titled “Why is everything so darned declarative†which deals with these kinds
of issues.

I am not giving up on finding the answer for you but in the end, I suspect
you are going to have to work around this with something like what I have
given you.

Try what I sent you let me know if you think you can use this instead. I
will continue to research this and will let you know if I come up with
something.

Regards,

--
aaa


"Harry Keck" wrote:
 
A

Angel

Okay, I think we got a handle on this. As I said yesterday it is nothing
more than a persistency problem. The dirty little secret here is that dynamic
controls are not persisted and it is your responsibility to persist them.

Of course, why the control (gridview) gets wacked out when EnableViewState
property is on is another dirty little secret. You understand that I mean
under the context of your code not in general. I use the grid very
successfully all the time doing way more sophisticated stuff without any
problems. But you will find gotchas from time to time.

I wrote a couple of lines of code to illustrate a very crude persistency
implementation. You can of course, improve on this you will need a
collection instead of just variables and you need to track existing dynamic
controls between postbacks. In the example I gave you it clearly shows that
the first column generated by your program is now stable but because I am
using a variable there is no way to store any subsequent columns. You will
have to do a little work in implementing your own persistency mechanism but
basically that’s it!

Hope this helps!!
Regards,
--
aaa


Harry Keck said:
Your example does work, but as you've guessed this will not take care of my
situation. I simply used a button in my template fields for the purpose of
creating an example. My real world scenario has much more complicated
templates, which can not be replicated with simple columns.

Angel said:
Wow!

Try this instead...

// ==================================================
using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;

public partial class CodeFrmHarry : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
BindGridToData();
}
}

private void BindGridToData()
{
DataSet datasetGrid = new DataSet();
datasetGrid.Tables.Add("GridDataTable");
datasetGrid.Tables[0].Columns.Add("1");

datasetGrid.Tables[0].Rows.Add("value 1");
datasetGrid.Tables[0].Rows.Add("value 2");

m_gridviewTest.DataSource = datasetGrid.Tables[0];
m_gridviewTest.DataBind();

}

private void InsertBoundField()
{
BoundField boundFieldNew = new BoundField();
boundFieldNew.DataField = "1";
m_gridviewTest.Columns.Insert(1, boundFieldNew);
}

protected void m_buttonInsertColumn_OnClick(object sender, EventArgs e)
{
InsertBoundField();
BindGridToData();
}

}

Markup source

<form id="form1" runat="server">
<div>
<asp:Button runat="server" Text="Insert Column"
ID="m_buttonInsertColumn" OnClick="m_buttonInsertColumn_OnClick" />
<asp:GridView ID="m_gridviewTest" runat="server"
AutoGenerateColumns="False">
<Columns>
<asp:ButtonField ButtonType="Button" Text="Select" />
<asp:ButtonField ButtonType="Button" Text="Delete" />
</Columns>
</asp:GridView>
</div>
</form>
// =================================================

Templates have always been Twitchy. Some really bizarre stuff happens when
you have multiple templates and viewstate is on. I have some articles I
titled “Why is everything so darned declarative†which deals with these kinds
of issues.

I am not giving up on finding the answer for you but in the end, I suspect
you are going to have to work around this with something like what I have
given you.

Try what I sent you let me know if you think you can use this instead. I
will continue to research this and will let you know if I come up with
something.

Regards,

--
aaa


"Harry Keck" wrote:
 
Ad

Advertisements

A

Angel

oops the code ;-)

using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;

public partial class CodeFrmHarry : System.Web.UI.Page
{

protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
// BindGridToData();
}
else
{
// This should only happen on postback


// this is the restore side of your custom viewstate management
// which you become responsible for when you add anything
dynamically
// in this case the columns collection. As I stated below this
should
// an array or collection.
string rht = (string)ViewState["savHeaderText"];
string rdf = (string)ViewState["savDataField"];

if (rdf != null)
{
BoundField BF = new BoundField();
// BF.HeaderText = rht;
BF.DataField = rdf;
m_gridviewTest.Columns.Insert(1, BF);
}

}
// This should happen everytime
BindGridToData();
}

private void BindGridToData()
{


DataSet datasetGrid = new DataSet();
datasetGrid.Tables.Add("GridDataTable");
datasetGrid.Tables[0].Columns.Add("1");

datasetGrid.Tables[0].Rows.Add("value 1");
datasetGrid.Tables[0].Rows.Add("value 2");

m_gridviewTest.DataSource = datasetGrid.Tables[0];
m_gridviewTest.DataBind();

}

private void InsertBoundField()
{
BoundField boundFieldNew = new BoundField();
boundFieldNew.DataField = "1";
m_gridviewTest.Columns.Insert(1, boundFieldNew);
// turn this into a collection or array prior to saving it to
viewstate
ViewState["savHeaderText"] = boundFieldNew.HeaderText;
ViewState["savDataField"] = boundFieldNew.DataField;

}

protected void m_buttonInsertColumn_OnClick(object sender, EventArgs e)
{
InsertBoundField();
BindGridToData();
}


}


markup source:


<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="CodeFrmHarry.aspx.cs" Inherits="CodeFrmHarry" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
<style type="text/css">
.style1
{
width: 100%;
}
.style2
{
width: 550px;
}
</style>
</head>
<body>
<form id="form1" runat="server">
<div>
<table class="style1">
<tr>
<td class="style2">
<asp:Button runat="server" Text="Insert Column"
ID="m_buttonInsertColumn" OnClick="m_buttonInsertColumn_OnClick" />
</td>
<td>
</td>
</tr>
<tr>
<td class="style2">
<asp:GridView ID="m_gridviewTest" runat="server"
AutoGenerateColumns="False" EnableViewState="False">
<Columns>
<asp:TemplateField HeaderText="Select" >
<ItemTemplate>
<asp:Button ID="buttonSelect" Text="Select"
runat="server"></asp:Button>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Delete" >
<ItemTemplate>
<asp:Button ID="buttonDelete" Text="Delete"
runat="server"></asp:Button>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</td>
<td>
</td>
</tr>
</table>
</div>
</form>


</body>
</html>

--
aaa


Harry Keck said:
Your example does work, but as you've guessed this will not take care of my
situation. I simply used a button in my template fields for the purpose of
creating an example. My real world scenario has much more complicated
templates, which can not be replicated with simple columns.

Angel said:
Wow!

Try this instead...

// ==================================================
using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;

public partial class CodeFrmHarry : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
BindGridToData();
}
}

private void BindGridToData()
{
DataSet datasetGrid = new DataSet();
datasetGrid.Tables.Add("GridDataTable");
datasetGrid.Tables[0].Columns.Add("1");

datasetGrid.Tables[0].Rows.Add("value 1");
datasetGrid.Tables[0].Rows.Add("value 2");

m_gridviewTest.DataSource = datasetGrid.Tables[0];
m_gridviewTest.DataBind();

}

private void InsertBoundField()
{
BoundField boundFieldNew = new BoundField();
boundFieldNew.DataField = "1";
m_gridviewTest.Columns.Insert(1, boundFieldNew);
}

protected void m_buttonInsertColumn_OnClick(object sender, EventArgs e)
{
InsertBoundField();
BindGridToData();
}

}

Markup source

<form id="form1" runat="server">
<div>
<asp:Button runat="server" Text="Insert Column"
ID="m_buttonInsertColumn" OnClick="m_buttonInsertColumn_OnClick" />
<asp:GridView ID="m_gridviewTest" runat="server"
AutoGenerateColumns="False">
<Columns>
<asp:ButtonField ButtonType="Button" Text="Select" />
<asp:ButtonField ButtonType="Button" Text="Delete" />
</Columns>
</asp:GridView>
</div>
</form>
// =================================================

Templates have always been Twitchy. Some really bizarre stuff happens when
you have multiple templates and viewstate is on. I have some articles I
titled “Why is everything so darned declarative†which deals with these kinds
of issues.

I am not giving up on finding the answer for you but in the end, I suspect
you are going to have to work around this with something like what I have
given you.

Try what I sent you let me know if you think you can use this instead. I
will continue to research this and will let you know if I come up with
something.

Regards,

--
aaa


"Harry Keck" wrote:
 
Ad

Advertisements

H

Harry Keck

Well, I did what you said, and I don't believe it, but it works. Simply
setting EnableViewState to false for the control completely cleared up the
issue with the column. I am going to give this a shot in my full
implementation and see if it hurts anything, but from the simple experiments
I did, it seems like it will be ok. Thank you very much for your help.

private const string NUMBER_OF_DYNAMIC_COLUMNS =
"NUMBER_OF_DYNAMIC_COLUMNS";

private void AddDynamicColumns()
{
int intNumberOfColumns = ViewState[NUMBER_OF_DYNAMIC_COLUMNS] ==
null ? 0 : (int)ViewState[NUMBER_OF_DYNAMIC_COLUMNS];
for (int i = 0; i < intNumberOfColumns; i++)
{
BoundField BF = new BoundField();
BF.HeaderText = (i + 1).ToString();
BF.DataField = "1";
m_gridviewTest.Columns.Insert(1, BF);
}
}

protected void Page_Load(object sender, EventArgs e)
{

if (!IsPostBack)
{
ViewState[NUMBER_OF_DYNAMIC_COLUMNS] = 0;
// BindGridToData();
}
else
{
// This should only happen on postback


// this is the restore side of your custom viewstate
management
// which you become responsible for when you add anything
dynamically
// in this case the columns collection. As I stated below
this should
// an array or collection.
AddDynamicColumns();

}
// This should happen everytime
BindGridToData();
}

private void BindGridToData()
{


DataSet datasetGrid = new DataSet();
datasetGrid.Tables.Add("GridDataTable");
datasetGrid.Tables[0].Columns.Add("1");

datasetGrid.Tables[0].Rows.Add("value 1");
datasetGrid.Tables[0].Rows.Add("value 2");

m_gridviewTest.DataSource = datasetGrid.Tables[0];
m_gridviewTest.DataBind();

}

private void InsertBoundField()
{
ViewState[NUMBER_OF_DYNAMIC_COLUMNS] =
(int)ViewState[NUMBER_OF_DYNAMIC_COLUMNS] + 1;

BoundField boundFieldNew = new BoundField();
boundFieldNew.DataField = "1";
m_gridviewTest.Columns.Insert(1, boundFieldNew);
// turn this into a collection or array prior to saving it to
viewstate
boundFieldNew.HeaderText =
ViewState[NUMBER_OF_DYNAMIC_COLUMNS].ToString();

}

protected void m_buttonInsertColumn_OnClick(object sender, EventArgs
e)
{
InsertBoundField();
BindGridToData();
}


Angel said:
oops the code ;-)

using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;

public partial class CodeFrmHarry : System.Web.UI.Page
{

protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
// BindGridToData();
}
else
{
// This should only happen on postback


// this is the restore side of your custom viewstate management
// which you become responsible for when you add anything
dynamically
// in this case the columns collection. As I stated below this
should
// an array or collection.
string rht = (string)ViewState["savHeaderText"];
string rdf = (string)ViewState["savDataField"];

if (rdf != null)
{
BoundField BF = new BoundField();
// BF.HeaderText = rht;
BF.DataField = rdf;
m_gridviewTest.Columns.Insert(1, BF);
}

}
// This should happen everytime
BindGridToData();
}

private void BindGridToData()
{


DataSet datasetGrid = new DataSet();
datasetGrid.Tables.Add("GridDataTable");
datasetGrid.Tables[0].Columns.Add("1");

datasetGrid.Tables[0].Rows.Add("value 1");
datasetGrid.Tables[0].Rows.Add("value 2");

m_gridviewTest.DataSource = datasetGrid.Tables[0];
m_gridviewTest.DataBind();

}

private void InsertBoundField()
{
BoundField boundFieldNew = new BoundField();
boundFieldNew.DataField = "1";
m_gridviewTest.Columns.Insert(1, boundFieldNew);
// turn this into a collection or array prior to saving it to
viewstate
ViewState["savHeaderText"] = boundFieldNew.HeaderText;
ViewState["savDataField"] = boundFieldNew.DataField;

}

protected void m_buttonInsertColumn_OnClick(object sender, EventArgs e)
{
InsertBoundField();
BindGridToData();
}


}


markup source:


<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="CodeFrmHarry.aspx.cs" Inherits="CodeFrmHarry" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
<style type="text/css">
.style1
{
width: 100%;
}
.style2
{
width: 550px;
}
</style>
</head>
<body>
<form id="form1" runat="server">
<div>
<table class="style1">
<tr>
<td class="style2">
<asp:Button runat="server" Text="Insert Column"
ID="m_buttonInsertColumn" OnClick="m_buttonInsertColumn_OnClick" />
</td>
<td>
</td>
</tr>
<tr>
<td class="style2">
<asp:GridView ID="m_gridviewTest" runat="server"
AutoGenerateColumns="False" EnableViewState="False">
<Columns>
<asp:TemplateField HeaderText="Select" >
<ItemTemplate>
<asp:Button ID="buttonSelect" Text="Select"
runat="server"></asp:Button>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Delete" >
<ItemTemplate>
<asp:Button ID="buttonDelete" Text="Delete"
runat="server"></asp:Button>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</td>
<td>
</td>
</tr>
</table>
</div>
</form>


</body>
</html>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top