My old, standard code to do this in a previous version was throwing errors and required some research. The working code included a workaround for what some are classifying as a bug (It looks though as if MSFT closed it as ‘by design’). Your mileage may vary.
To implement this you need to have a datagrid on your page already and link up the ‘ImageButton1′ element to your ‘Open this grid in Excel’ image or button. You can then use the following pieces with little alterations. Pay attention to part 4, you may have a decision to make there.
Part 1:
You use the old standard code to wire up the button to call the method:
{
Response.Clear();
Response.Buffer = true;
Response.ContentType = "application/vnd.ms-excel";
Response.Charset = "";
this.EnableViewState = false;
StringWriter sw = new StringWriter();
HtmlTextWriter hw = new HtmlTextWriter(sw);
this.ClearControls(YOUR_GRID_CONTROL_HERE);
YOUR_GRID_CONTROL_HERE.RenderControl(hw);
Response.Write(sw.ToString());
Response.End();
}
Including the ClearControls method to strip controls out of your grid and leave their value instead. This is called in the click handler. I clearly need to get a code plugin for Wordpress as my spacing was lost in translation here and it sucks to read…
private void ClearControls(Control control)
{
for (int i = control.Controls.Count - 1; i >= 0; i--)
{
ClearControls(control.Controls[i]);
}
if (!(control is TableCell))
{
if (control.GetType().GetProperty("SelectedItem") != null)
{
LiteralControl literal = new LiteralControl();
control.Parent.Controls.Add(literal);
try
{
literal.Text =
(string)control.GetType().GetProperty("SelectedItem").GetValue(control, null);
}
catch
{
}
control.Parent.Controls.Remove(control);
}
else
if (control.GetType().GetProperty("Text") != null)
{
LiteralControl literal = new LiteralControl();
control.Parent.Controls.Add(literal);
literal.Text =
(string)control.GetType().GetProperty("Text").GetValue(control, null);
control.Parent.Controls.Remove(control);
}
}
return;
}
Here is where the old code (above) started throwing new errors. The 2 following items may or may not be needed depending on your configuration.
I was getting an error about the grid not being in the form at that point which was bogus (as it was in the form) and found the following workaround for what some felt is a bug (http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=118285). Regardless, placing this before the 2 methods above cleared the error. I didn’t need to call it though a co-worker was calling it from the onlick event. Regardless of if you call it directly or not, it contains no code.
public override void VerifyRenderingInServerForm(Control control)
{
// Confirms that an HtmlForm control is rendered for the
// specified ASP.NET server control at run time.
// No code required here.
}
Now I was getting an error stating ‘RegisterForEventValidation can only be called during Render();’. What info I found stated that this seems to occur when there are column sorts present when doing this operation.
That leaves you with 2 options (that I know of) if you want the resorting to still be enabled (and I did):
ONE: Turn the eventValidation off, either for the page or whole app. Effective, but not best practice for security so I opted for the slightly irritating, but just as effective, option 2. My advice would be to leave eventValidation in place and go with option 2, but hey, I like freedom of choice too so here is how to disable it if you want:
To disable eventValidation:
For a single page - Put this in the @ Page
EnableEventValidation = "false"
For your whole app - Put this in the web.config
<pages enableEventValidation ="false" ></pages>
TWO: You can define a second gridview which looks exactly like the original, but with visible=”false”. Then when you hit the export button you make the hidden grid visible and get the result you are after, but with a little messier code. The advantage here is that you can leave additional controls out of the 2nd grid and remove any styles so it renders better in Excel…