views:

2577

answers:

5

I am creating a GridView in a method like so:

GridView gridView = new GridView();
gridView.DataSource = reportData.Tables[0];
gridView.DataBind();

I am later exporting it to Excel and it works great. The columns are being auto-generated from my source data. I would like to change the DataFormatString property of some of the columns however after I databind and before I export to Excel. I can't seem to find the correct property to change. Can anybody point me in the right direction?

A: 

This is the issue of how asp.net works. When you create some controls (columns) in a method and set this controls set to user, the next time user post backs data to you, you do not have access to those columns since they … do not exists. Every time you display your site, a brand new object (instance) is created.
The only way to be able to get data in post back from previously created controls is to create controls in Page_Init method…

smok1
I'm not sure you understand what I'm trying to do here. I'm creating an instance of the grid in code to immediatly export to Excel. Postback is not an issue.
Mike C.
A: 

For example:

String newDataFormatString = "{0:d}";
BoundField bf = gridView.Columns[Index] as BoundField;
if (bf != null) {
    bf.DataFormatString = "{0}"; // workaround to sync with ViewState (it's documented)
    bf.DataFormatString = newDataFormatString;
}
JG
It appears when using AutoGenerateColumns the Columns collection is empty, although final result does indeed have columns.
Mike C.
A: 

Here's an extract from a GridView exporter I wrote that converts controls in a GridView into literals that are re-formated. It might be of some help:

     /// <summary>
 /// Parses and cleans up data from the GridView controls collection
 /// to make the data more suitable for Exported
 /// </summary>
 /// <param name="gv">The GridView to parse</param>
 private void CleanUpControls(Control gv)
 {
  Literal l = new Literal();

  for (int i = 0; i < gv.Controls.Count; i++)
  {

   if (gv.Controls[i].GetType() == typeof (LinkButton))
   {
    l.Text = (gv.Controls[i] as LinkButton).Text;
    ReplaceWithLiteral(gv, l, i);
   }
   else if (gv.Controls[i].GetType() == typeof (ListControl))
   {
    l.Text = (gv.Controls[i] as ListControl).SelectedItem.Text;
    ReplaceWithLiteral(gv, l, i);
   }
   else if (gv.Controls[i].GetType() == typeof (CheckBox))
   {
    l.Text = (gv.Controls[i] as CheckBox).Checked ? "True" : "False";
    ReplaceWithLiteral(gv, l, i);
   }
   else if (gv.Controls[i].GetType() == typeof (BooleanImage))
   {
    l.Text = (gv.Controls[i] as BooleanImage).Value ? "True" : "False";
    ReplaceWithLiteral(gv, l, i);
   }
   else if (gv.Controls[i].GetType().ToString() == "System.Web.UI.WebControls.PagerTable")
    ReplaceWithLiteral(gv, l, i);

   else if (gv.Controls[i].GetType() == typeof (HyperLink))
   {
    HyperLink hl = gv.Controls[i] as HyperLink;
    if (MakeHyperLinksAbsolute)
    {
     if (hl != null)
      hl.NavigateUrl = UrlHelper.MakeAbsoluteUrl(hl.NavigateUrl);
    }

    switch (TreatHyperLinksAs)
    {
     case HyperLinkMode.Text:
      l.Text = hl.Text;
      ReplaceWithLiteral(gv, l, i);
      break;

     case HyperLinkMode.NavigateUrl:
      if (hl != null) l.Text = hl.NavigateUrl;
      ReplaceWithLiteral(gv, l, i);
      break;

     case HyperLinkMode.ToolTip:
      l.Text = hl.ToolTip;
      ReplaceWithLiteral(gv, l, i);
      break;

     case HyperLinkMode.TextAndLink:
      l.Text = String.Format("{0} ({1})", hl.Text, hl.NavigateUrl);
      ReplaceWithLiteral(gv, l, i);
      break;

     case HyperLinkMode.HyperLink:
      break;
    }
   }

   if (gv.Controls[i].HasControls())
    CleanUpControls(gv.Controls[i]);
  }
 }
Dan Diplo
This doesn't really help in the context of my question. I'm sure it is useful for other applications.
Mike C.
+1  A: 

According to AutoGenerateColumns documentation:

This option provides a convenient way to display every field in the data source; however, you have limited control of how an automatically generated column field is displayed or behaves.

Note: Automatically generated bound column fields are not added to the Columns collection.

I tired looking for these AutoGeneratedFields with no luck.
I can think of several options to achieve that (from worst to best):

  1. Add an event to the grid (like RowDataBound), this will give you access to the rows' cells, but isn't too convenient.
  2. Don't use AutoGeneratedField Create these columns manually, as in:

    BoundField dateField = new BoundField();
    dateField.HeaderText = "Date";
    dateField.DataField = "date";
    dateField.DataFormatString = "{0:MMMM, yyyy}";
    gridView.Columns.Add(dateField);
    

    This options gives you bes control over titles.

  3. Add another layer for data formatting and presentation. This is probably the best option. Also, that way you don't have to use DataTables, a GridView can by bound to any collection of objects with public properties (eg, to a List<Employee)), and AutoGeneratedField turns them into columns.
    I think this is the best option. Suppose you could access the auto columns, what then? You'd have to search for a column based on its name or index, which seems very messy, and increases coupling.

And, as a last note, you should think about creating Excel files by using the API. It's not as easy, but HTML XLS files are less compatible with Excel 2007 - it displays a warning message that the format of the file is incompatible with the extension, and worse, the file brakes if it is opened and saves (can be Save As though), making your files less user-friendly.

Kobi
Using the API requires Excel to be installed on the server... correct?
Mike C.
I believe so if you're using office interop. If you create xlsx files (of office 2007), they are basically a group of zipped XML files, so you can create them relatively easily (best - find a library). You can also write to Excel via a connection string and ole db. The simplest way, btw (thoug without formatting), is to create a CSV file.
Kobi
I cannot install Excel on the server. I can't use the xlsx files because these have to be compatible with 2000 and 2003. Formatting is required so I can't use csv. I think I may try your second suggestion above and I'll see how that works. Thanks!
Mike C.
Your method #2 above seems to work well, but now I can't format my header row with the following code because gridView.HeaderRow is null. How can I get around this?gridView.HeaderRow.BackColor = System.Drawing.Color.Yellow;
Mike C.
Hi, well, this is a whole new question, but try the gridView.HeaderStyle property, should be what you're looking for. Also, try looking for the HeaderRow at another event, like `DataBound`, it is null at `Load`, see http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.headerrow.aspx
Kobi
Thank you for your help!
Mike C.
A: 

can somebody show me how to format it from the codebehind? thanks

camping