I have this code which export data from GridView to csv. It works with other sites but not on this current one I've been developing.
The GridView is binded with DataTable in code behind. Following is the event that binds the fetch and bind the data to GridView.
private void bindGridView()
{
//Fetching data from DB goes here
myTable.Columns.Add("type", typeof(int));
myTable.Columns.Add("rate", typeof(int));
foreach (DataRow rows in myTable.Rows)
{
if (rows["dst"].ToString() == "1875")
{
rows["type"] = 1;
rows["rate"] = 500;
rows.AcceptChanges();
}
else if (rows["dst"].ToString() == "1876")
{
rows["type"] = 0;
rows["rate"] = 30;
rows.AcceptChanges();
}
}
gridViewData.DataSource = myTable;
gridViewData.AllowPaging = true;
gridViewData.PageSize = 10;
gridViewData.DataBind();
}
Following is the button click event to export data from GridView
protected void btnExportCDR_Click(object sender, EventArgs e)
{
if (gridViewData.Rows.Count == 0)
{
lblStatus.Text = "Data is empty. Can not export CDR. Please check your filtering dates.";
}
else
{
Response.Clear();
Response.Buffer = true;
Response.AddHeader("content-disposition", "attachment;filename=CDRMMCC_" + System.DateTime.Now.ToShortDateString() + ".csv");
Response.Charset = "";
Response.ContentType = "application/text";
bindGridView();
gridViewData.AllowPaging = false;
StringBuilder sb = new StringBuilder();
//I did a trace here, gridViewData.Columns.Count is 0. That's why it got skipped, I think.
for (int k = 0; k < gridViewData.Columns.Count; k++)
{
sb.Append(gridViewData.Columns[k].HeaderText + ",");
}
sb.Append("\r\n");
for (int i = 0; i < gridViewData.Rows.Count; i++)
{
for (int k = 0; k < gridViewData.Columns.Count; k++)
{
sb.Append(gridViewData.Rows[i].Cells[k].Text + ",");
}
sb.Append("\r\n");
}
Response.Output.Write(sb.ToString());
Response.Flush();
Response.End();
}
}
Please advice.
If you use the AutoGenerateColumns property of the GridView set to true the Columns collection will be empty. The MSDN documentation for this property says:
"Automatically generated bound column fields are not added to the Columns collection".
This is the reason your Columns collection is empty. As Henk Holterman pointed out use your DataTable directly to generate your CSV file.
An alternative approach would be to set the AutoGenerateColumns property to false and define the Columns explicitly.
In addition to Hans answer, you can use RenderControl of the GridView which reduces your work.
StringWriter strWriter = new StringWriter();
HtmlTextWriter htmlWriter = new HtmlTextWriter(strWriter);
MyGridView.RenderControl(htmlWriter);
Response.Write(strWriter.ToString());
Related
I have a datagrid that stores its data to a csv file when the application closes and retrieves it on load. I have a button that deletes rows from the datagrid using the code shown below. When I call the delete method, the row deletes from the datagrid, but not from the csv file. This means that when I restart the application, the data is loaded back into the datagrid, but is not given the correct index and throws this error:
System.NullReferenceException: 'Object reference not set to an instance of an object.' System.Windows.Forms.DataGridViewCell.Value.get returned null.
How could I modify my delete statement so that it deletes both the row in the datagrid view, and delete the specific row from my csv file, so that it isn't displayed when I reload the application?
private void DeleteItem()
{
var dataGrid = dataGridViewRegisteredVehicles;
foreach (DataGridViewCell oneCell in dataGrid.SelectedCells)
{
if (oneCell.Selected)
{
dataGrid.Rows.RemoveAt(oneCell.RowIndex);
GetSumOfCost();
}
}
}
Here is the code that stores the data:
public void Store(MainForm form)
{
var data = form.dataGridViewRegisteredVehicles;
using (var temp = new FileStream(#"C:\temp\Data.csv", FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
TextWriter write = new StreamWriter(temp);
for (int rows = 0; rows < data.Rows.Count; rows++)
{
for (int columns = 0; columns < data.Columns.Count; columns++)
{
write.Write("\t" + data.Rows[rows].Cells[columns].Value.ToString() + "\t" + "|");
}
write.WriteLine("");
}
write.Close();
}
}
And here is the code that retrieves the data:
public void Load(MainForm form)
{
string[] lines = File.ReadAllLines(#"C:\temp\Data.csv");
string[] data;
for (int i = 0; i < lines.Length; i++)
{
data = lines[i].ToString().Split('|');
string[] row = new string[data.Length];
for (int j = 0; j < data.Length; j++)
{
row[j] = data[j].Trim();
}
form.dataGridViewRegisteredVehicles.Rows.Add(row);
}
}
Easier if you forget the CSV and use an XML file instead:
Make a new form
Put a datagridview on your form
Put this code in the FormClosing event (double click FormClosing in the formdesigner, in the lightning bolt of the properties grid after clicking the background of the form)
(dataGridView1.DataSource as DataTable).WriteXml("grid.xml");
Put this code in the FormLoad event:
var dt = new DataTable();
if(File.Exists("grid.xml")){
dt.ReadXml("grid.xml");
} else {
dt.Columns.Add("Name");
dt.Columns.Add("Age");
}
dataGridView1.DataSource = dt;
So when you delete a row from the grid it will delete from the datatable. Being gone from the datatable means it isn't written to the file. The next time the program opens, the row is not present
This leverages the built in ability for a datatable to write itself/read itself from an xml file. If you want to extend it to doing a csv instead, you can merge in your existing code
Here is the table structure:
enter image description here
Here is the code:
protected void Write_CSV_From_Recordset2(SqlDataReader oDataReader)
{
StringBuilder builder = new StringBuilder();
List<string> columnNames = new List<string>();
List<string> rows = new List<string>();
for (int i = 0; i < oDataReader.FieldCount; i++)
{
string tmpColumnName = oDataReader.GetName(i);
columnNames.Add(tmpColumnName);
}
builder.Append(string.Join(",", columnNames.ToArray())).Append("\n");
List<string> currentRow = new List<string>();
while (oDataReader.Read())
{
////base.WriteLog(oDataReader.FieldCount + "fieldcount");
for (int i = 0; i < oDataReader.FieldCount; i++)
{
object item = oDataReader[i];
currentRow.Add(item.ToString());
}
}
//builder.Append(string.Join("\n", rows.ToArray())).Append("\n");
rows.Add(string.Join(",", currentRow.ToArray()));
builder.Append(string.Join(",", rows.ToArray())).Append("\n");
Response.Clear();
Response.ContentType = "text/csv";
Response.AddHeader("Content-Disposition", "attachment;filename=pretestscore.csv");
Response.Write(builder.ToString());
Response.End();
}
The problem is that while output is begin returned, the
while (oDataReader.Read())
function the value are being returned just like
281063,70,7091,85,TEST,200,test,NULL
How to get actually data from the table?
Where is the mistake in my code?
Any suggestions?
protected void Write_CSV_From_Recordset2(SqlDataReader oDataReader)
{
string strCSV = string.Empty;
for (int i = 0; i < oDataReader.FieldCount; i++)
{
string tmpColumnName = oDataReader.GetName(i);
strCSV += tmpColumnName + ',';
}
strCSV += "\r\n";
while (oDataReader.Read())
{
for (int i = 0; i < oDataReader.FieldCount; i++)
{
object item = oDataReader[i];
strCSV += item.ToString().Replace(",", ";") + ',';
}
strCSV += "\r\n";
}
//Download the CSV file.
Response.Clear();
Response.Buffer = true;
Response.AddHeader("content-disposition", "attachment;filename=pretestscore.csv");
Response.Charset = "";
Response.ContentType = "application/text";
Response.Output.Write(strCSV);
Response.Flush();
Response.End();
}
You can directly write code with comma separated with for loop or while loop.
You can refer this code and you will get idea
string s;
while (reader.Read())
{
if(!String.IsNullOrEmpty(s)){
s += ", ";
}
s += reader["name"].ToString();
}
I have 300 csv files that each file contain 18000 rows and 27 columns.
Now, I want to make a windows form application which import them and show in a datagridview and do some mathematical operation later.
But, my performance is very inefficiently...
After search this problem by google, I found a solution "A Fast CSV Reader".
(http://www.codeproject.com/Articles/9258/A-Fast-CSV-Reader)
I'm follow the code step by step, but my datagridview still empty.
I don't know how to solve this problem.
Could anyone tell me how to do or give me another better way to read csv efficiently.
Here is my code...
using System.IO;
using LumenWorks.Framework.IO.Csv;
private void Form1_Load(object sender, EventArgs e)
{
ReadCsv();
}
void ReadCsv()
{
// open the file "data.csv" which is a CSV file with headers
using (CachedCsvReader csv = new
CachedCsvReader(new StreamReader("data.csv"), true))
{
// Field headers will automatically be used as column names
dataGridView1.DataSource = csv;
}
}
Here is my input data:
https://dl.dropboxusercontent.com/u/28540219/20130102.csv
Thanks...
The data you provide contains no headers (first line is a data line). So I got an ArgumentException (item with same key added) when I tried to add the csv reader to the DataSource. Setting the hasHeaders parameter in the CachCsvReader constructor did the trick and it added the data to the DataGridView (very fast).
using (CachedCsvReader csv = new CachedCsvReader(new StreamReader("data.csv"), false))
{
dataGridView.DataSource = csv;
}
Hope this helps!
You can also do like
private void ReadCsv()
{
string filePath = #"C:\..\20130102.csv";
FileStream fileStream = null;
try
{
fileStream = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
}
catch (Exception ex)
{
return;
}
DataTable table = new DataTable();
bool isColumnCreated = false;
using (StringReader reader = new StringReader(new StreamReader(fileStream, Encoding.Default).ReadToEnd()))
{
while (reader.Peek() != -1)
{
string line = reader.ReadLine();
if (line == null || line.Length == 0)
continue;
string[] values = line.Split(',');
if(!isColumnCreated)
{
for(int i=0; i < values.Count(); i++)
{
table.Columns.Add("Column" + i);
}
isColumnCreated = true;
}
DataRow row = table.NewRow();
for(int i=0; i < values.Count(); i++)
{
row[i] = values[i];
}
table.Rows.Add(row);
}
}
dataGridView1.DataSource = table;
}
Based on you performance requirement, this code can be improvised. It is just a working sample for your reference.
I hope this will give some idea.
I have used ext.net 1.6 tool. I tried to convert data datatable to csv but i am getting error status code : 200 and status text : Bad Request.
And I also exported data from ext.net gridpanel to csv but now i want to export directly datatable to csv.
I passed Jason string for datatable same as passed for gridpanel but gridpanel data is exported perfectly, but datatable does not export with same method
can you suggest me?
what is exact problem with that?
Thanks
Use the below
Method to convert the Datatable data to export into CSV in c#:
void ToCSVDownload(DataTable dtDataTable)
{
var stream = new MemoryStream();
StreamWriter sw = new StreamWriter(stream);
//Writing Headers
for (int i = 0; i < dtDataTable.Columns.Count; i++)
{
sw.Write(dtDataTable.Columns[i]);
if (i < dtDataTable.Columns.Count - 1)
{
sw.Write(",");
}
}
sw.Write(sw.NewLine);
//Writing Data
foreach (DataRow dr in dtDataTable.Rows)
{
for (int i = 0; i < dtDataTable.Columns.Count; i++)
{
if (!Convert.IsDBNull(dr[i]))
{
string value = dr[i].ToString();
if (value.Contains(','))
{
value = String.Format("\"{0}\"", value);
sw.Write(value);
}
else
{
sw.Write(dr[i].ToString());
}
}
if (i < dtDataTable.Columns.Count - 1)
{
sw.Write(",");
}
}
sw.Write(sw.NewLine);
}
sw.Close();
//converting it to the Bytes
byte[] byteArray = stream.ToArray();
//Dowloading the file by writing Bytes
Response.AddHeader("Content-Disposition", "attachment; Filename = test.csv");
Response.ContentType = "application/octet-stream";
Response.BinaryWrite(byteArray);
Response.End();
}
I have tried Exporting GridView to Excel but observed that
the Dynamically added last Row to Gridview is not exported to excel.
I have two datasets first one binds the data directly to Gridview.
After Which I add the last row from another DataSet.
In the page I'm able to see the result as Expected but when exported excel I'm not.
Below is my code:
DataSet dsgrid = SqlHelper.ExecuteDataset(DBConnectionString.ConnectionString, CommandType.StoredProcedure, "usp_Training_GetCirclescoreCardReport ", sqlparam);
if (TrainingUtil.isDataSetValid(dsgrid))
{
RSGScoreCard_Grid.DataSource = dsgrid;
RSGScoreCard_Grid.DataBind();
AddOverallRow(dsgrid);
}
else RSGScoreCard_Grid.DataBind();
Adding Overall row at bottom:
#region Add OverallRow
private void AddOverallRow(DataSet dsgrid)
{
using (GridViewRow gr = new GridViewRow(RSGScoreCard_Grid.Rows.Count + 1, 0, DataControlRowType.DataRow, DataControlRowState.Normal))
{
for (int i = 0; i < 6; i++)//6 is the column count for overall row
{
using (TableCell tc = new TableCell())
{
gr.Cells.Add(tc);
if (i == 0)
{
gr.Cells[i].ColumnSpan = 4;
gr.Cells[i].Text = "Overall";
gr.Cells[i].Attributes.Add("class", "fcol");
gr.Cells[i].Attributes.Add("style", "font-weight:bold;padding-left:20%");
}
else gr.Cells[i].Attributes.Add("style", "font-weight:bold");
}
}
if (dsgrid.Tables[1] != null)//creating a dynamic row to gridview
if (dsgrid.Tables[1].Rows.Count > 0)
{
gr.Cells[1].Text = dsgrid.Tables[1].Rows[0][5].ToString();
gr.Cells[1].Width = Unit.Percentage(8);
gr.Cells[2].Text = dsgrid.Tables[1].Rows[0][6].ToString();
gr.Cells[2].Width = Unit.Percentage(8);
gr.Cells[3].Text = dsgrid.Tables[1].Rows[0][7].ToString();
gr.Cells[3].Width = Unit.Percentage(8);
gr.Cells[4].Text = dsgrid.Tables[1].Rows[0][8].ToString();
gr.Cells[4].Width = Unit.Percentage(8);
gr.Cells[5].Text = dsgrid.Tables[1].Rows[0][9].ToString();
gr.Cells[5].Width = Unit.Percentage(8);
}
gr.Attributes.Add("class", "row2");
RSGScoreCard_Grid.Controls[0].Controls.AddAt(RSGScoreCard_Grid.Rows.Count + 1, gr);
}
}
#endregion
and Last my code to Export the GrieView:
protected void btnExport_Click(object sender, EventArgs e)
{
TrainingUtil.Export(ddlOptions.SelectedItem.Text.ToString().Replace(" ", string.Empty) + "_" + ddlVerticals.SelectedItem.Text.ToString().Replace(" ", string.Empty) + "_" + ddlLernerGroups.SelectedItem.Text.ToString().Replace(" ", string.Empty), RSGScoreCard_Grid, "For the Month/Year: " + ddlFromMonths.SelectedItem.Text.ToString()+"/"+ddlYears.SelectedItem.Text.ToString(), RSGScoreCard_Grid.HeaderRow.Cells.Count);
}
public override void VerifyRenderingInServerForm(Control control)
{
/* Confirms that an HtmlForm control is rendered for the specified ASP.NET
server control at run time. */
}
the Export Method in TrainingUtil class
#region Export
public static void Export(string filename, GridView grid, string Heading, int ColumnsCount)
{
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.AddHeader("content-disposition", string.Format("attachment; filename={0}", filename + ".xls"));
HttpContext.Current.Response.ContentType = "application/ms-excel";
using (StringWriter sw = new StringWriter())
{
using (HtmlTextWriter htw = new HtmlTextWriter(sw))
{
grid.HeaderStyle.BackColor = System.Drawing.Color.Cyan;
//Cells color settings
GridViewRow row = new GridViewRow(0, 0, DataControlRowType.DataRow, DataControlRowState.Normal);
TableCell cell = new TableCell();
cell.Text = String.Format("{0}", Heading);
cell.ColumnSpan = ColumnsCount;
cell.Attributes.Add("align", "center");
cell.Attributes.Add("class", "yellow");
row.Cells.Add(cell);
grid.Controls[0].Controls.AddAt(0, row);
foreach (GridViewRow gridRow in grid.Rows)
{
foreach (TableCell tcGridCells in gridRow.Cells)
{
tcGridCells.Attributes.Add("class", "sborder");
}
}
grid.RenderControl(htw);
//Add the style sheet class here
HttpContext.Current.Response.Write(#"<style> .sborder { color : Black;border : 1px Solid Black; } .yellow {background-color:yellow;color:black;} </style> ");
HttpContext.Current.Response.Write(sw.ToString());
HttpContext.Current.Response.End();
}
}
}
#endregion
Can any help me out.Why I'm not able to export the last row.
Thanks in advance
I think in every post back your not binding the dynamically added rows.
Try to find the control which cause the postback and bind the data once again.
Code to find the postback control ex:-
public static Control GetPostBackControl(Page page)
{
Control control = null;
string ctrlname = page.Request.Params.Get("__EVENTTARGET");
if (ctrlname != null && ctrlname != string.Empty)
{
control = page.FindControl(ctrlname);
}
else
{
foreach (string ctl in page.Request.Form)
{
Control c = page.FindControl(ctl);
if (c is System.Web.UI.WebControls.Button)
{
control = c;
break;
}
}
}
return control;
}