Autofit long strings with EPPLus - c#

Using EPPLus library, I'm trying to autofit very long strings in xlsx cells this way:
worksheet.Cells.AutoFitColumns();
Rows: 1000
Columns: 10
For 2 columns, I'm expecting around 6000 character in each cell.
In this scenario, AutoFitColumns method generates the following exception:
Message: A generic error occurred in GDI+.
StackTrace: at
System.Drawing.Graphics.MeasureString(String text, Font font, SizeF
layoutArea, StringFormat stringFormat) at
System.Drawing.Graphics.MeasureString(String text, Font font, Int32
width, StringFormat format) at
OfficeOpenXml.ExcelRangeBase.AutoFitColumns(Double MinimumWidth,
Double MaximumWidth) at
OfficeOpenXml.ExcelRangeBase.AutoFitColumns()...
EDIT
Here is my full code:
using (ExcelPackage package = new ExcelPackage(newFile))
{
ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("Sheet1");
// Setup the first row with headers
for (int j = 0; j < fields.Length; j++)
{
worksheet.Cells[1, j + 1].Value = fields[j];
}
Color colFromHex = ColorTranslator.FromHtml("#B4B4B4");
worksheet.Row(1).Style.Fill.PatternType = ExcelFillStyle.Solid;
worksheet.Row(1).Style.Fill.BackgroundColor.SetColor(colFromHex);
// Insert new rows
for (int i = 0; i < elements.Count; i++)
{
// this will return List<object>
var properties = elements[i].GetPatentProperties();
for (int j = 0; j < properties.Count; j++)
{
worksheet.Cells[i + 2, j + 1].Value = properties[j];
}
}
// This will throw an exception for big number of elements: ~ 1000 element
worksheet.Cells.AutoFitColumns();
worksheet.Cells.Style.WrapText = true;
//worksheet.Cells[autosize].Style.HorizontalAlignment = ExcelHorizontalAlignment.CenterContinuous;
package.Save();
}
Note that for the same list of elements, if I remove worksheet.Cells.AutoFitColumns();, I will get my xlsx file without exception.
Is it possible to overcome this issue?

Have you tried setting min and max col sizes?
ws.Cells.AutoFitColumns(10, 60);

Related

Get Data From Excel - Index exceeds bounds

I am trying to get data from an Excel file. I know that indexing in excel starts from 1, but still when reading a simple matrix, I am getting an Index exceeds bounds error.
Here is a simple method I'm using:
public static string[,] ReadFromExcel(Worksheet excelSheet)
{
if (excelSheet == null) return new string[1,1];
Microsoft.Office.Interop.Excel.Range xlRange = excelSheet.UsedRange;
int firstRow = xlRange.Row;
int firstColumn = xlRange.Column;
int lastRow = xlRange.Row + xlRange.Rows.Count - 1;
int lastColumn = xlRange.Column + xlRange.Columns.Count - 1;
string[,] data = new string[xlRange.Rows.Count - xlRange.Row, xlRange.Columns.Count - xlRange.Column];
for (int i= 0; i<= lastRow - firstRow; i++)
{
for (int j= 0; j <= lastColumn - firstColumn; j++)
{
data[i,j] = (string)(excelSheet.Cells[firstRow + i][firstColumn + j] as Range).Value;
//When I try to read values I get an error
System.Windows.MessageBox.Show(data[i, j]);
}
}
return data;
}
What am I missing?
The size of your "data" array should match the number of rows & columns:
string[,] data = new string[xlRange.Rows.Count, xlRange.Columns.Count];
Although the start index for Excel Interop is 1, rather than zero, the count is correct & you don't need to subtract the start row & column.

How to color specific row in excel table?

I create excel file using NPOI dll's.
I have this code that create excel table from List<someObjects> :
IWorkbook workbook = new XSSFWorkbook();
ISheet sheet1 = workbook.CreateSheet("Sheet 1");
IRow header = sheet1.CreateRow(0);
header.CreateCell(0).SetCellValue("Id");
header.CreateCell(1).SetCellValue("Name");
header.CreateCell(2).SetCellValue("E-Mail");
header.CreateCell(3).SetCellValue("PhoneNumber");
for (int i = 0; i < list.Count(); i++)
{
IRow row = sheet1.CreateRow(i + 1);
row.CreateCell(0).SetCellValue(list[i].id);
row.CreateCell(1).SetCellValue(list[i].name);
row.CreateCell(2).SetCellValue(list[i].email);
row.CreateCell(3).SetCellValue(list[i].phoneNumber);
}
Then I make each cell bordered in the table created above.
Here is the code:
public void setBorderExcel()
{
XSSFCellStyle myStyle = (XSSFCellStyle)workbook.CreateCellStyle();
myStyle.BorderBottom = BorderStyle.Medium;
myStyle.BorderTop = BorderStyle.Medium;
myStyle.BorderLeft = BorderStyle.Medium;
myStyle.BorderRight = BorderStyle.Medium;
for (int i = 0; i < 7; i++)
{
for (int j = 0; j < 4; j++)
{
workbook.GetSheetAt(0).GetRow(i).GetCell(j).CellStyle = myStyle;
}
}
}
Then I make each odd row in the table created above colored.
Here is the code:
public void setColorExcel()
{
for (int i = 0; i < 7; i++)
{
for (int j = 0; j < 4; j++)
{
if (i % 2 == 0) continue;
workbook.GetSheetAt(0).GetRow(i).GetCell(j).CellStyle.FillForegroundColor = HSSFColor.Grey25Percent.Index;
workbook.GetSheetAt(0).GetRow(i).GetCell(j).CellStyle.FillPattern = FillPattern.SolidForeground;
}
}
}
And here is the result that I get:
As you can see the color applied to all rows in the table while, I wanted to color only the odd rows.
My question is why I get colored all rows? And how can I make colored only specific rows?
I think I understand it. You have applied the same XSSFCellStyle instance to all cells' Style property in (setBorderExcel). So, now they all have the same instance, so when you change a property on the CellStyle of one of the cells, it's changing the CellStyle instance which is associated with all cells.
You'll most likely need two XSSFCellStyle instances. One for odd rows and another for even rows.
I tried it out, and although I'm not sure why your way doesn't work, there is an easier way with less lines (simply declare another CellStyle with grey background, and use that instead of myStyle):
XSSFCellStyle myStyle = (XSSFCellStyle)workbook.CreateCellStyle();
myStyle.BorderBottom = BorderStyle.Medium;
myStyle.BorderTop = BorderStyle.Medium;
myStyle.BorderLeft = BorderStyle.Medium;
myStyle.BorderRight = BorderStyle.Medium;
XSSFCellStyle myStyleGrey = (XSSFCellStyle)workbook.CreateCellStyle();
myStyleGrey.BorderBottom = BorderStyle.Medium;
myStyleGrey.BorderTop = BorderStyle.Medium;
myStyleGrey.BorderLeft = BorderStyle.Medium;
myStyleGrey.BorderRight = BorderStyle.Medium;
myStyleGrey.FillForegroundColor = HSSFColor.Grey25Percent.Index;
myStyleGrey.FillPattern = FillPattern.SolidForeground;
for (int i = 0; i < 7; i++)
{
for (int j = 0; j < 4; j++)
{
if (i % 2 == 0)
workbook.GetSheetAt(0).GetRow(i).GetCell(j).CellStyle = myStyle;
else
workbook.GetSheetAt(0).GetRow(i).GetCell(j).CellStyle = myStyleGrey;
}
}
You can remove your code for setColorExcel() and it should work as expected, setting odd rows to grey.

Export Data Table To Excel

I am having a formatting issue when exporting my data table to Excel. The data is exported as it should, however if you look at my image, sometimes the cell height is increased and I am not sure why. I want the data to look the same from row to row. This is the syntax I am using to export
for (var i = 0; i < tbl.Columns.Count; i++)
workSheet.Cells[1, i + 1] = tbl.Columns[i].ColumnName;
for (var i = 0; i < tbl.Rows.Count; i++)
{
for (var j = 0; j < tbl.Columns.Count; j++)
workSheet.Cells[i + 2, j + 1] = tbl.Rows[i][j];
}
And here is an image that shows my formatting issues that I want to find a way to overcome. Can someone show me what syntax I need in order to have all row height/width the same?
Issue Image
EDIT
I tried this, but it throws an error and does not format as needed
The error is
System.Exception
Excel.Range range1 = workSheet.get_Range("A2", "S2000");
range1.EntireRow.Height.Value = 15;
You are over complicating it. Just use the UsedRange property. If workSheet is your actual variable name and 15 is the actual height you want to set, the below will work:
workSheet.UsedRange.EntireRow.RowHeight = 15;

How to merge first 3 columns for rows with same value in PDF

I'm using itextSharp to export a DataTable to a pdf table. I can export the data to a pdf table using the sample code i have posted below. The DataTable contains close to 21 columns.
The first column in the pdf (DataTable) might contain similar values for any number of rows. If the data values in first column for a group of rows is similar, i want to merge the first 3 columns of those rows as one cell.
I'm having trouble modifying the code below to achieve this.
public iTextSharp.text.Table GetItextTable(DataTable dtChartData, string reportType)
{
int intCols = dtChartData.Columns.Count; //Total number of columns
int intRows = dtChartData.Rows.Count; //Total number of rows
iTextSharp.text.Table pdfTable = new iTextSharp.text.Table(intCols, intRows);
try
{
pdfTable.BorderWidth = 1;
pdfTable.Width = 100;
pdfTable.Padding = 1;
pdfTable.Spacing = 1;
/*creating table headers */
for (int i = 0; i < intCols; i++)
{
iTextSharp.text.Cell cellCols = new iTextSharp.text.Cell();
iTextSharp.text.Font ColFont = iTextSharp.text.FontFactory.GetFont("Tahoma", 07,
iTextSharp.text.Font.BOLD);
for (int l = 0; l < dtChartData.Columns.Count; l++)
{
if (dtChartData.Columns[l].ColumnName.Contains("_"))
{
dtChartData.Columns[l].ColumnName = dtChartData.Columns[l].ColumnName.Replace("_", " ");
}
}
iTextSharp.text.Chunk chunkCols = new iTextSharp.text.Chunk(dtChartData.Columns[i].ColumnName,ColFont);
cellCols.HorizontalAlignment = iTextSharp.text.Element.ALIGN_CENTER;
if ((chunkCols.ToString().ToLower() == "ReportDetails"))
{
cellCols.HorizontalAlignment = iTextSharp.text.Element.ALIGN_CENTER;
}
}
/* loop that take values from every row in datatable and insert in itextsharp table */
for (int k = 0; k < intRows; k++)
{
for (int j = 0; j < intCols; j++)
{
iTextSharp.text.Cell cellRows = new iTextSharp.text.Cell();
iTextSharp.text.Font RowFont = iTextSharp.text.FontFactory.GetFont("Tahoma", 07);
iTextSharp.text.Chunk chunkRows = new iTextSharp.text.Chunk(dtChartData.Rows[k][j].ToString(),RowFont);
cellRows.HorizontalAlignment = iTextSharp.text.Element.ALIGN_CENTER;
cellRows.Add(chunkRows);
pdfTable.AddCell(cellRows);
}
}
}
catch (Exception ex)
{
//error handling code here removed
}
return pdfTable;
}
Have you tried to change the Colspan?
iTextSharp.text.Cell cell = new iTextSharp.text.Cell();
cell.AddElement(new Paragraph("colspan 3"));
cell.Colspan = 3;
table.AddCell(cell);
In this case, cell will span three columns.
try this. i just edited your code, not checked
here i have edited 1 line of your code and added a new line (total 2 lines of change only).
dont forget to combine headding row like this, if you need
/* loop that take values from every row in datatable and insert in itextsharp table */
for (int k = 0; k < intRows; k++)
{
for (int j = 2; j < intCols; j++)// EDIT: if all first 3 cols are same, then starts with 2
{
iTextSharp.text.Cell cellRows = new iTextSharp.text.Cell();
if(j == 2) cellRows.Colspan = 3;// ADD: it'll gives a 3 times long cell
iTextSharp.text.Font RowFont = iTextSharp.text.FontFactory.GetFont("Tahoma", 07);
iTextSharp.text.Chunk chunkRows = new iTextSharp.text.Chunk(dtChartData.Rows[k][j].ToString(),RowFont);
cellRows.HorizontalAlignment = iTextSharp.text.Element.ALIGN_CENTER;
cellRows.Add(chunkRows);
pdfTable.AddCell(cellRows);
}
}

Epplus conditional formatting based on a rule

How can we add three icon sets to each cell in excel using epplus conditional formatting. I'm using following code to add three icon set:
using (ExcelRange scoreRange = workSheet.Cells[1, 2, 1, 10])
{
ExcelAddress rangeAddress = new ExcelAddress(scoreRange.Address);
var ruleIconSet = workSheet.ConditionalFormatting.AddThreeIconSet(rangeAddress, eExcelconditionalFormatting3IconsSetType.Arrows); // This calculates based on the value in the range
}
I want to create a rule like if value in a cell is less than 0, the green color icon should be displayed, if value is greater than 0, the red color icon should be displayed.
What should be the rule statement that can perform this stuff?
for(int j =2; j <=9; j++) //Loop through columns
{
for(int i = 3; i <= 12; i++) // Loop through rows
{
// gets only the current cell as range
ExcelRange rng = worksheet.Cells[i, j, i, j];
ExcelAddress address = new ExcelAddress(rng.Address);
// Get the value of the current cell
if(Convert.ToDouble(worksheet.Cells[i, j].Value) >= 4.0)
{
var v = worksheet.ConditionalFormatting.AddThreeIconSet(address, eExcelconditionalFormatting3IconSetType.Arrows);
v.Reverse = true;
v.Icon1.Type = eExcelConditionalFormattingValueObjectType.Num;
}
else if(Convert.ToDouble(workSheet.Cells[i, j].Value) > 1.0 && Convert.ToDouble(workSheet.Cells[i, j].Value) < 4.0)
{
var v = worksheet.ConditionalFormatting.AddThreeIconSet(address , eExcelconditionalFormatting3IconsSetType.Arrows);
v.Icon3.Type = eExcelConditionalFormattingValueObjectType.Num;
}
else (Convert.ToDouble(workSheet.Cells[i, j].Value) < 1.0)
{
var v = worksheet.ConditionalFormatting.AddThreeIconSet(address , eExcelconditionalFormatting3IconsSetType.Arrows);
v.Icon2.Type = eExcelConditionalFormattingValueObjectType.Num;
}
}
}
This works for me.

Categories

Resources