Excel Range.FillDown using EPPlus - excel

How can I perform a FillDown operation on ExcelRange using EPPlus?
https://learn.microsoft.com/en-us/office/vba/api/excel.range.filldown

//create a new ExcelPackage
using (ExcelPackage excelPackage = new ExcelPackage())
{
//create 2 WorkSheets
ExcelWorksheet worksheet = excelPackage.Workbook.Worksheets.Add("Sheet 1");
ExcelWorksheet worksheet2 = excelPackage.Workbook.Worksheets.Add("Sheet 2");
//set the calculation mode to manual
excelPackage.Workbook.CalcMode = ExcelCalcMode.Manual;
//fill cell data with a loop, note that row and column indexes start at 1
for (int i = 1; i <= 25; i++)
{
for (int j = 1; j <= 10; j++)
{
worksheet.Cells[i, j].Value = (i + j) - 1;
worksheet2.Cells[i, j].Value = (i + j) - 1;
}
}
//set the total value of cells in range A1 - A25 into A27
worksheet.Cells["A27"].Formula = "=SUM(A1:A25)";
//set the number of cells with content in range C1 - C25 into C27
worksheet.Cells["C27"].Formula = "=COUNT(C1:C25)";
//fill column K with the sum of each row, range A - J
for (int i = 1; i <= 25; i++)
{
var cell = worksheet.Cells[i, 12];
cell.Formula = "=SUM(" + worksheet.Cells[i, 1].Address + ":" + worksheet.Cells[i, 10].Address + ")";
}
//calculate the quartile of range E1 - E25 into E27
worksheet.Cells[27, 5].Formula = "=QUARTILE(E1:E25,1)";
//set the total value of all cells in Sheet 2 into G27
worksheet.Cells["G27"].Formula = "=SUM('" + worksheet2.Name + "'!" + worksheet2.Dimension.Start.Address + ":" + worksheet2.Dimension.End.Address + ")";
//set the number of cells with content in Sheet 2, range C1 - C25 into I27
worksheet.Cells["I27"].Formula = "=COUNT('" + excelPackage.Workbook.Worksheets[2].Name + "'!" + excelPackage.Workbook.Worksheets[2].Cells["A1:B25"] + ")";
//calculate all the values of the formulas in the Excel file
excelPackage.Workbook.Calculate();
//Save the file
FileInfo fi = new FileInfo("FormulaExample.xlsx");
excelPackage.SaveAs(fi);
}

Related

Get row count of excel sheet in nodejs

I have an excel which has multiple sheet. Now I want to get row count for each sheet
var XLSX = require('xlsx');
var workbook = XLSX.readFile('test.xlsx');
var sheet_name_list = workbook.SheetNames;
let count = [];
for (var sheetIndex = 0; sheetIndex < sheet_name_list.length; sheetIndex++) {
var worksheet = workbook.Sheets[sheet_name_list[sheetIndex]];
var range = XLSX.utils.decode_range(worksheet['!ref']);
var num_rows = range.e.r - range.s.r + 1;
count.push({
data_count: num_rows
});
}
return count;
By using above script I am getting maximum 65536 even though excel has 100000 record.
try changing:
var range = XLSX.utils.decode_range(worksheet['!ref']);
to:
var range = XLSX.utils.decode_range(worksheet['!fullref']);

VBA Grid Generation with User Input

The aim of this code is to have the user input that they want an, e.g. 4x10 grid. I have attached a photo below of the desired output.
However, I'm stuck on the logic of the problem. I can generate one set of grid numbers (e.g. 1-25), but unsure how to duplicate this process to create the whole grid.
Hard to explain using words....
In short I am aiming for:
A1, A2, A3, A4, B1, B2, B3, B4 ...
But I am currently getting: A1, B2, C3, D4 ...
Tried experimenting with different code but to no success. Current code has a loop that I think is right in principle, but re-writes the data in the rows above it once it finishes one 'j' loop and goes back to the start. I'm not sure how to get 'j' to start on a blank cell rather than overwrite what is already in it.
['Userform prior to this step gathers user input
Dim Axial_Data_Points As Variant
Dim Circum_Data_Points As Variant
Axial_Data_Points = Axial_Data_Points_Box.Value 'User input value
Circum_Data_Points = Circum_Data_Points_Box.Value 'User input value
'Basic loop to generate a list of numbers up to the user imposed limit
For j = 1 To Axial_Data_Points
Worksheets("Data Entry").Activate
For k = 1 To Circum_Data_Points
Range("E" & ((j + k) + 1)).Select
ActiveCell.FormulaR1C1 = j
Next k
Next j]
1
This will produce output like:
Dim Axial_Data_Points As Variant
Dim Circum_Data_Points As Variant
Axial_Data_Points = Axial_Data_Points_Box.Value 'User input value
Circum_Data_Points = Circum_Data_Points_Box.Value 'User input value
'Basic loop to generate a list of numbers up to the user imposed limit
Dim i As Integer
Dim j As Integer
For i = 1 To Axial_Data_Points
For j = 1 To Circum_Data_Points
Worksheets("Data Entry").Cells(j + (i - 1) * 10, 4).Value = Chr(i + 64)
Worksheets("Data Entry").Cells(j + (i - 1) * 10, 5).Value = j
Next j
Next i
End Sub
Using Something of this type you can generate what you require:
j = 1
k = 1
For i = 1 To 200
If j < 27 Then
Range("A" & i).Value = Chr(j + 64)
j = j + 1
ElseIf j > 26 And j < 53 Then
G:
Range("A" & i).Value = Chr(k + 64) & Chr(j - 26 + 64)
j = j + 1
Else
j = 27
k = k + 1
GoTo G
End If
Next
You will have to put it in your code.

OpenXML: excel found unreadable content in .xsls

I'm using OpenXML in my ASP.NET application. Here is the code for generating it:
MemoryStream ms = new System.IO.MemoryStream();
SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Create(ms, SpreadsheetDocumentType.Workbook);
WorkbookPart workbookPart = spreadsheetDocument.AddWorkbookPart();
workbookPart.Workbook = new Workbook();
WorksheetPart worksheetPart = workbookPart.AddNewPart<WorksheetPart>();
worksheetPart.Worksheet = new Worksheet();
UInt32Value rowIndex = 0;
SheetData sheetData = new SheetData();
Row r1 = new Row() { RowIndex = rowIndex };
Cell c1 = new Cell() { DataType = CellValues.String, CellValue=new CellValue("col1") };
Cell c2 = new Cell() { DataType = CellValues.String, CellValue = new CellValue("col2") };
Cell c3 = new Cell() { DataType = CellValues.String, CellValue = new CellValue("col3") };
Cell c4 = new Cell() { DataType = CellValues.String, CellValue = new CellValue("col4") };
r1.Append(new List<Cell>() { c1, c2, c3, c4 });
rowIndex++;
sheetData.Append(r1);
foreach (Rezultat rez in rezultati)
{
Row r2 = new Row() { RowIndex = rowIndex };
Cell c1 = new Cell() { DataType = CellValues.String, CellValue = new CellValue(rez.a) };
Cell c2 = new Cell() { DataType = CellValues.String, CellValue = new CellValue(rez.b) };
Cell c3 = new Cell() { DataType = CellValues.String, CellValue = new CellValue(rez.c) };
Cell prolaz = new Cell() { DataType = CellValues.String };
if (rez.d)
{
prolaz.CellValue = new CellValue("DA");
}
else
{
prolaz.CellValue = new CellValue("NE");
}
r2.Append(new List<Cell>() { c1,c2,c3,c4 });
rowIndex++;
sheetData.Append(r2);
}
worksheetPart.Worksheet.Append(sheetData);
Sheets sheets = new Sheets();
Sheet sheet = new Sheet();
sheet.Name = "first";
sheet.SheetId = 1;
sheet.Id = spreadsheetDocument.WorkbookPart.GetIdOfPart(worksheetPart);
sheets.Append(sheet);
spreadsheetDocument.WorkbookPart.Workbook.AppendChild<Sheets>(sheets);
spreadsheetDocument.WorkbookPart.Workbook.Save();
spreadsheetDocument.Close();
string fileName = "testOpenXml.xlsx";
Response.Clear();
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("content-disposition", string.Format("attachment; filename={0}", fileName));
ms.WriteTo(Response.OutputStream);
ms.Close();
Response.End();
When I download it, and try to open it in excel, I got message that excel found unreadable context in excel.I suppose I have to change the way how I geenrate excel. I tried couple of solutions, some gave same error and some open excel, but with no data in it.
You will get this error if the cells do not appear in order in the file.
If you are using Microsoft's Sample Code in "How to: Insert text into a cell in a spreadsheet document (Open XML SDK)" in DevCenter you will see there is a function called InsertCellInWorksheet. This function has the defective line in it:
if (string.Compare(cell.CellReference.Value, cellReference, true) > 0)
If you have more than 26 columns, this will cause them to be sorted like this:
A1 AA1 AB1 B1 C1 D1 E1 ....
The result is you will see the data in column A and from AA on. Columns B through Z will be missing and you will get the dreaded "Excel found unreadable content" message.
You need to replace this string.Compare with a function that will put AA1 after Z1, or... if you know you are creating everything in order change it to if (false).
What you want to create are cells of type InlineString instead of String.
Below is a snippet to achieve part of what you need. Hopefully, you can modify it to your needs.
SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Create(#"test.xlsx", SpreadsheetDocumentType.Workbook);
WorkbookPart workbookPart = spreadsheetDocument.AddWorkbookPart();
WorksheetPart worksheetPart = workbookPart.AddNewPart<WorksheetPart>();
Row row = new Row { RowIndex = 1 };
Cell cell1 = new Cell { DataType = CellValues.InlineString };
InlineString inlineString1 = new InlineString();
Text text = new Text { Text = "col1" };
inlineString1.Append(text);
cell1.Append(inlineString1);
Cell cell2 = new Cell { DataType = CellValues.InlineString };
InlineString inlineString2 = new InlineString();
Text text2 = new Text { Text = "col2" };
inlineString2.Append(text2);
cell2.Append(inlineString2);
row.Append(new List<Cell>() { cell1, cell2 });
SheetData sheetData = new SheetData();
sheetData.Append(row);
Worksheet worksheet = new Worksheet();
worksheet.Append(sheetData);
worksheetPart.Worksheet = worksheet;
worksheetPart.Worksheet.Save();
Sheets sheets = new Sheets();
string relId = workbookPart.GetIdOfPart(worksheetPart);
Sheet sheet = new Sheet { Name = "Sheet1", SheetId = 1, Id = relId };
sheets.Append(sheet);
Workbook workbook = new Workbook();
workbook.Append(sheets);
spreadsheetDocument.WorkbookPart.Workbook = workbook;
spreadsheetDocument.WorkbookPart.Workbook.Save();
spreadsheetDocument.Close();
I know this is an old question, but I ran into this problem and found the solution in a MSDN forum. The SDK samples contain code that simply does not work with columns beyong Z (like AA for example).
As mentioned here, the problem is that using alphabetial order, AA1 will come before B1 and so on. The way to resolve it is to make the letters base-26 numbers. In the very same MSDN forum, the solution was given.
First create a base-26 converter:
//Hexavigesimal (Excel Column Name to Number) - Bijective
private int fromBase26(string colName)
{
colName = colName.ToUpper();
int decimalValue = 0;
for (int i = 0; i < colName.Length; i++)
{
decimalValue *= 26;
decimalValue += (colName[i] - 64);
}
return decimalValue;
}
Then, change this line in the method to insert a cell in the worsheet from:
if (string.Compare(cell.CellReference.Value, cellReference, true) > 0)
To:
if (fromBase26(Regex.Replace(cell.CellReference.Value, #"[\d-]", string.Empty)) > fromBase26(Regex.Replace(cellReference, #"[\d-]", string.Empty)))

Delete rows from Excel using OpenXML

I need to delete certain rows from an excel file. The excel file is a template and may have extra rows, which have to be deleted for the final output. However deletion of the cells corrupts the file. The code is as simple as follows
Worksheet worksheet = worksheetPart.Worksheet;
SheetData sheetData = worksheet.GetFirstChild<SheetData>();
foreach (var row in sheetData.Elements<Row>().
Where(r => r.RowIndex.Value >= rowIndex && r.RowIndex.Value < rowIndex + count).ToList())
{
row.Remove();
}
Alternatively, I tried setting the existing cells to blank values.
Worksheet worksheet = worksheetPart.Worksheet;
SheetData sheetData = worksheet.GetFirstChild<SheetData>();
foreach (var row in sheetData.Elements<Row>().
Where(r => r.RowIndex.Value >= rowIndex && r.RowIndex.Value < rowIndex + count).ToList())
{
IEnumerable<Cell> cells = row.Elements<Cell>().ToList();
if (cells != null)
{
foreach (Cell cell in cells)
{
if (cell.CellValue != null && !String.IsNullOrEmpty(cell.CellValue.Text))
{
cell.DataType = new EnumValue<CellValues>(CellValues.String);
cell.CellValue = new CellValue("");
}
}
}
}
My file always gets corrupted.
The issue was that the final streams to save the worksheet/workbooks, had a mismatch in the sizes.

How to optimize exporting data to excel in Excel Interop?

I am using Excel interop to create excel workbooks from my query results. When there are thousands of records it takes a long time for the workbook to be generated. The below code is a sample of how I am populating the cells.
RowNo = 1
For i = 1 To 4000
ColNo = 1
For j = 1 To 5
Dim cell As excel.Range = ws.Cells(RowNo, ColNo)
Dim value = j
cell.Value = value
ColNo = ColNo + 1
Next
RowNo = RowNo + 1
Next
For the above code to run it takes more than a minute. How can I optimize it?
Found the answer. You can write data to an array and then write the array to the excel range rather than writing the data cell by cell. See http://www.clear-lines.com/blog/post/Write-data-to-an-Excel-worksheet-with-C-fast.aspx
private static void WriteArray(int rows, int columns, Worksheet worksheet)
{
var data = new object[rows, columns];
for (var row = 1; row <= rows; row++)
{
for (var column = 1; column <= columns; column++)
{
data[row - 1, column - 1] = "Test";
}
}
var startCell = (Range)worksheet.Cells[1, 1];
var endCell = (Range)worksheet.Cells[rows, columns];
var writeRange = worksheet.Range[startCell, endCell];
writeRange.Value2 = data;
}

Resources