I have excel files with table. I know how to get data with C# if table position(col and row of first cell) is fixed but problem is that before that table could be some heder with random content and size. I need somehow skip header and find position of table. What could be best solution for that task.
A table is a ListObject, You can find out where it is by going through the ListObjects. You can then access the DataBodyRange to get the address of the table contents.
in C#
public void GetTableAddress(Microsoft.Office.Interop.Excel.Workbook wb)
{
foreach (Microsoft.Office.Interop.Excel.Worksheet ws in wb.Worksheets)
{
foreach (Microsoft.Office.Interop.Excel.ListObject lObj in ws.ListObjects)
{
MessageBox.Show(lObj.DataBodyRange.Address);
}
}
}
Related
How is it possible to remove all rows from the HTML table using anglesharp?
I am trying to remove all rows in table. I've read this documentation, however, rows are not removed.
My code looks like this:
public void DeleteRows(IElement table)
{
foreach (var row in table?.QuerySelectorAll("tr"))
{
row.Remove();
}
var lengthAfterDeletion = table?.QuerySelectorAll("tr")?.Length;
}
How is it possible to remove all rows from the HTML table using anglesharp?
I think we figured it out in the meantime (see https://github.com/AngleSharp/AngleSharp/issues/838).
Just for future reference (in case somebody else runs into the same problem, which happens quite easily):
public void DeleteRows(IElement table)
{
var rows = table?.QuerySelectorAll("tr").ToArray();
foreach (var row in rows)
{
row.Remove();
}
var legnthAfterDeletion = table?.QuerySelectorAll("tr")?.Length;
}
The key is to get a static snapshot of the result before changing the DOM. Hence the .ToArray() which comes from LINQ and can be applied to any iterator.
I'm working on an Excel file that I have to convert to an XML file.
Every time I cycle the rows to check if they are empty I use this code:
var ComuniRow = firstRowUsed.RowUsed();
while (!ComuniRow.Cell(coComuneId).IsEmpty())
{
// do stuff;
}
This time tho I need to select a specific row, not the starting one but I have no Idea about how to do that.
Any solutions?
Thanks :)
You can group the rows.
public void UngroupFromAll(){
IXLWorksheet ws = new XLWorkbook().AddWorksheet("Sheet1");
ws.Rows(1, 2).Group();
ws.Rows(1, 2).Ungroup(true);
}
I'm using the OpenXML SDK to update the contents of an Excel spreadsheet. When inserting cells into an Excel row they must be inserted in the correct order or the file will not open properly in Excel. I'm using the following code to find the first cell that will be after the cell I am inserting. This code comes almost directly from the OpenXML SDK documentation
public static Cell GetFirstFollowingCell(Row row, string newCellReference)
{
Cell refCell = null;
foreach (Cell cell in row.Elements<Cell>())
{
if (string.Compare(cell.CellReference.Value, newCellReference, true) > 0)
{
refCell = cell;
break;
}
}
return refCell;
}
When I edit files with this code and then open them in Excel, Excel reports that the file is corrupted. Excel is able to repair the file, but most of the data is removed from the workbook. Why does this result in file corruption?
Side note: I tried two different .NET Excel libraries before turning to the painfully low-level OpenXML SDK. NPOI created spreadsheets with corruption and EPPlus threw an exception whenever I tried to save. I was using the most recent version of each.
The code you are using is seriously flawed. This is very unfortunate, seeing as it comes from the documentation. It may work acceptably for spreadsheets that only use the first 26 columns but will fail miserably when confronted with "wider" spreadsheets. The first 26 columns are named alphabetically, A-Z. Columns 27-52 are named AA-AZ. Column 53-78 are named BA-BZ. (You should notice the pattern.)
Cell "AA1" should come after all cells with a single character column name (i.e. "A1" - "Z1"). Let's examine the current code comparing cell "AA1" with cell "B1".
string.Compare("B1", "AA1", true) returns the value 1
The code interprets this to mean that "AA1" should be placed before cell "B1".
The calling code will insert "AA1" before "B1" in the XML.
At this point the cells will be out of order and the Excel file is corrupted. Clearly, string.Compare by itself is not a sufficient test to determine the proper order of cells in a row. A more sophisticated comparison is required.
public static bool IsNewCellAfterCurrentCell(string currentCellReference, string newCellReference)
{
var columnNameRegex = new Regex("[A-Za-z]+");
var currentCellColumn = columnNameRegex.Match(currentCellReference).Value;
var newCellColumn = columnNameRegex.Match(newCellReference).Value;
var currentCellColumnLength = currentCellColumn.Length;
var newCellColumnLength = newCellColumn.Length;
if (currentCellColumnLength == newCellColumnLength)
{
var comparisonValue = string.Compare(currentCellColumn, newCellColumn, StringComparison.OrdinalIgnoreCase);
return comparisonValue > 0;
}
return currentCellColumnLength < newCellColumnLength;
}
If you wanted to place a new cell in column "BC" and you were comparing to cell "D5" you would use IsCellAfterColumn("D5", "BC5"). Substituting the new comparison function into the original code and simplifying with LINQ:
public static Cell GetFirstFollowingCell(Row row, string newCellReference)
{
var rowCells = row.Elements<Cell>();
return rowCells.FirstOrDefault(c => IsNewCellAfterCurrentCell(c.CellReference.Value, newCellReference));
}
I'm currently trying to add data programatically onto a DataGridView, but it doesn't seem to be working.
What I have is an Array, which I fill from a text file:
public static string PathList = #"C:\Users\gbbb\Desktop\Pfade.txt";
_PathRows = System.IO.File.ReadAllLines(#PathList);
and I have a DataGridView with 4 Columns on which I add as many Rows as I have paths, so:
public void InitPathsTable()
{
TabelleBib.Rows.Add(_PathRows.Length);
//And here is where i want to add the Paths on Column Nr.4
}
Next what I need is a way to add all paths that I get (24) into the Column Nr.4,
one Path per Row.
But it seems to be nearly impossible for a beginner like me, so I am asking you.
This is method that will do that for you. Read comments (especially make sure you have added 4 columns to you DataGridView):
public void InitPathsTable()
{
int rowindex;
DataGridViewRow row;
foreach (var line in _PathRows)
{
rowindex = TabelleBib.Rows.Add(); //retrieve row index of newly added row
row = TabelleBib.Rows[rowindex]; //reference to new row
row.Cells[3].Value = line; //set value of 4th column to line. WARNING: TabelleBib has to have 4 columns added either from code or designer othwerwise here you will get exception
}
}
if you get any more problems, write a comment and I will come back to you :)
I'm using Excel Interop assemblies for my project,
if I want to use auto filter with then thats possible using
sheet.UsedRange.AutoFilter(1,SheetNames[1],Microsoft.Office.Interop.Excel.XlAutoFilterOperator.xlAnd,oMissing,false)
but how can I get the filtered rows ??
can anyone have idea??
Once you filtered the range, you can access the cells that pass the filter criteria by making use of the Range.SpecialCells method, passing in a valued of 'Excel.XlCellType.xlCellTypeVisible' in order to get the visible cells.
Based on your example code, above, accessing the visible cells should look something like this:
Excel.Range visibleCells = sheet.UsedRange.SpecialCells(
Excel.XlCellType.xlCellTypeVisible,
Type.Missing)
From there you can either access each cell in the visible range, via the 'Range.Cells' collection, or access each row, by first accessing the areas via the 'Range.Areas' collection and then iterating each row within the 'Rows' collection for each area. For example:
foreach (Excel.Range area in visibleCells.Areas)
{
foreach (Excel.Range row in area.Rows)
{
// Process each un-filtered, visible row here.
}
}
Hope this helps!
Mike
I used as mentioned below, similar to what Mike told,
foreach (Excel.Range area in visibleCells.Areas)
{
foreach(Excel.Range row in area.Rows)
{
int index = row.Row; // now index is the present Row index within the range
string test = Mysheet.Cells[index,4].Values //// Mysheet is my present working sheet. After this test will contain the values pointing to the values.cells[index,4]
}
}