i set set datagridview AllowUserToAddRows true but after i add row programmatically, the uncommitted new row not visible, even i focus on last row and press enter, here is the code:
OpenFileDialog Open_DLG = new OpenFileDialog();
Open_DLG.Filter = "Text Files|*.txt";
if (Open_DLG.ShowDialog() == DialogResult.OK)
{
string[] Lines = File.ReadAllLines(Open_DLG.FileName);
int RowIndex = 0;
int ColumnIndex = 1;
foreach (string Line in Lines)
{
if (ColumnIndex > DataGRD_Comments.Columns.Count - 1)
{
RowIndex = DataGRD_Comments.Rows.Add();
ColumnIndex = 1;
}
DataGRD_Comments.Rows[RowIndex].Cells[ColumnIndex].Value = Line;
ColumnIndex++;
}
}
also i add columns programmatically,
i want to keep uncommitted new row visible after add rows programmatically? how to do that?
thanks
I am guessing you want to put all lines from a file into the DataGrid.
I think you need something like this short example.
foreach (string Line in Lines)
{
RowIndex = DataGRD_Comments.Rows.Add();
DataGRD_Comments.Rows[RowIndex].Cells[ColumnIndex].Value = Line;
}
What is the main reason of this error
No individual rows in this collection can be addressed because the
table contains vertically linked cells. '
I have table in which I want to add data (stored in array) but second row of the table is merged and I got this error message.
What can be appropriate solution to remove this error.
Code :
if (pCell.Range.Text.Contains("List of components robots"))
{
iDT16 = 0; rowcount = 0;
foreach (int Row in wordDocument.Tables[j].ToString()) // Add row in the table according to data available inside Result array
{
while (sDesignation_Componentsrobots[iDT16] != null)
{
wordDocument.Tables[j].Rows.Add();
wordDocument.Tables[j].Rows.SetHeight(28, Word.WdRowHeightRule.wdRowHeightAtLeast);
rowcount = wordDocument.Tables[j].Rows.Count;
iDT16++;
}
}
// Fill the row with data and add checkbox in particular table column.
iDT16 = 0; iEST16 = 0;
for (int row = 3; row <= rowcount; row++)
{
wTable.AllowAutoFit = true;
wTable.Rows[row].Range.Font.Bold = 0;
wTable.Rows[row].Range.ParagraphFormat.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter;
wTable.Rows[row].Range.ParagraphFormat.SpaceBefore = 5;
wTable.Cell(row, 1).Range.Text = sDesignation_Componentsrobots[iDT16];
wTable.Cell(row, 3).Range.Text = sEmergency_stopcircuit_T16[iEST16];
Word.FormField checkBox2 = wTable.Cell(row, 6).Range.FormFields.Add(wTable.Cell(row, 6).Range, Word.WdFieldType.wdFieldFormCheckBox);
iDT16++; iEST16++;
}
break;
}
Table with merged row:
I'm looking for the way to improve Datatable mapping to Excel spreadsheet.
Current code using looping technique to import data from DataTable to Excel:
for (int i = 0; i < dt.Columns.Count; i++)
{
thc = new TableHeaderCell();
thc.BorderWidth = 1;
thc.BorderStyle = BorderStyle.Solid;
//thc.Style.Add("backgroundColor", "#cacab5");
thc.BorderColor = System.Drawing.Color.White;
thc.BackColor = System.Drawing.Color.BurlyWood;
thc.Text = dt.Columns[i].ColumnName;
thr.Cells.Add(thc);
}
tblReport.Rows.Add(thr);
for (int j = 0; j < dt.Rows.Count; j++)
{
tr = new TableRow();
tr.BorderStyle = BorderStyle.Solid;
if (bt == "IE")
tr.BorderWidth = 1;
else
tr.BorderWidth = 2;
tr.BorderColor = System.Drawing.Color.White;
long n;
for (int i = 0; i < dt.Columns.Count; i++)
{
td = new TableCell();
td.BorderWidth = 1;
td.BorderStyle = BorderStyle.Solid;
td.BorderColor = System.Drawing.Color.White;
td.BackColor = System.Drawing.Color.Bisque;
td.Text = dt.Rows[j][i].ToString();
n = 0;
bool isNumeric = long.TryParse(td.Text, out n);
if (isNumeric && td.Text.Length > 10)
td.Attributes.Add("style", #"mso-number-format:\#");
tr.Cells.Add(td);
}
tblReport.Rows.Add(tr);
}
I found another way to do it through EPPlus.
Which way is faster?
EPPlus is very fast and efficient as is. Anything that is going to make it look like it copies your recordset to the workbook in one method is going to internally be looping over columns and rows in one fashion or another. So, the answer is to look at how many things you are doing and how you might optimize them.
From the code snippet you provided, two things I would recommend: First, you do not have to explicitly add rows to the worksheet before inserting values into the cells. This will slow things down quite a lot as your in memory EPPlus object gets bigger. If you are always just writing to the next row, then you never have to explicitly add a row, just reference your next row by index.
Next do not set the display attributes on every cell each time you write a value to the cell. Set it for the whole row (or column) using a range. Or better yet, do it for the whole worksheet at once after you have written out all the data in the cells for all your columns and rows. An example might be like the following which sets a Style setting for the columns A through E in one method call:
using (ExcelRange er = myWorksheet.Cells["A" + lineNo.ToString() + ":E" +
lineNo.ToString()]) {
er.Style.Font.Bold = true;
}
The fastest way I have found is to pass the DataTable into the LoadFromDataTable function for a range of cells.
_workSheet.Cells[startRow,startColumn,endRow,endColumn].LoadFromDataTable(dataTable);
I have a dynamically created WPF Grid (rows and columns count based on layout) like this:
private Grid CreateGrid(string layout)
{
int col;
int row;
if (layout == "4x4")
{
row = 4;
col = 4;
}
else
{
row = 2;
col = 2;
}
Grid output = new Grid();
for (int i = 0; i < col; i++)
{
ColumnDefinition coldef = new ColumnDefinition();
coldef.Width = GridLength.Auto;
output.ColumnDefinitions.Add(coldef);
}
for (int i = 0; i < row; i++)
{
RowDefinition rowdef = new RowDefinition();
rowdef.Height = GridLength.Auto;
output.RowDefinitions.Add(rowdef);
}
return output;
}
In each of these "cells" should be another object, filled with data from dataSet (one table per object). That object is also another set of grids. My aim is to loop through this dynamically created grid and put this object into each cell. (and if there is layout 2x2 but only 3 tables in the dataset, I want only 3 object there and last cell would be empty)
However, I did not find anything like "foreach column in grid", or even how to get column / row count. On the other hand, all I found was related to DataGrid or GridView - what is the difference, and if the other type would be better to use for this, why?
Thanks in advance
So, I was able to find a solution to this. It might not be the best one, but it works.
Here is the code:
foreach (DataTable table in result.Tables)
{
GfoTopBox box1 = StuffData(table);
Grid.SetRow(box1, j);
Grid.SetColumn(box1, i);
output.Children.Add(box1);
i++;
if (i >= output.ColumnDefinitions.Count)
{
i = 0;
j++;
}
}
"result" is the data set, each table provides the data for one of the objects I wanted to put in the cells of the Grid in the question (output).
However, if anyone has better solution, I am open to suggestions :)
I have user supplied excel files that need to be converted to PDF. Using excel interop, I can do this fine with .ExportAsFixedFormat(). My problem comes up when a workbook has millions of rows. This turns into a file that has 50k+ pages. That would be fine if the workbook had content in all of those rows. Every time one of these files shows up though, there are maybe 50 rows that have content and the rest are blank. How can I go about removing the empty rows so I can export it to a decent sized PDF?
I've tried starting at the end row and, one-by-one, using CountA to check if the row has content and if it does, delete it. Not only does this take forever, this seems to fail after about 100k rows with the following error:
Unable to evaluate expression because the code is optimized or a native frame is on top of the call stack.
I've tried using SpecialCells(XlCellType.xlCellTypeLastCell, XlSpecialCellsValue.xlTextValues) but that includes a row if any cell has formatting (like a bg color).
I've tried using Worksheet.UsedRange and then deleting everything after that but UsedRange has the same problem as point two.
This is the code I've tried:
for (int i = 0; i < worksheets.Count; i++)
{
sheet = worksheets[i + 1];
rows = sheet.Rows;
currentRowIndex = rows.Count;
bool contentFound = false;
while (!contentFound && currentRowIndex > 0)
{
currentRow = rows[currentRowIndex];
if (Application.WorksheetFunction.CountA(currentRow) == 0)
{
currentRow.Delete();
}
else
{
contentFound = true;
}
Marshal.FinalReleaseComObject(currentRow);
currentRowIndex--;
}
Marshal.FinalReleaseComObject(rows);
Marshal.FinalReleaseComObject(sheet);
}
for (int i = 0; i < worksheets.Count; i++)
{
sheet = worksheets[i + 1];
rows = sheet.Rows;
lastCell = rows.SpecialCells(XlCellType.xlCellTypeLastCell, XlSpecialCellsValue.xlTextValues);
int startRow = lastCell.Row;
Range range = sheet.get_Range(lastCell.get_Address(RowAbsolute: startRow));
range.Delete();
Marshal.FinalReleaseComObject(range);
Marshal.FinalReleaseComObject(lastCell);
Marshal.FinalReleaseComObject(rows);
Marshal.FinalReleaseComObject(sheet);
}
Do I have a problem with my code, is this an interop problem or maybe it's just a limitation on what Excel can do? Is there a better way to do what I'm attempting?
I would suggest you to get the count of rows which contain some values, using CountA (as you have tried in point 1). Then copy those rows into a new sheet and export it from there. It will be easier to copy few rows to new sheet and working on it, rather than trying to delete huge number of rows from source sheet.
For creating new sheet and copying rows you can use the following code:
excel.Worksheet tempSheet = workbook.Worksheets.Add();
tempSheet.Name = sheetName;
workbook.Save();
//create a new method for copy new rows
//as the rowindex you can pass the total no of rows you have found out using CountA
public void CopyRows(excel.Workbook workbook, string sourceSheetName, string DestSheetName, int rowIndex)
{
excel.Worksheet sourceSheet = (excel.Worksheet)workbook.Sheets[sourceSheetName];
excel.Range source = (excel.Range)sourceSheet.Range["A" + rowIndex.ToString(), Type.Missing].EntireRow;
excel.Worksheet destSheet = (excel.Worksheet)workbook.Sheets[DestSheetName];
excel.Range dest = (excel.Range)destSheet.Range["A" + rowIndex.ToString(), Type.Missing].EntireRow;
source.Copy(dest);
excel.Range newRow = (excel.Range)destSheet.Rows[rowIndex+1];
newRow.Insert();
workbook.Save();
}
Have you tried Sheet1.Range("A1").CurrentRegion.ExportAsFixedFormat() where Sheet1 is a valid sheet name and "A1" is a cell you can test to ensure it is located in the range you want to export?
The question remains, why does Excel think there is data in those "empty" cells? Formatting? A pre-existing print area that needs to be cleared? I know I've encountered situations like that before, those are the only possibilities that come to mind at this moment.
Try these steps -
copy Worksheet.UsedRange to a separate sheet (sheet2).
use paste special so that formatting is retained
try parsing sheet2 for unused rows
If this doesnt help try repeating step 2 with formatting info being cleared and then parsing sheet2. you can always copy format info later (if they are simple enough)
If you can first load the Excel file into a DataSet via the OleDBAdapter, it's relatively easy to remove blank rows on the import...
Try this OleDBAdapter Excel QA I posted via stack overflow.
Then export the DataSet to a new Excel file and convert that file to PDF. That may be a big "IF" though of course depending on the excel layout (or lack there of).
I had to solve this problem today for what might be a subset of your possible cases.
If your spreadsheet meets the following conditions:
All columns with data have header text in line 1.
All rows with data are in sequence until the first BLANK row.
Then, the following code may help:
private static string[,] LoadCellData(Excel.Application excel, dynamic sheet)
{
int countCols = CountColsToFirstBlank(excel, sheet);
int countRows = CountRowsToFirstBlank(excel, sheet);
cellData = new string[countCols, countRows];
string datum;
for (int i = 0; i < countCols; i++)
{
for (int j = 0; j < countRows; j++)
{
try
{
if (null != sheet.Cells[i + 1, j + 1].Value)
{
datum = excel.Cells[i + 1, j + 1].Value.ToString();
cellData[i, j] = datum;
}
}
catch (Exception ex)
{
lastException = ex;
//Console.WriteLine(String.Format("LoadCellData [{1}, {2}] reported an error: [{0}]", ex.Message, i, j));
}
}
}
return cellData;
}
private static int CountRowsToFirstBlank(Excel.Application excel, dynamic sheet)
{
int count = 0;
for (int j = 0; j < sheet.UsedRange.Rows.Count; j++)
{
if (IsBlankRow(excel, sheet, j + 1))
break;
count++;
}
return count;
}
private static int CountColsToFirstBlank(Excel.Application excel, dynamic sheet)
{
int count = 0;
for (int i = 0; i < sheet.UsedRange.Columns.Count; i++)
{
if (IsBlankCol(excel, sheet, i + 1))
break;
count++;
}
return count;
}
private static bool IsBlankCol(Excel.Application excel, dynamic sheet, int col)
{
for (int i = 0; i < sheet.UsedRange.Rows.Count; i++)
{
if (null != sheet.Cells[i + 1, col].Value)
{
return false;
}
}
return true;
}
private static bool IsBlankRow(Excel.Application excel, dynamic sheet, int row)
{
for (int i = 0; i < sheet.UsedRange.Columns.Count; i++)
{
if (null != sheet.Cells[i + 1, row].Value)
{
return false;
}
}
return true;
}
Can you try with below code :
for (int rowIndex = workSheet.Dimension.Start.Row; rowIndex <= workSheet.Dimension.End.Row; rowIndex++)
{
//Assume the first row is the header. Then use the column match ups by name to determine the index.
//This will allow you to have the order of the header.Keys change without any affect.
var row = workSheet.Cells[string.Format("{0}:{0}", rowIndex)];
// check if the row and column cells are empty
bool allEmpty = row.All(c => string.IsNullOrWhiteSpace(c.Text));
if (allEmpty)
continue; // skip this row
else{
//here read header
if()
{
//some code
}
else
{
//some code to read body
}
}
}
Hope this help,else let me know if you need description about code.
Updated :
below code is used to check how many rows are in the worksheet. a for loop will traverse untill end of row of the worksheet.
for (int rowIndex = workSheet.Dimension.Start.Row; rowIndex <= workSheet.Dimension.End.Row; rowIndex++)
here we are checking if the row and column cells are empty using linq:
bool allEmpty = row.All(c => string.IsNullOrWhiteSpace(c.Text));
if (allEmpty)
continue; // if true then skip this row
else
// read headers(assuming it is presented in worksheet)
// else read row wise data
and then do necessary steps.
hoping this clears now.
I had the same problem and managed to fix it using the CurrentRegion:
var lastcell = sheet.Cells.SpecialCells(XlCellType.xlCellTypeLastCell);
var filledcells = sheet.Cells.Range[sheet.Cells.Item[1, 1],
sheet.Cells[lastcell.Row - 1, lastcell.Column]]
.CurrentRegion;
filledcells.ExportAsFixedFormat(
and so on. The CurrentRegion is said to expand to the borders where cells are empty, and apparently that means it also shrinks if it contains many empty cells.
Please try the following code:
for (int i = 0; i < worksheets.Count; i++)
{
sheet = worksheets[i + 1];
sheet.Columns("A:A").SpecialCells(XlCellType.xlCellTypeBlanks).EntireRow.Delete
sheet.Rows("1:1").SpecialCells(XlCellType.xlCellTypeBlanks).EntireColumn.Delete
Marshal.FinalReleaseComObject(sheet);
}