I want to use EPPlus to input data and calculate it.
Here is my code:
ExcelWorksheet sheet = ep.Workbook.Worksheets["input"];
sheet.Cells[1, 1].Value = 10;
ep.Workbook.Calculate();
string test = sheet.Cells[1, 5].Text;
ep.Save();
The string test is "#NAME?"
It seems that EPPlus did not load user define function.
When I open the saved file, the calculation will be done automatically.
What should I do to make the user defined function work?
(I'll use this feature later in the ASP.NET to call User define functions in exist excel file.I tried Interop, it can achieve what I want, but a lot slower.)
Thanks!
The formula calc engine in EPPlus cannot execute VBA functions in the workbook. It supports approx. 150 common built in Excel formulas and nothing more than that.
However, you can implement your VBA functions in .NET code. Each function should inherit the EPPlus class ExcelFunction and be registred to EPPlus via the Workbook.FormulaParserManager given the same function name as your VBA functions.
There are samples that illustrates this (create custom functions) in the EPPlus Samples project which can be downloaded from Codeplex.
For version 4.1, you can download the solution "EPPlus with samples" here:
https://epplus.codeplex.com/releases/view/625020
Then goto the "EPPlusSamples" project and check out SampleAddFormulaFunction.cs
You need to create a vba project in Epplus which is where you would define the function. Something like this:
var fileinfo = new FileInfo(#"c:\temp\UserDefinedFunctionTest.xlsm");
if (fileinfo.Exists)
fileinfo.Delete();
var sb = new StringBuilder();
sb.AppendLine("Function test(a)");
sb.AppendLine(" test = a * 3");
sb.AppendLine("End Function");
using (var package = new ExcelPackage(fileinfo))
{
var workbook = package.Workbook;
var worksheet = workbook.Worksheets.Add("Sheet1");
workbook.CreateVBAProject();
var mod1 = workbook.VbaProject.Modules.AddModule("Module1");
mod1.Code = sb.ToString();
worksheet.Cells["A1"].Value = 5;
worksheet.Cells["A2"].Formula = "=test(A1)";
package.Save();
}
Which will look like this:
You need to set formula in ExcelWorkSheet
sheet.Cells[5, 5].Formula = "=A1*3";
This is for first row only , if you want to do in Large number of rows then you have to use loop and inside loop use formula.
Related
I need to be able to convert all charts in an excel spreadsheet to images programmatically (via c#),
I've tried Aspose.cells and it works perfectly, but i need a free alternative.
EPplus and other non-commercial libraries i know do not have the ability to do this,
and i'm in an web environment so I cannot use Office Interop.
My question is: is there any way I can programmatically read an .xlsx file and swap every chart it contains for an image of said chart, without depending on a paid library ?
Try Spire.Xls
var wb = new Spire.Xls.Workbook();
var sheet=wb.Worksheets[0];
//Replace charts with png
var charts = summarySheet.Charts.Select(x => (Chart)x).ToArray();
if (charts.Any())
{
var imgs = wb.SaveChartAsImage(summarySheet); //same indexes as chart obj arr
for (int i = 0; i <= charts.Length - 1; i++)
{
var chart = charts[i];
var chartImg = imgs[i];
summarySheet.Pictures.Add(chart.TopRow, chart.LeftColumn, chartImg, 100, 100, ImageFormatType.Png);
}
}
Have you tried ClosedXML.Excel in nuget?
XLSX support
using (var workbook = new XLWorkbook())
{
var worksheet = workbook.Worksheets.Add("Sample Sheet");
worksheet.Cell("A1").Value = "Hello World!";
worksheet.Cell("A2").FormulaA1 = "=MID(A1, 7, 5)";
workbook.SaveAs("HelloWorld.xlsx");
}
source https://github.com/ClosedXML/ClosedXML
I'm having trouble copying a formula from one cell to another using EPPlus. I want the copy to change the formula based on the cell position. I've tried using the copy function and I've tried copying the FormulaR1C1 property. Either way the formula gets corrupted.
To reproduce error copy this formula into cell(1,1) of an excel file named c:\test\in.xlsx =VLOOKUP(B1,Sheet2!A:B,2,FALSE)
using System.IO;
using OfficeOpenXml;
namespace eptest
{
class Program
{
static void Main(string[] args)
{
ExcelPackage ep = null;
ExcelWorksheet ws = null;
ep = new ExcelPackage(new FileInfo("c:\\test\\in.xlsx"));
ws = ep.Workbook.Worksheets["Sheet1"];
ws.Cells[1, 1].Copy(ws.Cells[2, 1]);
//ws.Cells[2, 1].FormulaR1C1 = ws.Cells[1, 1].FormulaR1C1; //this doesn't work either
ep.SaveAs(new FileInfo("c:\\test\\out.xlsx"));
}
}
}
I think you found a bug. The issue is here:
https://github.com/JanKallman/EPPlus/blob/d09fd3516b01c9fc6d6500ab9ff0ed82a60fab7b/EPPlus/ExcelCellBase.cs#L988
Since there is a delta of 1 row between the source cell and the destination, the UpdateFormulaReferences is eventually called and tries to adjust the formula. But the part of the formula that is A:B is the entire range which it does NOT correctly recognize and chews it up. I will open up an issue on their GitHub page.
To get around it, do this:
//This does a literal string copy
ws.Cells[1, 1].Copy(ws.Cells[2, 1], ExcelRangeCopyOptionFlags.ExcludeFormulas);
ws.Cells[2, 1].Formula = ws.Cells[1, 1].Formula;
This avoids a call to that function and then does a literal copy of the forumla. Cannot use the R1C1 since it also tries to adjust the formula.
I got Excel xlsx document with hyperlinks.
Hyperlinks have adresses and subaddresses (that's the way VBA call Html fragments, all after # sign)
Epplus library has Hyperlink property for every cell, but it has only first part of html address, so instead of
stackoverflow.com#footer
I got:
stackoverflow.com
Is there any way to read the html fragment part with this library ?
Code for reading hyperlinks via epplus:
FileInfo xlsxFile = new FileInfo(_filePath);
using (ExcelPackage pck = new ExcelPackage(xlsxFile))
{
var wb = pck.Workbook;
if (wb == null)
return null;
var ws = wb.Worksheets.FirstOrDefault();
ExcelRange er = ws.Cells[0,0];
var hyperlink = er.Hyperlink;
It seems to be an issue with the way excel store hyperlinks and the way Epplus reads them. Excel stores the hyperlinks both in the worksheet itself as well as the relationship file for the worksheet which is a file that stores any kind of cross referencing between workbook parts (worksheets, styles, strings, etc). This all has to do with the structure of the an xlsx file which is xml based off of the OpenOffice XML standard: OpenOffice XML Info
So the problem is Epplus is relying on that relationship file which does not contain the fragment while the `hyperlink' node in the worksheet xml does. You can see all of this in its gory detail if you open up the xlsx file as a zip file by renaming it.
So, the short answer is you are forced to use the `.Value' of the cell object. Not as clean but it will work. For example, if I create a cell like this:
with this code:
var fi = new FileInfo(#"c:\temp\Html_Fragment.xlsx");
using (var pck = new ExcelPackage(fi))
{
var wb = pck.Workbook;
var ws = wb.Worksheets.FirstOrDefault();
ExcelRange er = ws.Cells[1,1];
var hyperlink = er.Hyperlink;
Console.WriteLine(er.Value);
Console.WriteLine("{{Value: {0}, Hyperlink: {1}}}", er.Value, er.Hyperlink.AbsoluteUri);
}
Gives this:
{
Value: https://msdn.microsoft.com/en-us/library/aa982683(v=office.12).aspx#Anchor_3,
Hyperlink: https://msdn.microsoft.com/en-us/library/aa982683(v=office.12).aspx
}
I have a C# data processing application which uses EPPlus to write the final results into an excel sheet. The background color of the rows are changed based on what the data on that row signifies. Time was never an issue as I only dealt with files that were below <100MB before. However, as my requirements have changed and the files get larger, I have noticed that.. just coloring makes my application 60% slower. Removing coloring makes the application significantly faster. The snippet below is an example of the code which I use to color the data to make it visually distinguishing. I'm no expert at EPPlus but is there a way, this can be optimized to make my application faster? Or are there any better ways for me to make the rows visually distinct for the people who will end up looking at the data? Any help will be appreciated!
if (data[4] == "3")
{
// color the type 3 messages here
var fill1 = cell1.Style.Fill;
fill1.PatternType = ExcelFillStyle.Solid;
fill1.BackgroundColor.SetColor(Color.LightGray);
}
if (data[4] == "4")
{
var fill1 = cell1.Style.Fill;
fill1.PatternType = ExcelFillStyle.Solid;
fill1.BackgroundColor.SetColor(Color.BlanchedAlmond);
}
EDIT:
This is the code I use to copy the template and write the excel data into the new worksheet. p is an Excel Package which I convert to a byte Array before writing to the excel file.
Byte[] bin = p.GetAsByteArray();
File.Copy("C:\\Users\\mpas\\Desktop\\template.xlsx", "C:\\Users\\mpas\\Desktop\\result.xlsx");
using (FileStream fs = File.OpenWrite("C:\\Users\\mpas\\Desktop\\result.xlsx")) {
fs.Write(bin, 0, bin.Length);
}
Styling is much faster in EPPlus, and most Excel APIs, if you use named styles. Assign and use the style to cell in EPPlus like this ...
internal static string YourStyleName = "MyStyle";
ExcelNamedStyleXml yourStyle = excel.Workbook.Styles.CreateNamedStyle(YourStyleName);
yourStyle.Style.Font.Color.SetColor(Color.DarkRed);
yourStyle.Style.Fill.PatternType = ExcelFillStyle.Solid;
yourStyle.Style.Fill.BackgroundColor.SetColor(Color.LemonChiffon);
// ...
sheet.Cells[sourceRange].StyleName = YourStyleStyleName
Here is code to open an existing file.
FileInfo AddressList = new FileInfo("c:\test\test.xlsx");
// Open and read the XlSX file.
try
{
using (ExcelPackage package = new ExcelPackage(AddressList))
{
// Get the work book in the file
ExcelWorkbook workBook = package.Workbook;
if (workBook != null)
{
if (workBook.Worksheets.Count > 0)
{
// Get the first worksheet
//ExcelWorksheet Worksheet = workBook.Worksheets.First();
var worksheet = package.Workbook.Worksheets[1];
I have a datatable with larger than 300.000 row, i want export this datatable to excel 2003 but don't use Excel COM. I have used NPOI but it raise error OutOfMemory. I'm finding a thirt party component (free) can export for each row and write directly to file to avoid out of memory. Who can help me? thanks.
How about a csv file ? It is readable from Excel.
Try this Libs. I am not sure about the capacity
http://ehl.codeplex.com/
http://excelexportlib.codeplex.com/
You can export to an excel-file with the use of a webgrid (only in code). Under the assumption that you're creating a WinForm-application, you will have to make a reference to the System.Web library.
// Create the DataGrid and perform the databinding
var myDataGrid = new System.Web.UI.WebControls.DataGrid();
myDataGrid.HeaderStyle.Font.Bold = true;
myDataGrid.DataSource = myDataTable;
myDataGrid.DataBind();
string myFile = "put the name here with full path.xls"
var myFileStream = new FileStream( myFile, FileMode.Create, FileAccess.ReadWrite );
// Render the DataGrid control to a file
using ( var myStreamWriter = new StreamWriter( myFileStream ) )
{
using (var myHtmlTextWriter = new System.Web.UI.HtmlTextWriter(myStreamWriter ))
{
myDataGrid .RenderControl( myHtmlTextWriter );
}
}
I haven't tested it with so many records, so I don't know the impact of this memory-wise.
Edit:
Take note of the comment of #Charles Williams that excel 2003 has a row limitation