updating GridView cell background color

G

Guest

I understand how to connect a SqlDataSource to a GridView and have a nice
data-connected, paginated web page generated with virtually no coding.
Starting from that base, I would like to add an extra column to the GridView
and do two things: for each row, based on the value of another column, insert
a string in the new column cell and set the background color of the new
column cell. Suggested approaches would be appreciated.
 
G

Guest

Hi Michael,
you can create handler for RowDataBound event of your GridView. In this
handler you will be able to access and modify cells and data of your current
row.

protected void myGridView_OnRowDataBound(object sender, GridViewRowEventArgs
e)
{
if (e.Row.RowType = DataGridRowType.DataRow)
{
// e.Row.Cells contains collection of server side td elements, you can
fill
// text property or work with collection of controls inside this element
e.Row.Cells[INDEX_OF_YOUR_COLUMN].Text = EvalMyField(e.Row.DataItem );
// DataItem contains source of data for this row, it is object used by data
source to fill your row
// you can also modify css style for your elelment
e.Row.Cells[INDEX_OF_YOUR_COLUMN].Attributes.Add("style", ".......");
}
}

Regards,
Ladislav
 
G

Guest

Splendid! I had to test for DataControlRowType.DataRow rather than
DataGridRowType.DataRow, but that essentially did most of what I needed.

Now how do I position the new column as the right-most column?
I first tried adding a new column of type Template in the visual designer.
This new column became the first column. I tried the same thing
programmatically by calling gridView.Columns.Add() in the PageLoad handler
and it also became the first column. I then switched to Columns.Insert() but
in the PageLoad handler the binding has not yet occurred, hence column count
is still 0. When the binding occurs, the columns are added to the right,
again leaving my new column as the left-most. What event handler would give
me access to the GridView after the columns have been loaded so I can then
add my new column where I want?
 
W

Walter Wang [MSFT]

Hi Michael,

I'm glad that you've solved your first issue.

For the second question, have you tried to add the column in GridView's
DataBound event? In this event, the data has been bound and those columns
are generated, therefore you can add your column to the right-most.

Please let me know the result. Thanks.


Regards,
Walter Wang ([email protected], remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

I had tried the DataBound event because that seemed to be the right place.
But the results were the same. To see why, here is the output of a test
program that includes a GridView with 5 columns from design-time where I
attempt to add 3 more columns at run-time.

Curiousities:
(1) The column count shows 0, not 5, upon entering the DataBound event
handler.
(2) After adding the 3 new columns, the column count is then 3, not 8, at
the conclusion of the event handler.
(3) The DataBound event is triggered twice so I had to add the
gridInitialized switch to prevent adding the columns again.
(4) The column count still shows 3 on the second pass through the DataBound
event handler, yet the grid displays with all 8 columns (the 3 new ones are
left-most).
With novice-like bravado I will say that it sure looks like the event is not
firing when it is supposed to!

=================================================
ENTERING GridView_DataBound: Column count=0, gridInitialized=False,
IsPostBack=False
ENTERING AddCol[1]
LEAVING AddCol
ENTERING AddCol[2]
LEAVING AddCol
ENTERING AddCol[3]
LEAVING AddCol
LEAVING GridView_DataBound: Column count=3, gridInitialized=True,
IsPostBack=False
ENTERING GridView_DataBound: Column count=3, gridInitialized=True,
IsPostBack=False
LEAVING GridView_DataBound: Column count=3, gridInitialized=True,
IsPostBack=False
=================================================

Here is the sample program:
=================================================
public partial class _Default : System.Web.UI.Page
{
private int numDays = 3;
private DateTime firstDisplayDate = new DateTime(2007, 1, 3);
private List<TemplateField> chartCol = new List<TemplateField>();
private bool gridInitialized = false;

protected void GridView1_DataBound(object sender, EventArgs e)
{
Out("ENTERING GridView_DataBound: Column count=" + GridView1.Columns.Count
+ ", gridInitialized=" + gridInitialized + ", IsPostBack="+IsPostBack);
if (!gridInitialized && !IsPostBack)
{
for (int i = 0; i < numDays; i++) { AddCol(); }
gridInitialized = true;
}
setDates();
Out("LEAVING GridView_DataBound: Column count=" + GridView1.Columns.Count
+ ", gridInitialized=" + gridInitialized + ", IsPostBack=" + IsPostBack);
}

private void setDates()
{
DateTime d = firstDisplayDate;
foreach (TemplateField t in chartCol)
{
t.HeaderText = d.ToString("ddd MM/dd");
d = d.AddDays(1);
}
}

private void AddCol()
{
TemplateField tField = new TemplateField();
chartCol.Add(tField);
Out("ENTERING AddCol["+chartCol.Count+"]");
GridView1.Columns.Add(tField);
Out("LEAVING AddCol");
}

private void Out(string s)
{
Response.Write(s + "<br>\n");
}

}
=================================================
 
W

Walter Wang [MSFT]

Hi Michael,

I've done some research and found out that if we're using
AutoGenerateColumns, then there's no way to add our columns after those
generated columns since we cann't find an appropriate event to add our code.

There are two workarounds:

1) Don't use AutoGenerateColumns = true, use manually configured columns.
This way, you can simply add your columns in Page_Load.

2) Create a custom GridView, override the CreateColumns method to add your
own columns:

public class Class1 : GridView
{
protected override System.Collections.ICollection
CreateColumns(PagedDataSource dataSource, bool useDataSource)
{
ArrayList list = new ArrayList(base.CreateColumns(dataSource,
useDataSource));

BoundField nameColumn = new BoundField();
nameColumn.DataField = "au_lname";
nameColumn.HeaderText = "Person Name";

TemplateField ckhColumn = new TemplateField();
ckhColumn.HeaderTemplate = new
GridViewTemplate(ListItemType.Header, "CheckBox Column");
ckhColumn.ItemTemplate = new
GridViewTemplate(ListItemType.Item, "some data");

list.Add(ckhColumn);
list.Add(nameColumn);
return list;
}
}


(The GridViewTemplate is a custom ITemplate that adds some user defined
controls which is from
http://www.gridviewguy.com/ArticleDetails.aspx?articleID=88)

public class GridViewTemplate : System.Web.UI.Page, ITemplate
{
ListItemType templateType;
string columnName;
public GridViewTemplate(ListItemType type, string colname)
{
templateType = type;
columnName = colname;
}

public void InstantiateIn(System.Web.UI.Control container)
{
Literal lc = new Literal();
LinkButton lb = new LinkButton();
CheckBox ckh = new CheckBox();
TextBox tb1 = new TextBox();
switch (templateType)
{
case ListItemType.Header:
lc.Text = "<B>" + columnName + "</B>";
lb.Text = "Edit";
lb.CommandName = "EditButton";
container.Controls.Add(lb);
container.Controls.Add(lc);
break;
case ListItemType.Item:

container.Controls.Add(tb1);
container.Controls.Add(ckh);
break;
case ListItemType.EditItem:
TextBox tb = new TextBox();
tb.Text = "";
container.Controls.Add(tb);
break;
case ListItemType.Footer:
lc.Text = "<I>" + columnName + "</I>";
container.Controls.Add(lc);
break;
}
}
}


Hope this helps.



Regards,
Walter Wang ([email protected], remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

(1) If I set AutoGenerateColumns = false, I presume that means I have to
manually add *all* columns? If so, do you have a code sample showing how I
would add columns bound to the original select statement (which were created
automatically before)?
(2) In your sample CreateColumns, am I correct that you are showing one
bound field and one new field? So does this also need to manually create all
columns that were bound from the select statement? Is "au_lname" one of the
items in the select list? Not really sure how this relates to the original
behavior where the framework did everything for me...
 
G

Guest

(1) If I set AutoGenerateColumns = false, I presume that means I have to
manually add *all* columns? If so, do you have a code sample showing how I
would add columns bound to the original select statement (which were created
automatically before)?
(2) In your sample CreateColumns, am I correct that you are showing one
bound field and one new field? So does this also need to manually create all
columns that were bound from the select statement? Is "au_lname" one of the
items in the select list? Not really sure how this relates to the original
behavior where the framework did everything for me...
 
W

Walter Wang [MSFT]

Hi Michael,

(1) That's right, if AutoGenerateColumns=False, you will need to manually
add all columns. You can do it declaratively in ASPX:

<asp:GridView ID="GridView1" runat="server"
AutoGenerateColumns="False" DataKeyNames="au_id"
DataSourceID="SqlDataSource1" OnDataBound="GridView1_DataBound"
OnDataBinding="GridView1_DataBinding">
<Columns>
<asp:BoundField DataField="au_id" HeaderText="au_id"
ReadOnly="True" SortExpression="au_id" />
<asp:BoundField DataField="au_lname" HeaderText="au_lname"
SortExpression="au_lname" />
</Columns>
</asp:GridView>


or you can add at runtime, in either case, you need to know the DataField
name ("au_id" and "au_lname" in above example).

It's possible to duplicate the functionality of how GridView's
AutoGenerateColumns does, however, it's much complicated and I don't think
it's worth the effort doing this: the GridView needs to support various
data source such as DataSource controls (ObjectDataSource, SqlDataSource,
etc.) and IEnumerable data, you can take a look at GridView's code using
Reflector (http://www.aisto.com/roeder/dotnet/) if you're interested.

(2) Yes one field is a data bound field, just like above declarative
example shows.

As I explained above, I think if you need to set the
AutoGenerateColumns=True, then I suggest you create a customized GridView
to add your custom columns; if you set AutoGenrateColumns=False, then you
need to manually setup those columns in ASPX or code, but you need to know
the data field names.


Hope this helps.


Regards,
Walter Wang ([email protected], remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

This all seems rather more convoluted that it should need to be. After all,
the GridView.Columns collection has both an Add and an Insert method. I am
rather skeptical that you are, in essence, saying that either or both of
those and the DataBound event do not work as advertised.
 
W

Walter Wang [MSFT]

Hi Michael,

I fully understand your concerns here. Please let me try to explain more
about the limitation here.

First, I apologize if my initial reply indicated that this could be done in
the DataBound event, which I later found out is not correct.

You are right that the columns has Insert and Add method, however, it's all
about the correct timing to call these methods if you need to position your
manually added column with the auto generated columns. Currently GridView
doesn't expose an appropriate event that could let you do this after the
columns are auto-generated, in other words, from the WebForm that hosts the
GridView, we don't have a correct event or time to call
GridView.Columns.Add or Insert.

On the other hand, the GridView internally does calls a virtual method
named 'CreateColumns' which can be overriden to append new columns after
the auto-generated columns.

I agree that this is a limitation of the GridView. I will make sure this
feature request is correctly forwarded to product team for future version's
improvement. In the meanwhile, you're also welcome to submit your feedback
at http://connect.microsoft.com/Main/content/content.aspx?ContentID=2220
which is monitored by product team directly and other community members can
also vote on the reqeust.

Thanks again for your great feedback!


Regards,
Walter Wang ([email protected], remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

Thanks for the detailed notes. As this approach is more work than I need for
the task at hand (and proved unwieldy for another unrelated reason as well),
I altered my design a bit so I could get away from this issue. Thanks, though!
 

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

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,817
Latest member
DicWeils

Latest Threads

Top