I was trying to insert a new row at the end of a worksheet using OLEDB. The worksheet has a format table in a Range (a1:xx), with format and formula stored. But OLEDB insert does not come with any format.
I have read the post How to copy format of one row to another row in Excel with c# talking about get the format, but doesn't work for me. Also, I don't think it will get the formula.
In the Excel UI, at the lower right corner of a formatted table, a double arrow would appear, and we can drag it to expand the format table range.
Anything we could do through C#?
Thanks.
Excel.Range last = xlWS.Cells.SpecialCells(Excel.XlCellType.xlCellTypeLastCell, Type.Missing);
Excel.Range RngToCopyOri = xlWS.get_Range("A1", last).EntireRow;
Excel.Range RngToCopy = RngToCopyOri.Resize[RngToCopyOri.Rows.Count + 1, RngToCopyOri.Columns.Count]; //because insert will add only 1 row, so the range would be one row larger
Excel.Range RngToInsert = xlWS.get_Range("A1", Type.Missing).EntireRow;
RngToInsert.Insert(Excel.XlInsertShiftDirection.xlShiftDown, RngToCopy.Copy(Type.Missing));
I tried to copy Range(A1,lowerleft cell) to its original location, but nothing changed.
I tried Range.resize, autofill, autoformat. All of them has sort of problems. I finally gave up using OLEDB to insert data. Instead, i used
worksheet.UsedRange.Item[rowNo,getColumnIndex(worksheet,columnTitle)]=value
private int getColumnIndex(Excel.Worksheet sheetname, string header) {
int index=0;
Excel.Range activeRange=sheetname.UsedRange;
for (int i = 1; i <= activeRange.Columns.Count; i++) {
if (header == (string)(activeRange.Item[1,i] as Excel.Range).Value) {
index = i;
}
}
if(index==0)
throw some exception you like;
return index;
}
The getColumnIndex function aims to locate the column in SELECT [column] from...
In this way, the format table will automatically expand to the range you input the value.
Related
I have an Excel worksheet which has 50 Rows and 38 columns "Filled" with actual data but when I try to get the .UsedRange I am getting More than 1025 Rows and 250 columns as Used range! Please let me know how can I get only actual Used ranges with filled data and retrive the actual range data using Spreadsheetgear lib? I tried something like, but when user added some column, it's does not work.
var workbook = Factory.GetWorkbook(filePath);
var worksheet = workbook.Worksheets[0];
var cells = worksheet.UsedRange;
var headerCount = 0;
// get columns size
for (var columnCount = 0; columnCount <= range.ColumnCount; ++columnCount)
{
if (columnCount > headers.Length && string.IsNullOrEmpty(range[HeaderRow, columnCount].Text))
{
headerCount = columnCount - 1;
break;
}
}
SpreadsheetGear (and Excel itself) will include cells into the UsedRange that are empty but have formatting of some kind. For instance, if cell ABC123 has a custom NumberFormat, Font color or similar, the UsedRange will include that cell, thereby potentially blowing up your UsedRange A1:ABC123 even if the actual "value-populated" or "filled" portion of the worksheet is much smaller.
If this is a problem and you need to only include the portion of a sheet that is actually populated with cell values, below is one possible routine you might be able to use to only include cells that have cell values of some kind. It is written as an extension method off of IWorksheet to make utilization of it easier, and includes a bool flag that you can pass in so as to return either the "normal" UsedRange (including cells with other types of formatting) or the "altered" UsedRange discussed here:
public static class SGExtensionMethods
{
public static IRange GetUsedRange(this IWorksheet worksheet, bool ignoreEmptyCells)
{
IRange usedRange = worksheet.UsedRange;
if (!ignoreEmptyCells)
return usedRange;
// Find last row in used range with a cell containing data.
IRange foundCell = usedRange.Find("*", usedRange[0, 0], FindLookIn.Formulas,
LookAt.Part, SearchOrder.ByRows, SearchDirection.Previous, false);
int lastRow = foundCell?.Row ?? 0;
// Find last column in used range with a cell containing data.
foundCell = usedRange.Find("*", usedRange[0, 0], FindLookIn.Formulas,
LookAt.Part, SearchOrder.ByColumns, SearchDirection.Previous, false);
int lastCol = foundCell?.Column ?? 0;
// Return a new used range that clips of any empty rows/cols.
return worksheet.Cells[worksheet.UsedRange.Row, worksheet.UsedRange.Column, lastRow, lastCol];
}
}
A couple additional notes about this approach. It does generally take into account hidden rows or columns--meaning hidden rows or columns that have cell values will be included in the UsedRange. One exception / edge-case to this inclusion of hidden rows or columns is if AutoFilters is enabled on the worksheet. This puts the worksheet in a special "mode" that excludes hidden rows from search results. So if AutoFilters is enabled (in such cases IWorksheet.AutoFilterMode will be true), you may not be able to rely on this approach if the last row(s) or column(s) of the AutoFiltered range could possibly have been filtered out.
I have c# windows application that is reading files content. I wanted to extract values from used rows only.
I am using this code:
int rows = ExcelWorksheet.UsedRange.Rows.Count;
Everything works fine. Except when I have empty rows on top, the counting will be incorrect.
-File has no special characters, formula or such. Just plain text on it.
-The application can read excel xls and xlsx with no issue if the file has no empty rows on top.
Okay, now I've realized I'm doing it all wrong. Of course it will not read all of my UsedRange.Rows because in my for loop, I am starting the reading always on the first row. So I get the ((Microsoft.Office.Interop.Excel.Range)(ExcelWorksheet.UsedRange)).Row; as a starting point of reading
This code works:
int rows = ExcelWorksheet.UsedRange.Rows.Count;
int fRowIndex = ((Microsoft.Office.Interop.Excel.Range)(ExcelWorksheet.UsedRange)).Row;
int rowCycle = 1;
for (int rowcounter = fRowIndex; rowCycle <= rows; rowcounter++)
{
//code for reading
}
Instead of read Excel row-by-row, better to get it in C# as a Range, and then handle it as
Sheet.UsedRange.get_Value()
for whole UsedRange in Sheet. Whenever you'd like to get a part of UsedRange, do it as
Excel.Range cell1 = Sheet.Cells[r0, c0];
Excel.Range cell2 = Sheet.Cells[r1, c1];
Excel.Range rng = Sheet.Range[cell1, cell2];
var v = rng.get_Value();
You well know size of v in C# memory from the values of [r1-r0, c1-c0]
I want to delete every row that comes after my specific keyword and including the keyword row as well. Can anybody please help me with C# code.
Example :- I have not attached a dummy excel file as I am posting it from mobile.
I have a word in excel :- "hello user" so I have to delete all the lines of data after this including it as well. And most important this data is not on the fixed line it can be on any line number....Suppose for now I have given it on 10th line so it may come on 12th line in next file.
Line no. Data
10. "hello user"
11. A
12. B
And so on
.
.
.
.
.
I think this code should work for you:
const string magicWord = "HelloUser";
Excel.Application app = new Excel.Application();
Excel.Workbook workbook = app.Workbooks.Open(#"myWorkbook.xlsx");
Excel.Worksheet worksheet = workbook.Sheets[1]; //Excel has no zero based index!!!
int magicWordRowIndex = Int32.MaxValue;
//Here we find your magic word. But we can't delete the rows here, so just save the index
for (int row = 1; row <= worksheet.Rows.Count; row++)
{
for (int column = 1; column <= worksheet.Columns.Count; column++)
{
if (worksheet.Rows[row][column] == magicWord)
{
magicWordRowIndex = row;
break;
}
}
}
//Now we run reversed, because else our magicWordRowIndex become invalid if we delete rows
for (int row = worksheet.Rows.Count; row >= magicWordRowIndex; row--)
{
((Excel.Range) worksheet.Rows[row, Missing.Value]).Delete(Excel.XlDeleteShiftDirection.xlShiftUp);
}
Actualy I'm not able to test it but should do the job, maybe you need minor changes and fit it to your needs.
First it finds your magicword which is hardcoded on the beginning. After finding this word we go delete all rows from bottom up to your existing word.
Notice that you need to reference: Microsoft.Office.Interop.Excel
I have a Word.Chart whose underlying worksheet I am populating with data from C#.
My problem is however, that the selected dataset in the worksheet contains just the default selection (eg. 5x4 cells or sg like that), and not ALL the data which I entered.
If the object were an Excel chart, I could do
Excel.Range rangeBegin = ws.Cells[1, 1];
Excel.Range rangeEnd = ws.Cells[xAxisContents.Count + 1, feeds.Count + 1];
Excel.Range chartRange = ws.get_Range(rangeBegin, rangeEnd);
wordChart.SetSourceData(chartRange);
However, the Word.Chart's SetSourceData method only accepts a string, and if I call it with an arbitrary range (just for testing), eg. wordChart.SetSourceData("A1:C3"), it fails with a ComException(E_FAIL).
I have also found this code on a Microsoft blog:
Excel.Range tblRng = dataSheet.get_Range("A1", "B5");
Excel.ListObject tbl = dataSheet.ListObjects["Table1"];
tbl.Resize(tblRng);
which I think is meant to resize the selected dataset to the size of the worksheet. This would also be perfect for me, however, "Table1" is reported as an unknown index (maybe because I am using a non-English version of Word.)
What should I do to select the appropriate dataset?
I am using Com Interop and C#. I have to iterate through an Excel file looking for certain values in each of the rows (always in column 2). For some values I need to set the background colour of the row to red.
I am having trouble:
Reading the value in cell [i][2] for row i, and
Setting the background colour of this row.
Basically I am looking for something like this (which is the best I can find after much Googling):
// ws is the worksheet
for (int i = 1; i <= ws.Rows.Count; i++)
{
Range range = ws.Cells[i][2];
int count = Convert.ToInt32(range.Value2.ToString());
if (count >= 3)
{
Range chronic = ws.UsedRange.Rows[i];
chronic.EntireRow.Cells.Interior.Color = 0xFF0000;
}
}
Of course this doesn't work. I can't get past the first hurdle of just reading the cell. Any advice is appreciated.
Try this. The code assumes that the value in the column 2 cell is a number.
using Excel = Microsoft.Office.Interop.Excel;
using System.Reflection;
Missing noValue = Missing.Value;
Excel.Range conditionalCell;
foreach (Excel.Range usedRange in ws.UsedRange.Rows)
{
conditionalCell = usedRange.Cells[noValue, 2] as Excel.Range;
if (Convert.ToInt32(conditionalCell.Value2) >= 3)
{
usedRange.Cells.Interior.Color = Excel.XlRgbColor.rgbRed;
}
}