how to increment cells dynamically with Microsoft.Office.Interop.Excel - c#

I am trying to develop a reusable List to excel method. Using this example, "https://msdn.microsoft.com/en-us/library/dd264733.aspx"
I see the cells are being referenced individually like so,
workSheet.Cells[1, "A"] = "ID Number";
I want to be able to auto fill the column names, and also each cell from left to right dynamically. I would imagine there is a better way than having to type out "A", "B"....."A1" etc into the workSheet.Cells[] directly or even a better way than storing the alphabet into a list.
Here is what I have so far,
public static void DownloadExcelFile<T>(List<T> list, string fileName)
{
Excel.Application excelApp = new Excel.Application();
// Make the object visible.
excelApp.Visible = true;
excelApp.Workbooks.Add();
Excel._Worksheet workSheet = (Excel.Worksheet)excelApp.ActiveSheet;
//create column headings
foreach (System.ComponentModel.PropertyDescriptor descriptor in System.ComponentModel.TypeDescriptor.GetProperties(list))
{
//how can I reference workSheet.Cells by row, and have the
//column incremented somehow within the loop?
workSheet.Cells[1, "A"] = descriptor.name;
}
}

You can use the ordinal number instead of the letter code:
int colIndex = 1;
foreach (System.ComponentModel.PropertyDescriptor descriptor in System.ComponentModel.TypeDescriptor.GetProperties(list))
{
workSheet.Cells[1, colIndex++] = descriptor.Name;
}

Related

c# read specific columns from excel file

i have a tables like this
and i added checkboxs elements to form like this
i want to add the checkbox element text to datagridview then read the checked columns from excel file
if Date, Time, Price are checked datagridview will be like this
then get full Date column from excel file and add it to Date column in datagrid
my code to add checked boxes text as a columns in datagridview
DataTable dt = new DataTable();
foreach (Control checkbox in pnl.Controls)
if (checkbox.GetType() == typeof(CheckBox) && ((CheckBox) checkbox).Checked)
{
string txt = ((CheckBox)checkbox).Text;
dt.Columns.Add(new DataColumn(txt, typeof(object)));
}
datagrid.DataSource = dt;
There are a few steps which are needed before being able to grab data from an Excel file. So without your code, I don't know how much of this you have done. But here is the full explanation.
First
You have to add a reference to the Microsoft.Office.Interop.Excel dll (this assumes you aren't using epplus or another Nuget package). This link describes how to do this: How to reference Microsoft.Office.Interop.Excel dll?
Second
Include this library in whichever source file it is needed, and initialize an excel application (you'll also want InteropServices included):
using Microsoft.Office.Interop.Excel;
using System.Runtime.InteropServices;
// Global excel app object to be used anywhere
public Application ExcelApp;
// Intitializes an excel application by looking for an active one,
// and creating a new one if none are active
public void InitExcelApp()
{
try
{
ExcelApp = (Application)Marshal.GetActiveObject("Excel.Application")
}
catch(COMException ex)
{
ExcelApp = new Application
{
Visible = true
};
}
}
Third
You must initialize a workbook object. Here is how I do it, but my solution assumes you know the path to the desired Excel workbook:
Workbook myWorkbook = null;
// Checks open workbooks first
// Note that the path must be windows style. Ex: "C:\\Desktop\\myWorkbook.xlsx"
foreach (Workbook openWorkbook in ExcelApp.Workbooks)
{
if (openWorkbook.FullName == "<path to workbook>")
{
myWorkbook = openWorkbook;
}
}
// If no open workbooks were found at the known path, try opening one
if(myWorkbook is null)
{
myWorkbook = Excelapp.Workbooks.Open("<path to workbook>", Editable: true);
}
Fourth
Get the data you want. There are several ways to do this, and mine might not be the most efficient, but it works. In the code below I have included parameter names to hopefully make it more understandable.
// Gets the names of the checked items from the DataTable with columns you already added
// You could get these names from your checkboxes' names if you preferred
List<string> checkItems = new List<string>();
foreach (System.Data.DataColumn column in dt.Columns)
{
checkItems.Add(column.ColumnName);
}
// This dictionary holds info helpful for getting the correct data from excel:
// Key: a string containing the name of the column header, i.e. Date, Time, Price, etc.
// Value: an integer containing the number of that column in excel
Dictionary<string, int> excelColumnsInfo = new Dictionary<string, int>();
for (int columnNum = 1; columnNum <= myWorkbook.UsedRange.Columns.Count; columnNum++)
{
string columnHeader = myWorkbook.Cells[RowIndex: 1, ColumnIndex: columnNum].Value2.ToString();
if (checkedItems.Contains(columnHeader))
{
excelColumnsInfo.add(columnHeader, columnNum);
}
}
// Populates the data table with the data you need
// Start at row 2 to ignore the excel sheet's column headers
for (int rowNum = 2; rowNum <= myWorkbook.UsedRange.Rows.Count; rowNum++)
{
System.data.dataRow newRow = dt.NewRow();
foreach (KeyValuePair<string, int> columnInfo in excelColumnsInfo)
{
newRow[columnName: columnInfo.Key] = myWorkbook.Cells[RowIndex: rowNum, ColumnIndex: columnInfo.Value].Value2.ToString();
}
dt.Rows.Add(newRow);
}

Aspose.Cells: initialize empty workbook, workbook.Worksheets[0].Cells has no cells in it

Here's my code:
var workbook = new Workbook();
var sheet = workbook.Worksheets[0];
var row = 1;
var column = 1;
sheet.Cells.GetCell(row, column).Value = "Date";
This causes a null reference error because GetCell() returned null. Is this normal behavior? How can I properly initialize a workbook with a single blank worksheet, such that sheet.Cells.GetCell(1, 1) will not be null?
GetCell() method returns null when the cell has not been created earlier. However, Worksheet.Cells[r, c] will always return cell object because it returns the cell object if it already exists, otherwise it first creates it and then returns the cell object. It means, Worksheet.Cells[r, c] will never return null.
Please execute the following code at your end. The code explains, first time, GetCell() methods return null but second time, it returns cell object because it has already been created by Worksheet.Cells[r, c].
Please read the comments for your more help.
C#
//Create empty workbook.
Workbook wb = new Workbook();
//Access first worksheet
Worksheet ws = wb.Worksheets[0];
//This will return null because the cell is not initialized before.
Cell c = ws.Cells.GetCell(2, 5);
//This will automatically create cell object, so it will never return null.
c = ws.Cells[2, 5];
//Now execute the previous statement, this time, GetCell() will also return cell object
//because it has been created by ws.Cells[2, 5]
c = null;
c = ws.Cells.GetCell(2, 5);
Note: I am working as Developer Evangelist at Aspose

Writing a excel using closed XML - adding custom column names

I need to write a list of objects to excel sheet as a table, in which each column represents object attributes or values. To the below method, Im passing column names in a separate List and data objects in a List, I managed to get the data displayed like below, but still I could not get the columns to display properly.
I referred the below documentation, but I could not find a way to get the titles display properly.
https://github.com/closedxml/closedxml/wiki/Inserting-Tables
Code
public string CreateExcelFile<T>(IEnumerable<T> list, string sheetName, string headerTitle, List<string> titles, string fileName, string savedPath)
{
var wb = new XLWorkbook();
var ws = wb.Worksheets.Add(sheetName);
ws.Cell(1, 1).Value = headerTitle; // sets excel sheet header
var rangeTitle = ws.Range(3, 1, 3, titles.Count); // range for row 3, column 1 to row 3, column titles.Count
rangeTitle.AddToNamed("Titles");
// Need to add columns names with in rangeTitle
//rangeTitle.InsertData(titles);
// write data from row 4 onwards
if (list != null && list.Any())
{
ws.Cell(4, 1).InsertData(list);
}
else
{
ws.Cell(4, 1).Value = "No data to show";
}
// styles
var titlesStyle = wb.Style;
titlesStyle.Font.Bold = true;
titlesStyle.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;
titlesStyle.Fill.BackgroundColor = XLColor.Amber;
// style titles row
wb.NamedRanges.NamedRange("Titles").Ranges.Style = titlesStyle;
ws.Columns().AdjustToContents();
var filePath = savedPath + string.Format("{0}.xlsx", fileName);
wb.SaveAs(filePath);
return filePath;
}
Output excel
Output Im trying to get - I need to get values stored in titles in the Yellow highlighted row.
Can anyone help?
You could use InsertTable. The data is inserted as an Excel Table:
ws.Cell(1, 1).InsertTable(list.AsEnumerable());
I managed to get the columns to display by doing below.
// Need to add columns names with in rangeTitle
for (int i = 0; i < titles.Count; i++)
{
var columnNumber = i + 1;
ws.Cell(3, columnNumber).Value = titles[i];
}
This works for now. But, I wonder is there a better way to doing things (without manually assigning column names like above).
ws.Cell(3, 1).Value = new [] { titles };
If you set Value to an array, ClosedXML will write each object in the array to its own row, with one property of the object per column. (See https://github.com/ClosedXML/ClosedXML/wiki/Copying-IEnumerable-Collections)
In this case, the array we're passing in has only one object – an array of titles. That inner array gets written to the target row, and each item in the inner array gets written to a column in that row.

C# to generate automatically updating Excel charts

I have a Windows Form with a data grid view where I can input some data.
My C# code simply reads these data from the data grid view, processes it and then needs to plot the results.
In particular, the results are stored in a list. There are also some additional data (which are intermediate results of the calculations) that are stored in two dimensional arrays.
The point where I'm stuck is the plotting. I want to do this in Excel and I want to make it update dynamically whenever I change some input in the data grid view.
The code below open an Excel workbook and pastes the data of the list in column A.
how can I add the two dimensional array in column B and C?
how can I plot these columns in a line chart?
how can I make the Excel chart update automatically as soon as I update some value in my data grid view (without opening every time a new Excel workbook)?
Thank you for the help.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using Excel = Microsoft.Office.Interop.Excel;
namespace NewPoject
{
class plotter
{
public void plotGraphExcel_2D(List<double> x, double[,] y, double[,] yUP, double[,] yDOWN)
{
Excel.Application xlApp;
Excel.Workbook workbook;
Excel.Worksheet sheet;
object misValue = System.Reflection.Missing.Value;
xlApp = new Excel.Application();
xlApp.Visible = true;
workbook = xlApp.Workbooks.Add(misValue);
sheet = (Excel.Worksheet)workbook.Worksheets.get_Item(1);
var range = sheet.get_Range("A1", "A1");
range.Value2 = "Scores";
//now the list
string cellName;
int counter = 2;
foreach (var item in x)
{
cellName = "A" + counter.ToString();
var range2 = sheet.get_Range(cellName, cellName);
range2.Value2 = item.ToString();
++counter;
}
// How can I save the results of the array y in column B and C?
// How can I plot a line chart with the values I have pasted in column A, B and C?
// How can I make it update automatically when I change some value in the data grid view?
}
}
}

Export on .xlsxm file

In my WinApp I export data to a specific tab of an Excel spreadsheet, in which there are macros (file extension .xlxm).
In this workbook, the data is always inserted from the same cell when it is empty, but it can happen that has already had the previous entries, so you have to retrieve the first available blank cell on the new line after the one that has already had the data inserted. The sequence of entries in the cells is similar to the following: in cells A1: A3, and then such as A10: A15, dropping the cells A4 to A9 because they are cells with formulas. I would to add that I must to control every cell of workbook for to fill in data from winApp. I hope to be able to explain the scenario.
You could use a library such as EPPlus from NuGet to achieve this. Something like this would do the trick.
static void Main(string[] args)
{
List<string> ExampleData = new List<string> { "my", "intestesting", "data" };
using (ExcelPackage package = new ExcelPackage(new FileInfo(#"C:\Temp\example.xlsm")))
{
ExcelWorksheet ws = package.Workbook.Worksheets["MySheet"];
int lastRowIndex = ws.Dimension.End.Row;
int idx = lastRowIndex + 1;
foreach (var datum in ExampleData)
{
ws.Cells[idx, 1].Value = datum;
idx++;
}
package.Save();
}
}

Categories

Resources