Create Excel VBA code and button programmatically from C# - c#

I am in the middle of simple method, that saves my DataGridView into an Excel document (1 sheet only) and also adds VBA code and a button to run the VBA code.
public void SaveFile(string filePath)
{
Microsoft.Office.Interop.Excel.ApplicationClass ExcelApp = new Microsoft.Office.Interop.Excel.ApplicationClass();
ExcelApp.Application.Workbooks.Add(Type.Missing);
//Change Workbook-properties.
ExcelApp.Columns.ColumnWidth = 20;
// Storing header part in Excel.
for (int i = 1; i < gridData.Columns.Count + 1; i++)
{
ExcelApp.Cells[1, i] = gridData.Columns[i - 1].HeaderText;
}
//Storing Each row and column value to excel sheet
for (int row = 0; row < gridData.Rows.Count; row++)
{
gridData.Rows[row].Cells[0].Value = "Makro";
for (int column = 0; column < gridData.Columns.Count; column++)
{
ExcelApp.Cells[row + 2, column + 1] = gridData.Rows[row].Cells[column].Value.ToString();
}
}
ExcelApp.ActiveWorkbook.SaveCopyAs(filePath);
ExcelApp.ActiveWorkbook.Saved = true;
ExcelApp.Quit();
}
I only implemented DataGridView export.
EDIT: Thanks to Joel I could, with proper words, search again for the solution. I think that this may be helpful. Would you correct me or give a tip or two about what I should look for.

I just wrote a small example which adds a new button to an existing workbook and afterwards add a macro which will be called when the button is clicked.
using Excel = Microsoft.Office.Interop.Excel;
using VBIDE = Microsoft.Vbe.Interop;
...
private static void excelAddButtonWithVBA()
{
Excel.Application xlApp = new Excel.Application();
Excel.Workbook xlBook = xlApp.Workbooks.Open(#"PATH_TO_EXCEL_FILE");
Excel.Worksheet wrkSheet = xlBook.Worksheets[1];
Excel.Range range;
try
{
//set range for insert cell
range = wrkSheet.get_Range("A1:A1");
//insert the dropdown into the cell
Excel.Buttons xlButtons = wrkSheet.Buttons();
Excel.Button xlButton = xlButtons.Add((double)range.Left, (double)range.Top, (double)range.Width, (double)range.Height);
//set the name of the new button
xlButton.Name = "btnDoSomething";
xlButton.Text = "Click me!";
xlButton.OnAction = "btnDoSomething_Click";
buttonMacro(xlButton.Name, xlApp, xlBook, wrkSheet);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
xlApp.Visible = true;
}
And here we got the buttonMacro(..) method
private static void buttonMacro(string buttonName, Excel.Application xlApp, Excel.Workbook wrkBook, Excel.Worksheet wrkSheet)
{
StringBuilder sb;
VBIDE.VBComponent xlModule;
VBIDE.VBProject prj;
prj = wrkBook.VBProject;
sb = new StringBuilder();
// build string with module code
sb.Append("Sub " + buttonName + "_Click()" + "\n");
sb.Append("\t" + "msgbox \"" + buttonName + "\"\n"); // add your custom vba code here
sb.Append("End Sub");
// set an object for the new module to create
xlModule = wrkBook.VBProject.VBComponents.Add(VBIDE.vbext_ComponentType.vbext_ct_StdModule);
// add the macro to the spreadsheet
xlModule.CodeModule.AddFromString(sb.ToString());
}
Found this information within an KB article How To Create an Excel Macro by Using Automation from Visual C# .NET

Related

Referencing an Excel file, workbook, worksheet in C#

All,
I have been struggling to simply reference an Excel file so that I can extract its data into a new worksheet automatically.
I know this means to create a new Excel file and its items:
Excel.Application oXL;
Excel._Workbook oWB;
Excel._Worksheet oSheet;
Excel.Range oRng;
//Start Excel and get Application object.
oXL = new Excel.Application();
oXL.Visible = true;
//Get a new workbook.
oWB = (Excel._Workbook)(oXL.Workbooks.Add(Missing.Value));
oSheet = (Excel._Worksheet)oWB.ActiveSheet;
But this is where I am lost...I want the user to select another Excel file through a file dialog and then I want to copy data from said file into the new workbook above.
Ex: New file, user selects "MyExcel.csv". How would I reference this so that I can, say, copy Column A into the new worksheet? Whatever works with C#.
Maybe this helps:
Make sure your manage your Nugets and add the reference "Microsoft.Office.Interop.Excel" --> (References (Right click) --> Manage Nuget Packages --> Browse --> "Microsoft.Office.Interop.Excel" --> Install)
Note: This is is a copy paste into the same worksheet. To copy the data into another worksheet from another file just pass the "worksheet" as parameter to the method and paste it there.
public class Excel1
{
private readonly string excelSufix = ".xlsx";
private readonly string excelFilePrefix = "..."; //Where you excel file is located
private string getFilePath(string fileName)
{
return excelFilePrefix + fileName + excelSufix; //returns the file path by the given file name
}
public void CopyPaste(string fileName, int worksheet, string toCopyRange, string whereInsertRange)
{
//Range should look like = "A:C" or "D:F"
var excelApp = new Microsoft.Office.Interop.Excel.Application();
excelApp.Visible = true;
var workBook = excelApp.Workbooks.Open(getFilePath(fileName));
var workSheet = (Microsoft.Office.Interop.Excel.Worksheet)workBook.Sheets[worksheet];
var toCopy = workSheet.Range[toCopyRange];
var whereInsert = workSheet.Range[whereInsertRange];
whereInsert.Insert(Microsoft.Office.Interop.Excel.XlInsertShiftDirection.xlShiftToRight, toCopy.Cut());
}
}
Edit: You could add a constructor to the class where you pass the file Path and some class variables which reference the file, the worksheet etc etc... In this case, you will have independent objects for each file
Based on your description, you want to copy one column from the csv file and paste in the new excel file.
First, I convert the csv file to datatable.
Second, I select the specific column and convert one column to datatable.
Third, I convert the datatable to the new excel file.
You can try the following code.
using System;
using System.Data;
using Excel = Microsoft.Office.Interop.Excel;
class Program
{
static void Main(string[] args)
{
string path = "D:\\t.csv";
DataTable table = ReadCsv(path);
table= new DataView(table).ToTable(false, "Tests");
ExportToExcel(table, "D:\\t.xlsx");
}
public static DataTable ReadCsv(string path)
{
Microsoft.Office.Interop.Excel.Application objXL = null;
Microsoft.Office.Interop.Excel.Workbook objWB = null;
objXL = new Microsoft.Office.Interop.Excel.Application();
objWB = objXL.Workbooks.Open(path);
Microsoft.Office.Interop.Excel.Worksheet objSHT = objWB.Worksheets[1];
int rows = objSHT.UsedRange.Rows.Count;
int cols = objSHT.UsedRange.Columns.Count;
DataTable dt = new DataTable();
int noofrow = 1;
for (int c = 1; c <= cols; c++)
{
string colname = objSHT.Cells[1, c].Text;
dt.Columns.Add(colname);
noofrow = 2;
}
for (int r = noofrow; r <= rows; r++)
{
DataRow dr = dt.NewRow();
for (int c = 1; c <= cols; c++)
{
dr[c - 1] = objSHT.Cells[r, c].Text;
}
dt.Rows.Add(dr);
}
objWB.Close();
objXL.Quit();
return dt;
}
public static void ExportToExcel( DataTable tbl, string excelFilePath = null)
{
try
{
if (tbl == null || tbl.Columns.Count == 0)
throw new Exception("ExportToExcel: Null or empty input table!\n");
// load excel, and create a new workbook
var excelApp = new Excel.Application();
excelApp.Workbooks.Add();
// single worksheet
Excel._Worksheet workSheet = excelApp.ActiveSheet;
// column headings
for (var i = 0; i < tbl.Columns.Count; i++)
{
workSheet.Cells[1, i + 1] = tbl.Columns[i].ColumnName;
}
// rows
for (var i = 0; i < tbl.Rows.Count; i++)
{
// to do: format datetime values before printing
for (var j = 0; j < tbl.Columns.Count; j++)
{
workSheet.Cells[i + 2, j + 1] = tbl.Rows[i][j];
}
}
// check file path
if (!string.IsNullOrEmpty(excelFilePath))
{
try
{
workSheet.SaveAs(excelFilePath);
excelApp.Quit();
Console.WriteLine("Excel file saved!");
}
catch (Exception ex)
{
throw new Exception("ExportToExcel: Excel file could not be saved! Check filepath.\n"
+ ex.Message);
}
}
else
{ // no file path is given
excelApp.Visible = true;
}
}
catch (Exception ex)
{
throw new Exception("ExportToExcel: \n" + ex.Message);
}
}
}
Initial csv file.
The excel file:

Extract values from a list and save it to an existing Excel sheet in c#

I have an existing Excel sheet which has headers. I get data from my server and place it in my WPF DataGrid and it looks like this:
On a click of a button, I need to place the values from my list to a particular sheet in my existing Excel workbook. I can actually get the values from a WINFORM DataGrid like this:
var xlApp = new Excel.Application();
Excel.Worksheet sheet = new Excel.Worksheet();
xlApp.Visible = true;
var path = #"D:\Reports\Tag_History.xlsx";
sheet = xlApp.Application.Workbooks.Open(path).Worksheets["Summary"];
var rowCount = dataGrid.Items.Count;
var rowColumn = dataGrid.Columns.Count;
for (int i = 0; i < rowCount - 1; i++)
{
for (int j = 0; j < 7; j++)
{
if (dataGrid[j, i].ValueType == typeof(string))
{
xlsht.Cells[i + 2, j + 1] = "'" + dataGrid[j, i].Value.ToString();
}
else
{
xlsht.Cells[i + 2, j + 1] = dataGrid[j, i].Value.ToString();
}
}
}
but since I am trying to do this in WPF, this code does not work anymore. This is by transferring dataGrid data to an existing excel file. Since I think that transferring list to an existing excel file is better, I have to try this. This is what I have so far:
var xlApp = new Excel.Application();
Excel.Worksheet sheet = new Excel.Worksheet();
xlApp.Visible = true;
var path = #"D:\Reports\Tag_History.xlsx";
sheet = xlApp.Application.Workbooks.Open(path).Worksheets["Summary"];
var range = sheet.Range["A2", "A2"];
foreach (var item in summaryList)
{
range.Value2 = item.TagNumber;
}
This code works but it is only updating a single cell of the excel file.
Can you please show me how to do this? Thank you.
Install Microsoft.Office.Interop.Excel Nuget package in your application. Right-click on your project -> "References" and choose "Manage NuGet Packages...", then just search for Excel. Otherwise, select Tools -> Nuget Package Manager -> Package Manager Console -> then install the Excel nuget (https://www.nuget.org/packages/Microsoft.Office.Interop.Excel/).
Bind the items in DataGrid and then export data to excel as like below,
private void btnExport_Click(object sender, RoutedEventArgs e)
{
Microsoft.Office.Interop.Excel.Application excel = null;
Microsoft.Office.Interop.Excel.Workbook wb = null;
object missing = Type.Missing;
Microsoft.Office.Interop.Excel.Worksheet ws = null;
Microsoft.Office.Interop.Excel.Range rng = null;
// collection of DataGrid Items
var dtExcelDataTable = ExcelTimeReport(txtFrmDte.Text, txtToDte.Text, strCondition);
excel = new Microsoft.Office.Interop.Excel.Application();
wb = excel.Workbooks.Add();
ws = (Microsoft.Office.Interop.Excel.Worksheet)wb.ActiveSheet;
ws.Columns.AutoFit();
ws.Columns.EntireColumn.ColumnWidth = 25;
// Header row
for (int Idx = 0; Idx < dtExcelDataTable.Columns.Count; Idx++)
{
ws.Range["A1"].Offset[0, Idx].Value = dtExcelDataTable.Columns[Idx].ColumnName;
}
// Data Rows
for (int Idx = 0; Idx < dtExcelDataTable.Rows.Count; Idx++)
{
ws.Range["A2"].Offset[Idx].Resize[1, dtExcelDataTable.Columns.Count].Value = dtExcelDataTable.Rows[Idx].ItemArray;
}
excel.Visible = true;
wb.Activate();
wb.SaveCopyAs("excel file location");
wb.Saved = true;
excel.Quit();
}

Reading docx file with table

I have a simple document with one table in it. I would like to read its cells content. I found many tutorials for writing, but none for reading.
I suppose I should enumerate sections, but how to know which contains a table?
var document = DocX.Create(#"mydoc.docx");
var s = document.GetSections();
foreach (var item in s)
{
}
I'm using the following namespace aliases:
using excel = Microsoft.Office.Interop.Excel;
using word = Microsoft.Office.Interop.Word;
You can specifically grab the tables using this code:
private void WordRunButton_Click(object sender, EventArgs e)
{
var excelApp = new excel.Application();
excel.Workbooks workbooks = excelApp.Workbooks;
var wordApp = new word.Application();
word.Documents documents = wordApp.Documents;
wordApp.Visible = false;
excelApp.Visible = false;
// You don't want your computer to actually load each one visibly; would ruin performance.
string[] fileDirectories = Directory.GetFiles("Some Directory", "*.doc*",
SearchOption.AllDirectories);
foreach (var item in fileDirectories)
{
word._Document document = documents.Open(item);
foreach (word.Table table in document.Tables)
{
string wordFile = item;
appendName = Path.GetFileNameWithoutExtension(wordFile) + " Table " + tableCount + ".xlsx";
//Not needed if you're not going to save each table individually
var workbook = excelApp.Workbooks.Add(1);
excel._Worksheet worksheet = (excel.Worksheet)workbook.Sheets[1];
for (int row = 1; row <= table.Rows.Count; row++)
{
for (int col = 1; col <= table.Columns.Count; col++)
{
var cell = table.Cell(row, col);
var range = cell.Range;
var text = range.Text;
var cleaned = excelApp.WorksheetFunction.Clean(text);
worksheet.Cells[row, col] = cleaned;
}
}
workbook.SaveAs(Path.Combine("Some Directory", Path.GetFileName(appendName)), excel.XlFileFormat.xlWorkbookDefault);
//Last arg can be whatever file extension you want
//just make sure it matches what you set above.
workbook.Close();
Marshal.ReleaseComObject(workbook);
tableCount++;
}
document.Close();
Marshal.ReleaseComObject(document);
}
//Microsoft apps are picky with memory. Make sure you close and release each instance once you're done with it.
//Failure to do so will result in many lingering apps in the background
excelApp.Application.Quit();
workbooks.Close();
excelApp.Quit();
Marshal.ReleaseComObject(workbooks);
Marshal.ReleaseComObject(excelApp);
wordApp.Application.Quit();
wordApp.Quit();
Marshal.ReleaseComObject(documents);
Marshal.ReleaseComObject(wordApp);
}
The document is the actual word document type (word.Document). Make sure you check for split cells if you have them!
Hope this helps!
If you only have one table in document it should be rather simple. Try this:
DocX doc = DocX.Load("C:\\Temp\\mydoc.docx");
Table t = doc.Table[0];
//read cell content
string someText = t.Rows[0].Cells[0].Paragraps[0].Text;
You can loop through table rows and table cells inside each row, and also through Paragraphs inside each Cells[i] if there are more paragraphs. You can do that with simple for loop:
for (int i = 0; i < t.Rows.Count; i++)
{
someText = t.Rows[i].Cells[0].Paragraphs[0].Text;
}
Hope it helps.

C# not creating the excel file and cannot write in different excel sheets

First of all in my code im opening an excel sheet and reading it into a list. Second of all im closing this excel sheet and creating a new excel sheet:
excel_init("C:\\Users\\oma\\Desktop\\excel2.xlsx"); // this path does NOT exist yet
Next its going to this method:
static void excel_init(String path)
{
appExcel = new Microsoft.Office.Interop.Excel.ApplicationClass();
if (System.IO.File.Exists(path))
{
// then go and load this into excel
newWorkbook_First = appExcel.Workbooks.Open(path, true, true);
objsheet = (_Worksheet)appExcel.ActiveWorkbook.ActiveSheet;
}
else
{
try
{
appExcel = new Microsoft.Office.Interop.Excel.ApplicationClass();
appExcel.Visible = true;
newWorkbook_First = appExcel.Workbooks.Add(1);
objsheet = (Microsoft.Office.Interop.Excel.Worksheet)newWorkbook_First.Sheets[1];
objsheet.Name = ("test");
var newSheet3 = (Microsoft.Office.Interop.Excel.Worksheet)appExcel.Worksheets.Add(Type.Missing, appExcel.Worksheets[appExcel.Worksheets.Count], 1, XlSheetType.xlWorksheet);
newSheet3.Name = "test2";
var newSheet2 = (Microsoft.Office.Interop.Excel.Worksheet)appExcel.Worksheets.Add(Type.Missing, appExcel.Worksheets[appExcel.Worksheets.Count], 1, XlSheetType.xlWorksheet);
newSheet2.Name = "test3";
}
catch (Exception e)
{
Console.Write("Error");
}
finally
{
}
}
}
It wont create excel2.xlsx on my desktop, why not?
Next in my main I am shouting excel_setValue this way:
excel_setValue("C", "hello", "");
This is the excel_setValue function:
static void excel_setValue(string cellname, string value, string color)
{
objsheet.get_Range(cellname).set_Value(Type.Missing, value);
if (kleur == "red")
{
objsheet.get_Range(cellname).Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.Red);
}
}
How do I add the sheet to this? For exmaple: excel_setValue(cellname, value, color, sheetname)
Finally I do excel_close();
the excel_close function:
static void excel_close()
{
if (appExcel != null)
{
try
{
newWorkbook_First.Close();
System.Runtime.InteropServices.Marshal.ReleaseComObject(appExcel.ActiveWorkbook.ActiveSheet);
System.Runtime.InteropServices.Marshal.ReleaseComObject(appExcel.ActiveWorkbook);
System.Runtime.InteropServices.Marshal.ReleaseComObject(appExcel);
appExcel = null;
objsheet = null;
}
catch (Exception ex)
{
appExcel = null;
Console.WriteLine("Unable to release the Object " + ex.ToString());
}
finally
{
GC.Collect();
}
}
}
It closes and ask me if I wanna save/not-save or cancel it. And it will save # documents with no errors given
I create my Excel like this worked fine for me!
You need to do the folowing in you code before the newWorkbook_First.close(); part:
newWorkbook_First.SaveAs(totalPath);
I hope this will help you solve the problems..
using Excel = Microsoft.Office.Interop.Excel;
internal static bool ExportDGV(DataGridView DGV, List<string> selectedCustomerList, string path, string fileName, string exportName, int exportType, string mailSubject)
{
string totalPath;
//Create an Excel application instance
Excel.Application excelApp = new Excel.Application();
Excel.Workbook excelWorkBook = excelApp.Application.Workbooks.Add();
Excel._Worksheet worksheet = null;
excelApp.Visible = false;
worksheet = excelWorkBook.ActiveSheet;
//set headers
for (int i = 1; i < DataGridView.Columns.Count + 1; i++)
{
worksheet.Cells[1, i] = DGV.Columns[i - 1].HeaderText;
}
createList(worksheet, DGV);
//Create excel with the choosen name
Worksheet sheet1 = excelWorkBook.Worksheets[1];
worksheet.Name = fileName;
totalPath = path + "/" + fileName + ".xlsx";
//if path exist add a number
totalPath = directoryExist(totalPath, path, fileName);
//Save exel and Quit exelApp
excelWorkBook.SaveAs(totalPath);
excelWorkBook.Close();
excelApp.Quit();
}
You can use EpPlus library for excel. It is very easy to use and well documented. You don't need to use COM classes anymore

How to export datagridview into Open Office Excel c#

I have a datagridview and i can export the same to Microsoft Excel. Now i want to export the datagridview to Open Office Excel. I cant figure out what assemblies are to be used in reference for my project for Open Office. For Microsoft Excel i used the following reference followed by the code of the event.
using Excel=Microsoft.Office.Interop.Excel;
private void exportToMSExcelToolStripMenuItem_Click(object sender, EventArgs e)
{
try
{
Microsoft.Office.Interop.Excel._Application app = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel._Workbook workbook = app.Workbooks.Add(Type.Missing);
Microsoft.Office.Interop.Excel._Worksheet worksheet = null;
app.Visible = true;
worksheet = workbook.Sheets["Sheet1"];
worksheet = workbook.ActiveSheet;
worksheet.Name = "Exported from .net app";
for (int i = 1; i < datagridEC.Columns.Count + 1; i++)
{
worksheet.Cells[1, i] = datagridEC.Columns[i - 1].HeaderText;
}
for (int i = 0; i < datagridEC.Rows.Count; i++)
{
for (int j = 0; j < datagridEC.Columns.Count; j++)
{
worksheet.Cells[i + 2, j + 1] = datagridEC.Rows[i].Cells[j].Value.ToString();
}
}
}
catch (Exception ex)
{
MessageBox.Show("ERROR--> " + ex.Message.ToString(), "ERROR");
}
finally
{
}
}
This works fine for Microsoft Office but now i would like to replace it for Open Office Excel.
You need to add references for following assembles: cli_basetype, cli_cppihelper, cli_oootypes, cli_ure, cli_uretypes
And also
using unoidl.com.sun.star.lang;
using unoidl.com.sun.star.bridge;
using unoidl.com.sun.star.frame;
using unoidl.com.sun.star.beans;
using UNO = unoidl.com.sun.star.uno;
using OOo = unoidl.com.sun.star;
using unoidl.com.sun.star.text;
using unoidl.com.sun.star.container;
using unoidl.com.sun.star.sheet;
using unoidl.com.sun.star.table;
And also example how to get a worksheet:
UNO.XComponentContext context = uno.util.Bootstrap.bootstrap();
XMultiServiceFactory SrvManager = (XMultiServiceFactory)context.getServiceManager();
XComponentLoader loader = (XComponentLoader)SrvManager.createInstance("com.sun.star.frame.Desktop");
string AFile = "file:///" + "filePath";
PropertyValue[] props = new PropertyValue[0];
XComponent oDoc = loader.loadComponentFromURL(AFile, "_blank", 0, props);
XSpreadsheetDocument xSpreadDoc = (XSpreadsheetDocument)oDoc;
XSpreadsheets xSheets = xSpreadDoc.getSheets();
XIndexAccess xIA = (XIndexAccess)xSheets;
XSpreadsheet xSheet = (XSpreadsheet)xIA.getByIndex(0).Value;

Categories