EPPLUS ExcelRange creates table starting in wrong row - c#

In C# I have populated an excel file with data. Now I would like to create a table starting at cell A2.
I am using the code below to create the table but instead of creating the table starting at Cell A2, the table is being created starting at cell A3
using var package = new ExcelPackage(file);
var ws = package.Workbook.Worksheets.Add(Name: "MainReport");
var range = ws.Cells[Address: "A2"].LoadFromCollection(people, PrintHeaders: true);
range.AutoFitColumns();
//Formats Header row
ws.Cells[Address: "A1"].Value = "My Data!";
ws.Cells[Address: "A1:C1"].Merge = true;
ws.Column(col: 1).Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
ws.Row(row: 1).Style.Font.Size = 24;
ws.Row(row: 1).Style.Font.Color.SetColor(Color.Pink);
ws.Row(row: 2).Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
ws.Row(row: 2).Style.Font.Bold = true;
ws.Column(col: 3).Width = 20;
//create a range for the table
ExcelRange range_table = ws.Cells[2, 1, ws.Dimension.End.Row, ws.Dimension.End.Column];
//add a table to the range
ExcelTable tab = ws.Tables.Add(range_table, "Table1");
//format the table
tab.TableStyle = TableStyles.Medium2;

Excel itself works so that if you select A2:C4 and create a table and you say "has no Headers" it will put some generic headers in A2:C2 and shift the data area (and the data if there is any) to A2:C5.
If you say "has Headers" the headers will be defined in A2:C2, too, but the data only is in A3:C4.
The real Excel obviously does some guessing whether headers are present or not and pre-ticks the box for you.
As stated here in the API Documentation, there is no flag to define if headers are present in the range so there might be no guessing and it might be assumed it is "no" and the shifting as explained on top takes place.
If you take that into consideration you should be able to work it out.

Related

Creating multiple header rows in an excel file with EPPlus.Core

I will be using EPPlus.Core to generate excel reports in my .Net Core project. So after digging Google to find some sample code snippets I found the following blog:
Create Excel Files in C#
I can create an excel file with a single header with the following code:
using (ExcelPackage excel = new ExcelPackage())
{
excel.Workbook.Worksheets.Add("Worksheet1");
excel.Workbook.Worksheets.Add("Worksheet2");
excel.Workbook.Worksheets.Add("Worksheet3");
var headerRow = new List<string[]>()
{
new string[] { "ID", "First Name", "Last Name", "DOB" }
};
// Determine the header range (e.g. A1:D1)
string headerRange = "A1:" + Char.ConvertFromUtf32(headerRow[0].Length + 64) + "1";
// Target a worksheet
var worksheet = excel.Workbook.Worksheets["Worksheet1"];
// Popular header row data
worksheet.Cells[headerRange].LoadFromArrays(headerRow);
FileInfo excelFile = new FileInfo(#"C:\Users\amir\Desktop\test.xlsx");
excel.SaveAs(excelFile);
}
But I couldn't find out how to add multiple header rows on a single worksheet. For instance, the first table has ID, Name, Price headers and the second table has Notes and Price headers. Is it possible to add multiple tables into a worksheet with EPPlus.Core? The code snippet above adds only a single header row from A1 to D1. Let's say I wanna add another header row from A4 to J4. Any suggestions?
And yet I found the answer. Hope this will help others to save their time. It is not the best of best approach but this is what I need. I defined the coordinates on the Cells array by adding "A1:J1" and "A3:E3".
var worksheet = excel.Workbook.Worksheets["Worksheet1"];
worksheet.Cells["A1:J1"].LoadFromArrays(header1Data);
worksheet.Cells["A1:J1"].Style.Font.Bold = true;
worksheet.Cells[2, 1].LoadFromArrays(array1Data);
worksheet.Cells["A3:E3"].LoadFromArrays(header2Data);
worksheet.Cells["A3:E3"].Style.Font.Bold = true;
worksheet.Cells[4, 1].LoadFromArrays(array2Data);

Format vsto listobject before linked to datatable

I have a vsto application that populates an Excel sheet.
First I populate the datatable. The next function is to create a vsto listobject:
// Populate the sheet
XlsInterop.Excel.Worksheet worksheet = (XlsInterop.Excel.Worksheet)Globals.ThisAddIn.Application.ActiveWorkbook.Worksheets.Add();
extendedWorksheet = Globals.Factory.GetVstoObject(worksheet);
XlsInterop.Excel.Range cell = extendedWorksheet.Range["A1"];
excelItemsList = extendedWorksheet.Controls.AddListObject(cell, sheetName);
excelItemsList.AutoSetDataBoundColumnHeaders = true;
excelItemsList.DataSource = dt;
excelItemsList.ListColumns[5].Range.NumberFormat = "#";
Now the problem is that in column "5" I have values like 005, 004. In Excel, the values display as 5 and 4. How can I make sure that the values in Excel show the same values as in my database?
If I change my code like:
excelItemsList.SetDataBinding(dt);
excelItemsList.ListColumns[5].Range.NumberFormat = "#";
excelItemsList.SetDataBinding(dt);
It is doing what I want, but I don't think that this is the way to go.
If you know how many leading zeros you need, you can then format the column with that.
.NumberFormat = "000";
The column would then still be evaluated as a number.

Append data to excel sheet if created using ClosedXML in c#

I am writing an application in which I need to store data cell values into excel sheet. Everything is working fine but the problem is everytime I run the application, it overwrites the existing data.
So far the code I have taken from Github:
var workbook = new XLWorkbook();
var worksheet = workbook.Worksheets.Add("Sample Sheet");
worksheet.Cell("A1").Value = this.textBox1.Text;
worksheet.Cell("B1").Value = this.textBox2.Text;
worksheet.Cell("C1").Value = this.textBox3.Text;
worksheet.Cell("D1").Value = col1;
worksheet.Cell("E1").Value = col2;
worksheet.Cell("F1").Value = this.textBox6.Text;
workbook.SaveAs("HelloWorld.xlsx");
Note: I don't want to save data using datatable or anything. I just want to get values from textboxes and append them to the existing sheet. I have visited many stackoverflow post but they doesn't helped me much.
Thanks in advance!
Hope this helps:
var wb = new XLWorkbook("Path to file");
IXLWorksheet Worksheet = wb.Worksheet("Tab name");
int NumberOfLastRow = Worksheet.LastRowUsed().RowNumber();
IXLCell CellForNewData = Worksheet.Cell(NumberOfLastRow + 1, 1);
CellForNewData.InsertData(your_data);
You are explicitly storing the values in row 1 of the spreadsheet. If you want to append the values, you'll have to increment the row number and store the values in the appropriate cells.

Open XML populate excel table

I have excel template with empty one-column table. I need to populate it with some string values (this is needed for setting lookups using data validation, but I guess it doesn't really matter)
I came up to getting Table object and I assume I should use Append method
var workBookPart = doc.WorkbookPart;
var lookupsSheet = (Sheet)workBookPart.Workbook.Sheets.FirstOrDefault(x => (x is Sheet && ((Sheet)x).Name == "Lookups"));
var worksheetPart = (WorksheetPart)workBookPart.GetPartById(lookupsSheet.Id);
var table = worksheetPart.TableDefinitionParts.FirstOrDefault(x => x.Table.DisplayName == "ValuesTable")?.Table;
Can someone enlighten about the correct way of adding rows to such table. Thanks!
I would suggest you use the ClosedXML library to set the values of cells in your worksheet. By using ClosedXML, you will be able to populate the cells you want in the following fashion:
var workbook = new XLWorkbook();
var ws = workbook.Worksheets.Add("Demo");
// Set the values for the cells
ws.Cell(1, 1).Value = "Value";
ws.Cell(2, 1).Value = 1;
ws.Cell(3, 1).Value = 2;
ws.Cell(4, 1).Value = 3;
ws.Cell(5, 1).Value = true;
Note that you can set the value of a cell to a string, an integer, and a boolean without doing any explicit casting. You can set the value of a cell without doing any explicit casting to other types as well, as it is explained in the following link: Cell Values.
For more information regarding the ClosedXML library please refer to the documentation.
As a side note, I was really eager to use Open XML to manipulate Excel spreadsheets but I found ClosedXML way easier to use.

Select range in aspose

Do you know an equivalent to VBA code:
Range(Selection, Selection.End(xlToRight)).Select
In Aspose.Cells. It seems that its only possible to select the last cell in the entire row:
public Aspose.Cells.Cell EndCellInRow ( Int32 rowIndex )
Or the last cell on the right within a range:
public Aspose.Cells.Cell EndCellInRow ( Int32 startRow, Int32 endRow, Int32 startColumn, Int32 endColumn )
but then you must know more or less how big your table is going to be.
I found this from 2009: http://www.aspose.com/community/forums/permalink/196519/196405/showthread.aspx but that will not resolve my problem as I may have many tables in a sheet both horizontally and vertiacally. And I can't predict where they are going to be.
Edit1:
Sorry if this is dumb question, but ctrl+shift+arrow is such a common operation that I can't believe it would be not implemented so I'm making sure I really have to re-invent the wheel.
Aspose.Cells provides the list of tables in a worksheet using property named 'Worksheet.ListObjects'. 'ListObjects' is a colloection of 'ListObject' type which represents a Table in an excel sheet. That means if one has more than one Tables in a worksheet, the ListObjects collection will give access to every table in the worksheet very conveniently. Each 'ListObject' in turn contains a property named 'DataRange' which specifies all the cells inside a Table. For the sake of convenience DataRange can be used for following operations on a Table:
To apply styles/formatting on the cells in Table
To get the data values
Merge or move the cells in Range
Export contents
To get enumerator to traverse through Table cells
To make selection of cells from DataRange, you can traverse using DataRange to get all the cells in a Row (This could also be done for a column)
Applying any operation on Table cells like after selecting cells using Ctrl+Shift+Arrow, could be performed using a workbook object as follows:
Workbook workbook = new Workbook(new FileStream("book1.xls", FileMode.Open));
if (workbook.Worksheets[0].ListObjects.Count > 0)
{
foreach (ListObject table in workbook.Worksheets[0].ListObjects)
{
Style st = new Style();
st.BackgroundColor = System.Drawing.Color.Aqua;
st.ForegroundColor = System.Drawing.Color.Black;
st.Font.Name = "Agency FB";
st.Font.Size = 16;
st.Font.Color = System.Drawing.Color.DarkRed;
StyleFlag stFlag = new StyleFlag();
stFlag.All = true;
table.DataRange.ApplyStyle(st, stFlag);
}
}
workbook.Save("output.xls");
There is also some worthy information available in Aspose docs about Table styles and applying formatting on a ListObject. For getting last Table cell in a certain row or column, I am sure this will help:
int iFirstRowIndex = table.DataRange.FirstRow;
int iFirstColumnIndex = table.DataRange.FirstColumn;
int iLastRowIndex = table.DataRange.RowCount + iFirstRowIndex;
int iLastColumnIndex = table.DataRange.ColumnCount + iFirstColumnIndex;
for (int rowIndex = 0; rowIndex < table.DataRange.RowCount; rowIndex++)
{
//Get last cell in every row of table
Cell cell = worksheet.Cells.EndCellInColumn(rowIndex + iFirstRowIndex, rowIndex + iFirstRowIndex, (short)iFirstColumnIndex, (short)(iLastColumnIndex - 1));
//display cell value
System.Console.WriteLine(cell.Value);
}

Categories

Resources