EPPlus - Get file name from worksheet - c#

I am using EPPlus to create Excel files. I need to get the name of the file containing a worksheet from an ExcelWorksheet or ExcelWorkbook object. I can't find any "name" property in the ExcelWorkbook object, or any way of getting from an ExcelWorkbook or ExcelWorksheet back to the containing ExcelPackage.
Is there a property or path of properties I can use to get from ExcelWorksheet to a file name?
To clarify my intent:
I am creating an API that will create table difference reports. It mainly works with ADO.NET DataTables, but it also has adapters that take interop Worksheets or EPPlus ExcelWorksheets, which it will convert to DataTables for processing.
I only need the file name containing the ExcelWorksheet so that it can be printed on the output report for clarity. The API is only really working at the scope of DataTables or objects that are roughly equivalent to tables, like Worksheets or ExcelWorksheets. It doesn't deal with DataSets, Workbooks, ExcelWorkbooks, or ExcelPackages (except when it outputs a report file using EPPlus).
So, I would very much like the API functions to require a bare minimum of parameters, like DataTables, Worksheets, ExcelWorksheets, and some bitflag options. It would also be nice to have the different overloads of the functions take analogous parameters (i.e. taking two DataTables or two Worksheets, or two ExcelWorksheets), and not require extra clutter parameters for the EPPlus input case.
With interop, it is extremely easy to get a file name from a Worksheet (mySheet.Parent.Name), and EPPlus provides easy ways to move down the object hierarchy (myPackage.Workbook.Worksheets[1]), so I assumed there would be some way to move back up the hierarchy from an ExcelWorksheet object.

As suggested by Donald Jansen in the comments, the solution is to edit the EPPlus source code.
Add the following properties to ExcelWorkbook.cs:
//Get the package containing this workbook.
public ExcelPackage Package { get { return _package; } }
//Get the name of the file of this workbook.
public String Name { get { return _package.File.Name; } }
Now you can scale up and down the object hierarchy to your heart's content.

Related

What is the easiest way to count .xlsx workbook sheets using c#, NPOI and an XSSF workbook?

I am trying to count the number of sheets in a workbook. The workbook is created using NPOI and there doesn't seem to be a way to count the amount of sheets using the C# version of NPOI?
This is a really tricky thing to both explain and show... But I will give it a try.
What I am trying to do is having an existing excel-file as a template for statistics. This existing excel-file can have different amounts of templates and I need to be able to count these templates to know where to place my new sheets and edit their names.
The sender of the data only has to chose which template-sheet should be filled with which data, and I will then remove the template-sheets from the workbook after all data has been inserted.
What I have tried:
I have read the documentation and searched for information and have tried the following approaches:
getNumberOfSheets - How to know number of sheets in a workbook?
Problem with this approach: The C# version of NPOI doesn't seem to have getNumberOfSheets.
Convert found row-counters into sheet-counters - NPOI - Get excel row count to check if it is empty
Can't really recreate the code to work for sheets as the functionality for sheets and rows are too different.
var sheetIndex = 0;
foreach (var sheet in requestBody.Sheets)
{
if (sheet.TemplateNumber == "")
{
sheetTemplate = templateWorkbook.CreateSheet(sheet.Name);
}
else
{
sheetTemplate = templateWorkbook.CloneSheet(Convert.ToInt32(sheet.SheetTemplate));
if (!templates.Contains(Convert.ToInt32(sheet.SheetTemplate)))
{
templates.Add(Convert.ToInt32(sheet.SheetTemplate));
}
// Do math's to make sure we add the name to the newly created sheet further down the code (I need to actual index here)
}
// Insert statistics
//After inserting statistics:
workingCopy.SetSheetName(sheetIndex, sheet.Name);
foreach (var template in templates)
{
workingCopy.RemoveSheetAt(template);
}
}
You can get number of sheets from NumberOfSheets property in XSSFWorkbook class.

Excel Interop: Get named table (Range) from specific workbook

I'm trying to create a WinForms application that interacts with Excel using the Excel Object Library v.15.
I'm using this to get the Excel Application object
(Application)System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application");
And I know I can get the Range for the named table I want by using
_application.Range["MyTableName"];
Now, the problem I'm facing is that if I have two workbooks opened at the same time and each one of them has a named table with the same name, I don't know which Range will be returned.
The Excel application is unique, so I cannot simply try to get the process based on the window title or something like that.
I can get the Workbook object based on its title:
_application.Workbooks.Cast<Workbook>().FirstOrDefault(w.Name.Equals(title))
However I cannot access the Ranges of a particular Workbook.
I know I could iterate through the Sheets of the Workbook element trying to find the table but I was wondering if there was another "cleaner" way.
I would appreciate any guideline on this.
Thanks,
Will
The simplest/most direct way I can think of would be to iterate through the Names collection, check the parent, and move on.
E.g:
For Each NamedRange as Range in MyApplication.Names
Dim Check as Object = TryCast(NamedRange.Parent, Workbook)
If Check Is Nothing Then
Check = TryCast(NamedRange.Parent, Worksheet)
Check = TryCast(Check.Parent, Workbook)
End If
If Not Check Is Nothing AndAlso Check.Name = "MyWorkbook" Then
'Do something
End If
Next

Save specific pages of an Excel workbook

I have one workbook with three sheets. Each sheet got 3 pages. What I want to reach is: I want to save only the first page of each sheet.
I can only count those pages with
int numberOfPages = 0;
foreach(Excel.Worksheet sheet in excelWorkbook.Sheets)
{
numberOfPages += sheet.PageSetup.Pages.Count;
}
But I cant find a way how to save these pages. Is there a way?
Here is how to copy a worksheet:
Excel.Worksheet worksheet1 = ((Excel.Worksheet)Application.ActiveWorkbook.Worksheets[1]);
Excel.Worksheet worksheet3 = ((Excel.Worksheet)Application.ActiveWorkbook.Worksheets[3]);
worksheet1.Copy(worksheet3);
Hope that helps.
I'd suggest using the Macro Recorder in such cases (which is available in Excel). The required VBA code can generated automatically in the background for you. Most probably you will need to correct it because an auto-generated code is not well-optimized, but at least you will have an idea what properties and methods should be used to get the job done. See Create or delete a macro for more information.

How to get data from C# to Excel smoothly using VSTO and back again

I'm writing an application level add-in for Excel in C#.
The add-in is to be used for getting data from a foreign source (the add-in provides some GUI options for this etc.) into Excel. This data is not going to be updated and sent back to the data source or anything like that - although the user is of course free to edit the data in the local Excel application.
The data arrives in an XML format and currently I have used a code generation tool to be able to deserialize the xml documents into C# objects. The data follows a relational model.
The things I'm thinking about right now:
Should I translate everything to a DataSet object with DataTables?
If I've done that, how can I then get this data into an Excel sheet? Is it possible to e.g. create a table in excel and databind to my datatables/dataset?
Really I don't think I want a "table" per se but just throw in the data into cells and the user can then work with the cells. Is it better then to just supply 2D arrays? But won't it be a pain to go from DataTable data rows to 2D arrays?
Some other questions as well...
What is the easiest/best way to read data back from Excel to C#? I think I'd mostly be satisfied with just getting 2D arrays here. But traversing the "Range" objects seems cumbersome. Must be some better way?
The sheet will likely have column names in the first row and then data in the rest of the rows. Is there any way for the C# code to recognize this when the user has selected the cells that make up my "table"? Or is this just something I'm going to have to take care of manually in the code?
I've never worked with this before so apologizing if some questions seem stupid. Any help is appreciated.
Here are some example from my previous work to open excel and get data from excel:
public class ExcelModule
{
private Excel.Application excelApp;
private Excel.Workbook excelBook;
private Excel.Worksheet excelSheet;
object misValue = System.Reflection.Missing.Value;
object oMissing = System.Reflection.Missing.Value;
public ExcelModule()
{
}
public void OpenWorksheet(string fileName, int sheetNum)
{
excelApp = new Excel.Application();
excelBook = excelApp.Workbooks.Open(fileName,
0,
true,
5,
"",
"",
true,
Microsoft.Office.Interop.Excel.XlPlatform.xlWindows,
"\t",
false,
false,
0,
true,
1,
0);
excelSheet = (Excel.Worksheet)excelBook.Worksheets.get_Item(sheetNum);
}
public string GetValue(string cellAddress)
{
if (excelSheet.get_Range(cellAddress, cellAddress).Value2 != null)
return excelSheet.get_Range(cellAddress, cellAddress).Value2.ToString();
else
return "";
}
public int Close()
{
excelApp.Quit();
return 0;
}
~ExcelModule()
{
excelApp.Quit();
}
}
To write data into Excel you may use:
excelSheet.get_Range(cellAddress, cellAddress).Value2 = "your text";
Notes:
*I'm using VS10 with Office2007
Not sure why my question was downvoted... At least give reasons, how else can they become better next time around?
Anyway. The best solution, it seems to me, is to get my data into a DataSet and then create a ListObject in the Excel application and use it's data binding features to get my data into Excel.
Was not aware of this great control before.
Using range along with 2d array in Excel will give you beter performance. Here as you are deserializing incoming xml to object, there is no need to convert it into dataset then to 2d array. Would recommend in view layer of your code you directly tranform your object to 2d array and then bind with range in excel sheet. For reading back read data into 2d array from range and then tranform it back to object which you can serialize and send it back to server. Now how effectively or exactly you use range or array will depend on how data in your sheet looks. To distinguish between header and data you may have a look at named range, it can be helpful.
Excel tables (aka "ListObjects") give you formatting for free, and they are easy to use. The corresponding type is ListObject.
You can use them with LINQ, without having to manufacture a DataSet object:
ListObject myTable; // usually declared somewhere else, eg. via the designer
var data = from x in myObjects select new
{
Foo = x.Foo,
Bar = x.Bar
};
myTable.SetDataBinding(data.ToList());
This will fill the table with your data using reflection. In the example above, you will have two columns titled Foo and Bar, and as many rows as you had elements in myObjects.
Of course, you can use more complex queries. In your case, using Linq to XML is probably a good idea. The point is that you can do exactly what you want in a handful of lines.
Also, you can put any IList<object> into SetDataBinding.

Importing an Excel WorkSheet into a Datatable

I have been asked to create import functionality in my application. I am getting an excel worksheet as input. The worksheet has column headers followed by data. The users want to simply select an xls file from their system, click upload and the tool deletes the table in the database and adds this new data.
I thought the best way would be too bring the data into a datatable object and do a foeach for every row in the datatable insert row by row into the db.
My question is what can anyone give me code to open an excel file, know what line the data starts on in the file, and import the data into a datable object?
Take a look at Koogra.
You instantiate a WorkBook object from a path to an XLS file.
You access a WorkSheet object from the workbook's Sheets property.
You can enumerate over the rows in the worksheet by accessing the sheet's Rows property from index MinRow to MaxRow.
You can enumerate over the cells in a given row by accessing the row's Cells property from index MinColumn to MaxColumn.
Each cell has a Value property (object) as well as a FormattedValue method (string).
Give it a try -- I've found it to be extremely intuitive and easy to use.
You can make use of an OleDbConnection to connect to excel file and the query it using SQL queries.
If it is an Asp.Net application, then you make use of the FileUpload control and get the bytes from the file. Then you will have to manually convert it to a datatable.
Try out these links:
OleDbConnection to excel file
Byte array to datatable
What your looking for is the concept described Here
Providing you dont want to use a third party library anyway, else Dans solution will suit you
First you have to download the dll file namely
NExcel.dll
By using this dll you can make various object which are very useful for
import excel data in .net using both vb as well as c#.
Good luck.

Categories