In C# I have a DataTable which has valid values, some of which are in exponential format. I export this DataTable to an xlsx file using ExtremeML (which I believe is based on OpenXML) and the following code:
if (!Directory.Exists(savePath.Text))
Directory.CreateDirectory(savePath.Text);
using (var package = SpreadsheetDocumentWrapper.Create(savePath.Text + fileName + ".xlsx"))
{
for (int i = 0; i < dataset.Tables.Count; i++)
{
// declares worksheet
var part = package.WorkbookPart.WorksheetParts.Add(dataset.Tables[i].TableName.ToString()); // second worksheet filled by second collection
bool first = true;
int position = 0;
for (int row = 0; row < dataset.Tables[i].Rows.Count; row++)
{
for (int col = 0; col < dataset.Tables[i].Columns.Count; col++)
{
// adds to file
if (first)
part.Worksheet.SetCellValue(new GridReference(row, col), dataset.Tables[i].Columns[col].ColumnName.ToString());
else
part.Worksheet.SetCellValue(new GridReference(row, col), dataset.Tables[i].Rows[position][col]);
}
if (first)
{
first = false;
}
else
position++;
}
}
}
The resulting excel file is almost acceptable, except that negative exponential negative numbers
(for example -7.45E-05) treat the negative sign as a digit (previous example becomes 0.000-745). The columns are all set to be doubles in the DataTable, so the excel file should be formatting them as such.
Any ideas as to the cause of this problem?
(Also, I know the code is a touch painful to grok- the code is not mine, and I haven't gotten around to cleaning up the program.)
Your sample code seems fine.
This looks like a bug in the way way ExtremeML converts doubles. As you say, it only appears to affect negative exponential negative numbers.
I am currently debugging it and creating additional unit tests to cover these scenarios, after which I will commit the updated code to CodePlex and post an update here.
Edit: This bug has now been fixed. You'll need to download and build the ExtremeML source code from CodePlex, as the runtime release is not currently up-to-date.
Related
What is the way to copy all cell comments (on right click - Insert Comments) in a specified range?
Range r1 = (Range)ws1.get_Range("A1", "C10");
Range r2 = (Range)ws2.get_Range("A1", "C10");
r2.Value = r1.Value; // copies cell values and ignores comments
I know that r1.Copy(r2); would copy values and comments, but it shows unnecessary Excel dialogs due to validation issues and therefore I cannot use it.
There's a AddComment method for Range. Unfortunately, it cannot be applied to a range of cells. I guess they assumed: why would you want the same comment written multiple times? So you'll have to loop:
for (int r = 1; r <= r1.Rows.Count; r++)
{
for (int c = 1; c <= r1.Columns.Count; c++)
{
r2[r, c].AddComment(r1.Comment);
}
}
Hello sorry for my english.
I have to select a row of a excel file, put any new data and save them.
In the end I see that the excel file is always larger than before although the data are not increased but it looks to be created of the blank columns to the right.
I think this because when I execute the following statement
var wb = openWorkBook(filename);
var ws = wb.Worksheet("CNF");
IXLRow row = ws.Row(device.Ordinal - 1 + FirstRow);
for (int j = 0; j < MAXCOLS; ++j)
{
IXLCell cell = row.Cell(j + FirstCol);
...}
as range goes from A1 to XFD1048576.
Although after I take the line of my interest and cycle of 100 columns when I go
wb.Save();
the file increases.
So I ask you if you have a method to take only a part of a file then for example take already suffered from a limited number of columns, starting from education var ws = wb.Worksheet("CNF");.
Thank you
I am trying to truncate the cells in a column to a fixed number of characters using the DevExpress SpreadsheetControl. I have it working by just iterating through each cell and manually truncating it using the code below:
for (int i = 0; i <= rowCount; ++i)
{
worksheet.Columns[0][i].Value = worksheet.Columns[0][i].Value.ToString().Substring(0, 15);
}
But this is extremely slow. I was wondering if there is a way in the control to tell it to truncate the cells automatically?
EDIT
I found where I can export the sheet to a datatable and do the substring on it. This is much faster:
var dataTable = worksheet.CreateDataTable(worksheet.GetUsedRange(), true);
var exporter = worksheet.CreateDataTableExporter(worksheet.GetUsedRange(), dataTable, true);
exporter.Export();
for (int i = 0; i < dataTable.Rows.Count; ++i)
{
dataTable.Rows[i][0] = dataTable.Rows[i][0].ToString().Substring(0, 15);
}
worksheet.Import(dataTable, true, 0, 0);
I would still like to see if there is a better way built into the control or someplace else in the API.
Your code is extremely slow because SpreadsheetControl is trying to update its content with any change in any cell. So, you just need to lock updates before running your code and unlock its after. For lock/unlock updates you can use SpreadsheetControl.BeginUpdate and SpreadsheetControl.EndUpdate methods.
Here is example:
spreadsheetControl1.BeginUpdate();
var cells = spreadsheetControl1.ActiveWorksheet.GetUsedRange();
foreach (var cell in cells)
cell.Value = cell.Value.ToString().Substring(0, 15);
spreadsheetControl1.EndUpdate();
I know how to write single cell into excel but when im trying it on array excel sheet is filling with only last value
this is my range
Excel.Range ServiceName = (Excel.Range)_sheet.get_Range(_sheet.Cells[38, "B"] as Excel.Range, _sheet.Cells[45, "B"] as Excel.Range);
_ServiceName is List which contains 1,2,3,4,5,6
for (int i = 0; i < _ServiceName.Count; i++)
{
ServiceNameArray[0, i] = _ServiceName[i];
}
this i my trying to write into excel but as i said it there is only last item (6) in excel book
for (int i = 0; i < _ServiceName.Count; i++)
{
ServiceName.set_Value(Type.Missing, ServiceNameArray[0,i]);
}
does anyone have an idea?
Davide Piras is right. And you're doing a few other strange things there, I can elaborate by request.
For now I just want to point out that you can directly assign the .Value property of a Range to an array:
ServiceName.Value2 = _ServiceName.toArray();
This is much, much faster for bigger amounts of data.
(Side note: If you want to do the same with Formulas, for some strange reason you have to take an extra step (doubling the time):
range.Formula = array;
range.Formula = range.Formula;
unless there is a better way I don't know about yet.)
I see you looping on the ServiceName array to get all values one after the other but not see you changing the focused cell inside the cellrange at every loop iteration. Of course, I would say, you see only the last value, because you are writing all values one over the other always in the same place.
I wanted to ask if there is some practical way of adding multiple hyperlinks in excel worksheet with C# ..? I want to generate a list of websites and anchor hyperlinks to them, so the user could click such hyperlink and get to that website.
So far I have come with simple nested for statement, which loops through every cell in a given excel range and adds hyperlink to that cell:
for (int i = 0; i < _range.Rows.Count; i++)
{
Microsoft.Office.Interop.Excel.Range row = _range.Rows[i];
for (int j = 0; j < row.Cells.Count; j++)
{
Microsoft.Office.Interop.Excel.Range cell = row.Cells[j];
cell.Hyperlinks.Add(cell, adresses[i, j], _optionalValue, _optionalValue, _optionalValue);
}
}
The code is working as intended, but it is Extremely slow due to thousands of calls of the Hyperlinks.Add method.
One thing that intrigues me is that the method set_Value from Office.Interop.Excel can add thousands of strings with one simple call, but there is no similar method for adding hyperlinks (Hyperlinks.Add can add just one hyperlink).
So my question is, is there some way to optimize adding hyperlinks to excel file in C# when you need to add a large number of hyperlinks...?
Any help would be apreciated.
I am using VS2010 and MS Excel 2010.
I have the very same problems (adding 300 hyperlinks via Range.Hyperlinks.Add takes approx. 2 min).
The runtime issue is because of the many Range-Instances.
Solution:
Use a single range instance and add Hyperlinks with the "=HYPERLINK(target, [friendlyName])" Excel-Formula.
Example:
List<string> urlsList = new List<string>();
urlsList.Add("http://www.gin.de");
// ^^ n times ...
// create shaped array with content
object[,] content = new object [urlsList.Count, 1];
foreach(string url in urlsList)
{
content[i, 1] = string.Format("=HYPERLINK(\"{0}\")", url);
}
// get Range
string rangeDescription = string.Format("A1:A{0}", urlsList.Count+1) // excel indexes start by 1
Xl.Range xlRange = worksheet.Range[rangeDescription, XlTools.missing];
// set value finally
xlRange.Value2 = content;
... takes just 1 sec ...