I was wondering if it is possible to set cell color programmatically using epplus?
I load my data from a sql stored procedure and it works well, but my users want
cells that contain the words 'Annual Leave' to have a background color of light yellow instead of the default white. Is there a way to do this? perhaps by iterating through a datatable perhaps? Below is where
public void ExportTableData(DataTable dtdata)
{
//Using EPPLUS to export Spreadsheets
ExcelPackage pck = new ExcelPackage();
var ws = pck.Workbook.Worksheets.Add("Availability list");
ws.Cells["A1"].LoadFromDataTable(dtdata, true);
ws.Cells["A1:G1"].Style.Font.Bold = true;
ws.Cells["A1:G1"].Style.Font.UnderLine = true;
//change cell color depending on the text input from stored proc?
if (dtdata.Rows[4].ToString() == "Annual Leave")
{
ws.Cells["E1"].Style.Fill.PatternType = ExcelFillStyle.Solid;
ws.Cells["E1"].Style.Fill.BackgroundColor.SetColor(Color.LightYellow);
}
pck.SaveAs(Response.OutputStream);
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("content-disposition", "attachment; filename=Availability.xlsx");
Response.End();
}
Check your line:
if (dtdata.Rows[4].ToString() == "Annual Leave")
If it is a standard .net table wouldnt .ToString() evaluate to "System.Data.DataRow"? Also ws.Cells["E1"] will need to be adjusted for each cell after looping through the row count (basically what krillgar was saying).
Something like that:
[TestMethod]
public void Cell_Color_Background_Test()
{
//http://stackoverflow.com/questions/28679602/how-to-set-cell-color-programmatically-epplus
//Throw in some data
var dtdata = new DataTable("tblData");
dtdata.Columns.Add(new DataColumn("Col1", typeof(string)));
dtdata.Columns.Add(new DataColumn("Col2", typeof(int)));
dtdata.Columns.Add(new DataColumn("Col3", typeof(int)));
for (var i = 0; i < 20; i++)
{
var row = dtdata.NewRow();
row["Col1"] = "Available";
row["Col2"] = i * 10;
row["Col3"] = i * 100;
dtdata.Rows.Add(row);
}
//throw in one cell that triggers
dtdata.Rows[10]["Col1"] = "Annual leave";
var existingFile = new FileInfo(#"c:\temp\temp.xlsx");
if (existingFile.Exists)
existingFile.Delete();
using (var pck = new ExcelPackage(existingFile))
{
//Using EPPLUS to export Spreadsheets
var ws = pck.Workbook.Worksheets.Add("Availability list");
ws.Cells["A1"].LoadFromDataTable(dtdata, true);
ws.Cells["A1:G1"].Style.Font.Bold = true;
ws.Cells["A1:G1"].Style.Font.UnderLine = true;
//change cell color depending on the text input from stored proc?
//if (dtdata.Rows[4].ToString() == "Annual Leave")
for (var i = 0; i < dtdata.Rows.Count; i++)
{
if (dtdata.Rows[i]["Col1"].ToString() == "Annual leave")
{
ws.Cells[i + 1, 1].Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid;
ws.Cells[i + 1, 1].Style.Fill.BackgroundColor.SetColor(System.Drawing.Color.LightYellow);
}
}
pck.Save();
}
Thanks Ernie! I changed it slightly to allow for my header in excel and to also to make sure that the code doesnt start at E1. I used ws.cells[i + 2, 5] to do this. Cheers!
for (var i = 0; i < dtdata.Rows.Count; i++)
{
if (dtdata.Rows[i]["typeName"].ToString() == "Annual Leave")
{
ws.Cells[i + 2, 5].Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid;
ws.Cells[i + 2, 5].Style.Fill.BackgroundColor.SetColor(System.Drawing.Color.LightYellow);
}
else if (dtdata.Rows[i]["typeName"].ToString() == "Available")
{
ws.Cells[i + 2, 5].Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid;
ws.Cells[i + 2, 5].Style.Fill.BackgroundColor.SetColor(System.Drawing.Color.LightGreen);
}
else
{
ws.Cells[i + 2, 5].Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid;
ws.Cells[i + 2, 5].Style.Fill.BackgroundColor.SetColor(System.Drawing.Color.White);
}
}
You could try using the conditional formatting option in EPPlus
here is their sample
and here is a SO post with someone else who has used this option
Generally using links as answers is not my style but no reason to remake those wheels, if the EPP sample goes away im guessing so did they and if the SO sample is gone then im guessing so with this answer.
Hope it helps
Related
I'm using NPOI library to create excel file, I have problem with formatting price.
ISheet excelSheet = workbook.CreateSheet(sheetName);
ICellStyle codeCellStyle = workbook.CreateCellStyle();
ICellStyle priceCellStyle = workbook.CreateCellStyle();
ICellStyle availabilityStyle = workbook.CreateCellStyle();
excelSheet.SetColumnWidth(0, 10 * 256);
excelSheet.SetColumnWidth(1, 12 * 256);
excelSheet.SetColumnWidth(2, 15 * 256);
List<string> columns = new List<string>() { "Code", "Price", "Availability" };
IRow row = excelSheet.CreateRow(0);
foreach (var columnData in columns.Select((v, i) => new { Column = v, Index = i }).ToList())
{
row.CreateCell(columnData.Index).SetCellValue(columnData.Column);
}
codeCellStyle.DataFormat = workbook.CreateDataFormat().GetFormat("#");
priceCellStyle.DataFormat = workbook.CreateDataFormat().GetFormat("#,##0.00");
availabilityStyle.DataFormat = workbook.CreateDataFormat().GetFormat("#");
int rowIndex = 1;
foreach (var item in items)
{
row = excelSheet.CreateRow(rowIndex);
row.CreateCell(0).SetCellValue(item.Code);
row.Cells[0].CellStyle = codeCellStyle;
if (item.HasData)
{
if (item.Price == "ON DEMAND")
{
row.CreateCell(1).SetCellValue(item.Price);
}
else
{
ICell priceCell = row.CreateCell(1);
row.Cells[1].SetCellType(CellType.Numeric);
row.Cells[1].CellStyle = priceCellStyle;
if (percentage != 0)
priceCell.SetCellValue(double.Parse(item.Price) + ((double)percentage / (double)100) * double.Parse(item.Price));
else
priceCell.SetCellValue(double.Parse(item.Price));
}
row.CreateCell(2).SetCellValue(item.Availability ? "True" : "False");
}
else
{
row.CreateCell(1).SetCellValue("");
row.CreateCell(2).SetCellValue("");
}
rowIndex++;
}
When I have item with price "422,26" it produce excel file with price value 42226,00.
It works fine when I have price "380,00", "4730,00", but problem occurs when I have decimal part in string number.
I tried other suggestions from stackoverflow but I have no luck nothing works on my example.
After struggling this format solved my problem
"#,#0.00"
I want to add some basic information regarding the DataGridView before my DGV gets converted to Excel. This is an example from the internet sample output, currently I can upload all the data to Excel, but I'm not sure how to hardcode the title (row1 from pic) and some basic information (row 2 from pic) before the data gets converted.
If anything is unclear let me know.
//Create headers
for (int i = 0; i < dv.Columns.Count; i++)
{
Excel.Range CellHeadersRange = ws.get_Range(GetExcelColumnName(i + 1) + rowstartindex.ToString(), GetExcelColumnName(i + 1) + rowstartindex.ToString());
//Setting the borders
CellHeadersRange.BorderAround2(LineStyle.Thin, Excel.XlBorderWeight.xlThin, Excel.XlColorIndex.xlColorIndexNone,
Color.FromArgb(255, 0, 0), Type.Missing);
//Aligning headers to the middle
CellHeadersRange.HorizontalAlignment = Excel.XlHAlign.xlHAlignCenter;
//Updating header value to Excel
CellHeadersRange.Value = dv.Columns[i].HeaderText;
CellHeadersRange.Font.Bold = true;
double widthDGV = (dv.Columns[i].Width) / 10;
Math.Ceiling(widthDGV);
CellHeadersRange.ColumnWidth = widthDGV * 2;
}
//Write data
for (int i = 0; i < dv.Rows.Count - 1; i++)
{
for (int j = 0; j < dv.Columns.Count; j++)
{
Excel.Range CellDataRange = ws.get_Range(GetExcelColumnName(j + 1) + (i + rowstartindex + 1).ToString());
CellDataRange.WrapText = true;
//Setting borders for all cells
CellDataRange.BorderAround2(LineStyle.Thin, Excel.XlBorderWeight.xlThin, Excel.XlColorIndex.xlColorIndexNone, Color.FromArgb(255, 0, 0), Type.Missing);
CellDataRange.Value = dv[j, i].Value;
//Verify that backgroundcolor of datagrid is not RGB(0,0,0,0) and in that case apply datagridviewcell color to excel range
if (!dv.Rows[i].Cells[j].Style.BackColor.IsEmpty)
CellDataRange.Interior.Color = dv.Rows[i].Cells[j].Style.BackColor;
//Verify that font style exist before checking for bold and in that case apply datagridviewcell font.bold property to excel range
if (dv.Rows[i].Cells[j].Style.Font != null)
CellDataRange.Font.Bold = dv.Rows[i].Cells[j].Style.Font.Bold;
}
}
wb = null;
ws = null;
xlApp = null;
GC.Collect();
GC.WaitForPendingFinalizers();
Edit: Maybe my question is all over places due to that I'm getting no response so I was wondering how can I add data to the first row of an existing excel sheet? Lets say using my code i first generate my excel sheet than I would like to insert couple new rows in the beginning of the sheet. How can I achieve that??
Solution:
//Writitng the title
Excel.Range line = (Excel.Range)ws.Rows[1];
line.Insert();
Excel.Range rng = ws.get_Range("B1");
rng.RowHeight = 35;
rng.Font.Bold = true;
rng.Value = "Assumptions";
rng.HorizontalAlignment = Excel.XlHAlign.xlHAlignCenter;
rng.Font.Size = 14;
rng.Interior.Color = Color.LightBlue;
rng = ws.get_Range("A1");
rng.Interior.Color = Color.LightBlue;
You can manipulate where you want to insert row by changing this ws.Rows[x];
I am using EPPlus library to exporting charts from the application. But I want to change the text direction of X-Axis labels of exported graphs. I am not able to find the property in epplus.
I have attached the image of property which I want to change in the graph using EPPLUS.
This is code to export the graph from Dataset to excel sheet.
using (ExcelPackage objExcelPackage = new ExcelPackage())
{
int i = 0, startIndex = 1, endIndex = 1, j = 0;
string[] seriesValues; string[] seriesHeader;
foreach (DataTable item in ds.Tables)
{
ExcelWorksheet objWorksheet = objExcelPackage.Workbook.Worksheets.Add("Sheet" + i.ToString());
objWorksheet.Cells.Style.Font.SetFromFont(new System.Drawing.Font("Calibri", 10));
objWorksheet.Cells.AutoFitColumns();
dynamic chart;
//Add the chart to the sheet
if (item.Rows[0].CommonEnum.CommonColumnName.GraphType.ToString()].ToString() == CommonEnum.GetEnumDescription(CommonEnum.GraphType.ScatterChart) || item.Rows[0][CommonEnum.CommonColumnName.GraphType.ToString()].ToString() == CommonEnum.GraphType.ScatterChart.ToString())
{
chart = objWorksheet.Drawings.AddChart(string.Empty, eChartType.XYScatterLines);
}
else if (item.Rows[0][CommonEnum.CommonColumnName.GraphType.ToString()].ToString() == CommonEnum.GetEnumDescription(CommonEnum.GraphType.BarChart) || item.Rows[0][CommonEnum.CommonColumnName.GraphType.ToString()].ToString() == CommonEnum.GraphType.BarChart.ToString())
{
chart = objWorksheet.Drawings.AddChart(string.Empty, eChartType.ColumnClustered) as ExcelBarChart;
}
else if (item.Rows[0][CommonEnum.CommonColumnName.GraphType.ToString()].ToString() == CommonEnum.GetEnumDescription(CommonEnum.GraphType.BubbleChart) || item.Rows[0][CommonEnum.CommonColumnName.GraphType.ToString()].ToString() == CommonEnum.GraphType.BubbleChart.ToString())
{
chart = objWorksheet.Drawings.AddChart(string.Empty, eChartType.Bubble) as ExcelBubbleChart;
}
else if (item.Rows[0][CommonEnum.CommonColumnName.GraphType.ToString()].ToString() == CommonEnum.GetEnumDescription(CommonEnum.GraphType.BarSideBySideStackedSeries2D) || item.Rows[0][CommonEnum.CommonColumnName.GraphType.ToString()].ToString() == CommonEnum.GraphType.BarSideBySideStackedSeries2D.ToString())
{
chart = objWorksheet.Drawings.AddChart(string.Empty, eChartType.BarStacked) as ExcelBarChart;
}
else if (item.Rows[0][CommonEnum.CommonColumnName.GraphType.ToString()].ToString() == CommonEnum.GetEnumDescription(CommonEnum.GraphType.PointSeries2D) || item.Rows[0][CommonEnum.CommonColumnName.GraphType.ToString()].ToString() == CommonEnum.GraphType.PointSeries2D.ToString())
{
chart = objWorksheet.Drawings.AddChart(string.Empty, eChartType.XYScatter);
}
else
{
chart = objWorksheet.Drawings.AddChart(string.Empty, eChartType.Area);
}
if (item.TableName.Contains("TimeBased"))
{
//var chart1= objWorksheet.Drawings.AddChart(string.Empty, eChartType.XYScatter);
//Create the worksheet
objWorksheet.Cells["A1"].LoadFromDataTable(item, true);
DataView view = new DataView(item);
DataTable distinctMeasNumber = view.ToTable(true, CommonEnum.CommonColumnName.Name.ToString());
objWorksheet.Column(2).Style.Numberformat.Format = "yyyy-mm-dd hh:mm:ss";
foreach (DataRow dtItemRow in distinctMeasNumber.Rows)
{
startIndex = endIndex + 1;
endIndex = GetStartEndRowCount(item, dtItemRow[CommonEnum.CommonColumnName.Name.ToString()].ToString()) + 1;
chart.Series.Add(ExcelRange.GetAddress(startIndex, 3, endIndex, 3), ExcelRange.GetAddress(startIndex, 2, endIndex, 2)).Header = dtItemRow[CommonEnum.CommonColumnName.Name.ToString()].ToString();
}
chart.Title.Font.Bold = true;
chart.Title.Font.Size = 8;
chart.PlotArea.Border.LineStyle = eLineStyle.Solid;
chart.SetSize(650, 320);
chart.XAxis.MajorTickMark = eAxisTickMark.Cross;
chart.XAxis.MinorTickMark = eAxisTickMark.Cross;
chart.XAxis.LabelPosition = eTickLabelPosition.Low;
chart.YAxis.LabelPosition = eTickLabelPosition.Low;
chart.YAxis.MajorTickMark = eAxisTickMark.None;
chart.YAxis.MinorTickMark = eAxisTickMark.None;
chart.XAxis.Title.Text = item.Columns[1].ColumnName;`enter code here`
chart.XAxis.Title.Font.Size = 8;
chart.YAxis.Title.Text = item.Columns[2].ColumnName;
chart.YAxis.Title.Font.Size = 8;
i++;
}
chart.Title.Font.Bold = true;
chart.Title.Font.Size = 8;
chart.PlotArea.Border.LineStyle = eLineStyle.Solid;
chart.SetSize(580, 300);
chart.XAxis.MajorTickMark = eAxisTickMark.None;
chart.XAxis.MinorTickMark = eAxisTickMark.None;
chart.XAxis.LabelPosition = eTickLabelPosition.Low;
chart.YAxis.LabelPosition = eTickLabelPosition.Low;
chart.YAxis.MajorTickMark = eAxisTickMark.None;
chart.YAxis.MinorTickMark = eAxisTickMark.None;
chart.XAxis.Title.Text = item.Rows[0][CommonEnum.CommonColumnName.Col1Value.ToString()].ToString();
chart.XAxis.Title.Font.Size = 8;
chart.YAxis.Title.Text = item.Rows[0][CommonEnum.CommonColumnName.Col2Value.ToString()].ToString();
chart.YAxis.Title.Font.Size = 8;
}
chart.SetPosition(4, 0, 7, 0);
chart.Style = eChartStyle.Style2;
}
if (File.Exists(saveAsLocation))
File.Delete(saveAsLocation);
//Create excel file on physical disk
FileStream objFileStrm = File.Create(saveAsLocation);
objFileStrm.Close();
//Write content to excel file
File.WriteAllBytes(saveAsLocation, objExcelPackage.GetAsByteArray());
}
I dont believe EPPlus supports rotating the chart axis (it can do the chart title).
So, you could use the option of manually setting the XML. If you do something like this:
[TestMethod]
public void Chart_Rotate_x_Axis()
{
//https://stackoverflow.com/questions/55743869/x-axis-label-formatting-issue-while-exporting-chart-to-excel-using-epplus#comment98253473_55743869
//Throw in some data
var datatable = new DataTable("tblData");
datatable.Columns.AddRange(new[] {
new DataColumn("Col1", typeof(int)),
new DataColumn("Col2", typeof(int)),
new DataColumn("Col3", typeof(object))
});
for (var i = 0; i < 10; i++)
{
var row = datatable.NewRow();
row[0] = i;
row[1] = i * 10;
row[2] = Path.GetRandomFileName();
datatable.Rows.Add(row);
}
//Create a test file
var fileInfo = new FileInfo(#"c:\temp\Chart_Rotate_x_Axis.xlsx");
if (fileInfo.Exists)
fileInfo.Delete();
using (var pck = new ExcelPackage(fileInfo))
{
var workbook = pck.Workbook;
var worksheet = workbook.Worksheets.Add("Sheet1");
worksheet.Cells.LoadFromDataTable(datatable, true);
var chart = worksheet.Drawings.AddChart("chart test", eChartType.XYScatter);
var series = chart.Series.Add(worksheet.Cells["B2:B11"], worksheet.Cells["A2:A11"]);
//Get the chart's xml
var chartXml = chart.ChartXml;
var chartNsUri = chartXml.DocumentElement.NamespaceURI;
var mainNsUri = "http://schemas.openxmlformats.org/drawingml/2006/main";
//XML Namespaces
var nsm = new XmlNamespaceManager(chartXml.NameTable);
nsm.AddNamespace("c", chartNsUri);
nsm.AddNamespace("a", mainNsUri);
//Get the axis nodes
var xdoc = worksheet.WorksheetXml;
var valAxisNodes = chartXml.SelectNodes("c:chartSpace/c:chart/c:plotArea/c:valAx", nsm);
foreach (XmlNode valAxisNode in valAxisNodes)
{
//Axis one should be the X Axis
if (valAxisNode.SelectSingleNode("c:axId", nsm).Attributes["val"].Value == "1")
{
var txPrNode = valAxisNode.SelectSingleNode("c:txPr", nsm) ?? valAxisNode.AppendChild(chartXml.CreateNode(XmlNodeType.Element, "c:txPr", chartNsUri));
var bodyPrNode = txPrNode.SelectSingleNode("a:bodyPr", nsm) ?? txPrNode.AppendChild(chartXml.CreateNode(XmlNodeType.Element, "a:bodyPr", mainNsUri));
//Set the rotation angle
var att = chartXml.CreateAttribute("rot");
att.Value = "-5400000";
bodyPrNode.Attributes.Append(att);
var att2 = chartXml.CreateAttribute("vert");
att2.Value = "horz";
bodyPrNode.Attributes.Append(att2);
txPrNode.AppendChild(chartXml.CreateNode(XmlNodeType.Element, "a:lstStyle", mainNsUri));
var pNode = chartXml.CreateNode(XmlNodeType.Element, "a:p", mainNsUri);
txPrNode.AppendChild(pNode);
var pPrNode = chartXml.CreateNode(XmlNodeType.Element, "a:pPr", mainNsUri);
pNode.AppendChild(pPrNode);
var defRPrNode = chartXml.CreateNode(XmlNodeType.Element, "a:defRPr", mainNsUri);
pPrNode.AppendChild(defRPrNode);
}
}
pck.Save();
}
}
You can get this:
The documentation for the rot or Rotation attribute is here:
Specifies the rotation that is being applied to the text within the bounding box. If it not specified, the rotation of the accompanying shape is used. If it is specified, then this is applied independently from the shape. That is the shape can have a rotation applied in addition to the text itself having a rotation applied to it. If this attribute is omitted, then a value of 0 is implied.
Consider the case where a shape has a rotation of 5400000, meaning 90 degrees clockwise, applied to it. In addition to this, the text body itself has a rotation of 5400000, or 90 degrees counter-clockwise, applied to it. Then the resulting shape would appear to be rotated but the text within it would appear as though it had not been rotated at all. The DrawingML specifying this would look like the following:
<p:sp>
<p:spPr>
<a:xfrm rot="5400000">
…
</a:xfrm>
</p:spPr>
…
<p:txBody>
<a:bodyPr rot="-5400000" … />
…
(Some text)
…
</p:txBody>
</p:sp>
https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.drawing.bodyproperties.rotation?view=openxml-2.8.1#DocumentFormat_OpenXml_Drawing_BodyProperties_Rotation
In EPPlus 5 at least (not sure about earlier versions), this can be done via the XAxis.TextBody.Rotation property. Be sure to set it between -90 and +90 for the values to align with the tick marks properly.
As an overview I am currently exporting data from my database and exporting it to an excel sheet.
I have formatted some of the cells (i.e Merged cells etc) in the excel sheet using ClosedXml, now I am little stuck with a small issue which I can get around as of now.
I want to fill the cells with a background color, but what is hindering is the merged cells. I am not able to color all the cells in the rows which are used by the merged cells.
The current output in the excel is somewhat like this:
The solutions I have tried fill the merged cells correctly, but the adjacent unmerged cells in the row arent all filled with the background color.
Could someone please give me an idea to go about this hurdle?
This is a sample POC code I have been working on,
private static void ToExcel(System.Data.DataTable dataTable, HttpResponseBase response, string fileName)
{
using (XLWorkbook wb = new XLWorkbook())
{
wb.CalculateMode = XLCalculateMode.Auto;
var ws = wb.Worksheets.Add(dataTable, "OKR Quater Report");
ws.Tables.FirstOrDefault().ShowAutoFilter = false;
var colRange = ws.Columns();
colRange.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Left;
colRange.Style.Alignment.Vertical = XLAlignmentVerticalValues.Center;
var headingCells = ws.Row(1).Cells();
headingCells.Style.Font.Bold = true;
headingCells.Style.Fill.SetBackgroundColor(XLColor.AirForceBlue);
headingCells.Style.Font.SetFontColor(XLColor.White);
ws.SheetView.FreezeRows(1);
ws.Column(3).Hide();
ws.Column(8).Hide();
for (int i = 2; i <= dataTable.Rows.Count + 1; i++)
{
for (int k = 1; k <= dataTable.Columns.Count - 4; k++)
{
if (ws.Column(k).IsHidden)
{
continue;
}
List<IXLCell> mergeRange = new List<IXLCell>();
int j = i;
while (j <= dataTable.Rows.Count + 1)
{
if (ws.Column(k).Cell(j).Value.ToString().Equals(ws.Column(k).Cell(j + 1).Value.ToString()) && ws.Column(1).Cell(j).Value.ToString().Equals(ws.Column(1).Cell(j + 1).Value.ToString())) //&& ws.Column(5).Cell(j).Value.ToString().Equals(ws.Column(5).Cell(j + 1).Value.ToString())
{
mergeRange.Add(ws.Column(k).Cell(j));
j++;
}
else
{
mergeRange.Add(ws.Column(k).Cell(j));
break;
}
}
if (mergeRange != null && mergeRange.Count > 0)
{
ws.Range(mergeRange.First(), mergeRange.Last()).Merge(false);
}
}
}
//Converting All string in the attachement column to Hyperlinks
for (int i = 2; i <= dataTable.Rows.Count + 1; i++)
{
if (!(ws.Column(10).Cell(i).Value.ToString().Equals(string.Empty)))
{
ws.Column(10).Cell(i).FormulaA1 = "=HYPERLINK" + ws.Column(10).Cell(i).Value.ToString();
}
}
//Writing datatable to Excel
MemoryStream stream = GetStream(wb);// The method is defined below
response.Clear();
response.Buffer = true;
response.AddHeader("content-disposition",
"attachment; filename=" + fileName + "_" + DateTime.Now.ToString() + ".xlsx;");
response.ContentType = "application/vnd.ms-excel";
response.BinaryWrite(stream.ToArray());
response.End();
}
}
You can use ws.MergedRanges to get a list of all the merged cells on the sheet. To find the merged range which includes a given cell, you can do something like this: ws.MergedRanges.First(r => r.Contains("B4")). Apply the styling to the entire range that you retrieve.
The "Print Preview" of a spreadsheet created with my EPPlus code shows the gutter/row number column (column 0, so to speak):
How can I programmatically prevent the gutter/row number ("crack?") column from printing?
My printing setup code is currently as follows:
private void ConfigureCustomerSheetForPrinting()
{
string columnName = GetExcelTextColumnName(customerWorksheet.Dimension.End.Column);
string printArea = string.Format("A1:{0}{1}", columnName, customerWorksheet.Dimension.End.Row);
customerWorksheet.PrinterSettings.PrintArea = customerWorksheet.Cells[printArea];
customerWorksheet.PrinterSettings.FitToPage = true;
customerWorksheet.PrinterSettings.Orientation = eOrientation.Landscape;
customerWorksheet.View.ZoomScale = 100;
customerWorksheet.PrinterSettings.FitToPage = true;
customerWorksheet.PrinterSettings.FitToHeight = 100;
customerWorksheet.PrinterSettings.Scale = 100;
customerWorksheet.PrinterSettings.LeftMargin = (decimal).5 / 2.54M;
customerWorksheet.PrinterSettings.RightMargin = (decimal).5 / 2.54M;
customerWorksheet.PrinterSettings.TopMargin = (decimal).5 / 2.54M;
customerWorksheet.PrinterSettings.BottomMargin = (decimal).5 / 2.54M;
customerWorksheet.PrinterSettings.HeaderMargin = (decimal).5 / 2.54M;
customerWorksheet.PrinterSettings.FooterMargin = (decimal).5 / 2.54M;
}
If I understand what you are asking for you want to show the Column headers ( say "Row 0" as "A", "B", "C", ...) but NOT show the Row headers (say "Column 0" as "1", "2" 3", etc.). If so, I have never seen a way to do it. You can hide both row/col header or show both but not either-or according to the DocumentFormat.OpenXml.Spreadsheet.PrintOptions. Basically the ShowHeaders option you and Richardo talked about.
The only decent work around I can think of is to fake it with something like this. This includes setting the first row as a repeat. I set the first row as frozen as well but this is optional:
using (var pck = new ExcelPackage(fi))
{
var wb = pck.Workbook;
var ws = wb.Worksheets.Add("Sheet1");
//Make sure headers are not show
ws.PrinterSettings.ShowHeaders = false;
//Header
ws.Cells[1, 1].Value = "A";
ws.Cells[1, 2].Value = "B";
ws.Cells[1, 3].Value = "C";
ws.Cells[1, 4].Value = "D";
var headerrange = ws.Cells[1, 1, 1, 4];
headerrange.Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
headerrange.Style.Border.Top.Style = ExcelBorderStyle.Thin;
headerrange.Style.Border.Bottom.Style = ExcelBorderStyle.Thin;
headerrange.Style.Border.Left.Style = ExcelBorderStyle.Thin;
headerrange.Style.Border.Right.Style = ExcelBorderStyle.Thin;
ws.View.FreezePanes(1,4);
ws.PrinterSettings.RepeatRows = new ExcelAddress("$1:$1");
//Some data > 1 page
for (var i = 0; i < 1000; i++)
{
ws.Cells[2 + i, 1].Value = DateTime.Now.AddDays(i);
ws.Cells[2 + i, 2].Value = i;
ws.Cells[2 + i, 3].Value = i*100;
ws.Cells[2 + i, 4].Value = Path.GetRandomFileName();
}
//Save it
pck.Save();
}
Which gives this in the output:
And this in print preview (I scrolled down a few pages):
There is a property called ShowHeaders in the PrinterSettings object that should do what you need. You don't seem to have it there so you might be missing that.
customerWorksheet.PrinterSettings.ShowHeaders = false;
customerWorksheet.View.ShowHeaders = false;
You can see this more explicitly in the source code in the ExcelPrinterSettings class.
/// <summary>
/// Print headings (column letter and row numbers)
/// </summary>
public bool ShowHeaders
{
get
{
return GetXmlNodeBool(_headersPath, false);
}
set
{
SetXmlNodeBool(_headersPath, value, false);
}
}
Hope it helps B. ;)