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);
}
Related
Is there a way to only select Sheet Lists in a Schedule?
Like in this picture, but instead of those fields, I want only the existent Sheet Lists in the project.
Creating a Sheet List, but I want all the Sheet Lists in the fields.
I actually found code that helped me out with this:
public IEnumerable<ViewSheet> GetAllSheets (Document doc)
{
IEnumerable<ViewSheet> sheets = new FilteredElementCollector(doc)
.OfClass(typeof(ViewSheet))
.OfCategory(BuiltInCategory.OST_Sheets)
.Cast<ViewSheet>()
;
return sheets;
}
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);
}
}
}
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 am creating a ListObject in Excel using VSTO as follows:
ListObject lo = ws_vsto.Controls.AddListObject(range, "MyList");
(The range variable is a previously defined range.)
If I then loop through the worksheet Controls collection I can find that ListObject.
However, if I save the workbook and reopen it, the Controls collection is empty. How can I get this ListObject back after re-opening so that I can continue working with it?
EDIT
I've got a bit further:
var wb = Globals.ThisAddIn.Application.ActiveWorkbook;
var wb_vsto = wb.GetVstoObject();
foreach (Excel.Worksheet ws in wb.Worksheets)
{
var wsv = ws.GetVstoObject();
foreach (Excel.ListObject l in ws.ListObjects)
{
MessageBox.Show(l.Name);
var lo = wsv.Controls.AddListObject(l);
Excel.Range range = lo.Range;
range.Activate();
}
}
When I get to the var lo = line, I have a ListObject added to the Controls collection and available for use. However, it's DataSource property holds null. Is there an easy way to get the original data source back?
I then thought about rebuilding the data source from the information in the range. The range.Activate() line selects the list in Excel (so I know it has the right thing). However, I can't for the life of me work out how to get the data out of that range and get the address of the range. The MSDN documentation talks about the Address property but this doesn't appear to actually exist. (MSDN documentation for VSTO seems ropey at best).
I made the following changes to the initial code. You need to get a VSTO Listobject back from the Factory.
var wb = Globals.ThisAddIn.Application.ActiveWorkbook;
var wb_vsto = wb.GetVstoObject();
foreach (Excel.Worksheet ws in wb.Worksheets)
{
var wsv = ws.GetVstoObject();
foreach (Excel.ListObject l in ws.ListObjects)
{
MessageBox.Show(l.Name);
//var lo = wsv.Controls.AddListObject(l);
Microsoft.Office.Tools.Excel.ListObject lo =
Globals.Factory.GetVstoObject(l);
// I can now get at the datasource if neede
var ds = lo.DataSource;
// In my case the datasource was DataTable.
DataTable t = (DataTable)d;
if (t.Rows.Count > 0)
{
foreach (DataRow r in t.Rows)
{
// Access row data.
}
}
//Excel.Range range = lo.Range;
//range.Activate();
}
}
Have you tried?
Microsoft.Office.Tools.Excel.ListObject lo= Microsoft.Office.Tools.Excel.ListObject.GetVstoObject(l) (it's C# I'm not sure in VB)
From MSDN GetVstoObject, be sure to read the remarks.
About your first question,
you created the listOject with the code
ListObject lo = ws_vsto.Controls.AddListObject(range, "MyList");
To recover the object after save/reope the workbook, try this line of code:
ListObject lo = Globals.Factory.GetVstoObject(Worksheet.ListObjects["MyList"]);
You simply can't get back a ListObject control that you created dynmically during run-time. this is from the MSDN documentation.
By default, dynamically created list objects are not persisted in the
worksheet as host controls when the worksheet is closed.
The only way I can get back my ListObject is to create them directly in the sheets of my template during design-time.