I have a UWP app that I am developing in Visual Studio. It successfully makes api calls and returns data. So far I have only bound this data to grid views for displaying. Now however I would like to add a "save" function that will export this data to an excel document.
Any thoughts on how I could go about this ?
Any help is greatly appreciated.
I would advise you NOT to use excel directly, but use a different approach; try to get a nuget package to do the work for you (handling excel etc). Excel itself (as interop library) is a pain in the proverbial but cheeks.
A good one : https://www.nuget.org/packages/EPPlus/
You can still use the same data you get for your grid, but export it to excel. There are numerous examples to be found for above mentioned EPPLus.
try this
private void button_SAVE(object sender, EventArgs e)
{
// creating Excel Application
Microsoft.Office.Interop.Excel._Application app = new Microsoft.Office.Interop.Excel.Application();
// creating new WorkBook within Excel application
Microsoft.Office.Interop.Excel._Workbook workbook = app.Workbooks.Add(Type.Missing);
// creating new Excelsheet in workbook
Microsoft.Office.Interop.Excel._Worksheet worksheet = null;
// see the excel sheet behind the program
app.Visible = true;
// get the reference of first sheet. By default its name is Sheet1.
// store its reference to worksheet
worksheet = workbook.Sheets["Sheet1"];
worksheet = workbook.ActiveSheet;
// changing the name of active sheet
worksheet.Name = "Exported from gridview";
// storing header part in Excel
for (int i = 1; i < dataGridView1.Columns.Count + 1; i++)
{
worksheet.Cells[1, i] = dataGridView1.Columns[i - 1].HeaderText;
}
// storing Each row and column value to excel sheet
for (int i = 0; i < dataGridView1.Rows.Count - 1; i++) {
for (int j = 0; j < dataGridView1.Columns.Count; j++) {
worksheet.Cells[i + 2, j + 1] = dataGridView1.Rows[i].Cells[j].Value.ToString();
}
}
// save the application
workbook.SaveAs("c:\\output.xls", Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlExclusive, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
// Exit from the application
app.Quit();
See Sunteen's reply in this post. There are exist libraries which can do this.(Example doc)
If you want to create csv yourself, there is a blog about parsing CSV.
Related
From a console application using C# I am trying to open a new Excel workbook and add data to it. I can open a new workbook fine, but I am running into issues adding data to the workbook because my range object is null, and I can't seem to hook into the excel workbook that was just opened. I tried a variation of ActiveWorkbook, Sheets[1] and a couple of others and I can't seem to figure it out
using Microsoft.Office.Interop.Excel;
using System.Reflection;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Application xl = null;
_Workbook wb = null;
// Option 1
xl = new Application();
xl.Visible = true;
wb = (_Workbook)(xl.Workbooks.Add(XlWBATemplate.xlWBATWorksheet));
Worksheet sheet = xl.ActiveWorkbook.ActiveSheet;
Range cell = sheet.Cells[1, 1];
//ERROR on cell.Value("Test");
cell.Value("Test");
}
}
}
This code may be help you.
using (SaveFileDialog sfd = new SaveFileDialog() { Filter = "Excel Workbook|*.xls" })
{
if (sfd.ShowDialog() == DialogResult.OK)
{
// creating Excel Application
Microsoft.Office.Interop.Excel._Application app = new Microsoft.Office.Interop.Excel.Application();
// creating new WorkBook within Excel application
Microsoft.Office.Interop.Excel._Workbook workbook = app.Workbooks.Add(Type.Missing);
// creating new Excelsheet in workbook
Microsoft.Office.Interop.Excel._Worksheet worksheet = null;
// see the excel sheet behind the program
app.Visible = true;
// get the reference of first sheet. By default its name is Sheet1.
// store its reference to worksheet
worksheet = workbook.Sheets["Sheet1"];
worksheet = workbook.ActiveSheet;
// changing the name of active sheet
worksheet.Name = "Exported from gridview";
// storing header part in Excel
for (int i = 1; i < DGView.Columns.Count + 1; i++)
{
worksheet.Cells[1, i] = DGView.Columns[i - 1].HeaderText;
}
// storing Each row and column value to excel sheet
for (int i = 0; i < DGView.Rows.Count - 1; i++)
{
for (int j = 0; j < DGView.Columns.Count; j++)
{
worksheet.Cells[i + 2, j + 1] = DGView.Rows[i].Cells[j].Value.ToString();
}
}
// save the application
workbook.SaveAs(sfd.FileName, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlExclusive, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
// Exit from the application
app.Quit();
}
}
I used this code in my work for saving datagridview as excel sheet and it has been worked well.
Good day to all.
I am trying to merge all the sheets of multiple excel files into one excel file. I have successfully did it using below code:
string folder = textBox1.Text;
string[] xlsxfiles = Directory.GetFiles(folder, "*.xlsx");
Excel.Application app = new Excel.Application();
app.Visible = true;
Excel.Workbook finalWB = app.Workbooks.Add("");
Excel.Workbook tempWB = app.Workbooks.Add(xlsxfiles);
for (int i = 2; i <= app.Workbooks.Count; i++)
{
for (int j = 1; j <= app.Workbooks[i].Worksheets.Count; j++)
{
Excel.Worksheet ws = app.Workbooks[i].Worksheets[j];
ws.Copy(app.Workbooks[1].Worksheets[1]);
}
}
However, the workbooks "tempWB" are still open and some of them got their filenames "1" added at the end (e.g.Book1.xlsx becomes Book11.xlsx).
I've already tried:
tempWB.Close();
but it is not closing the ones with "1" added to their filenames.
Is there a code that I can use to close all open excel files except one (finalWB in my code)?
Thank you in advanced for the ususal help.
I think app.Workbooks.Close(); needs to be called at the end to close all the open workbooks is there are any.
I have successfully closed all excel sheets by Saving As first the active workbook then run
app.Workbook.Close()
my code looks like below
finalWB.SaveAs(excelReportSaveas, Microsoft.Office.Interop.Excel.XlFileFormat.xlWorkbookDefault, Type.Missing, Type.Missing,
false, false, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlNoChange,
Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
app.Workbooks.Close();
Thank you Gowri for the reply.
I like to delete rows from multiple worksheet in Excel. Currently my code only delete rows from active worksheet. I am looking for a specific value on the cell then when I find this value then I am deleting all the rows up to that value that stored on that row.
Code
private void button2_Click(object sender, EventArgs e)
{
Microsoft.Office.Interop.Excel.Application Excel = new Microsoft.Office.Interop.Excel.Application();
Workbook workBook = Excel.Workbooks.Open(FilePath);
Worksheet ws = (Worksheet)Excel.ActiveSheet;
for (int j = 1; j <= 10; j++)
{
for (int i = 1; i <= 20; i++)
{
if (Convert.ToString(((Microsoft.Office.Interop.Excel.Range)ws.Cells[j, i]).Value2) == "Matter")
{
for (int r = 1; r <= j; r++)
{
((Range)ws.Rows[r]).Delete(XlDeleteShiftDirection.xlShiftUp);
MessageBox.Show(Convert.ToString(r));
workBook.SaveAs(#"C:\Users\Separate\New.xlsx", Microsoft.Office.Interop.Excel.XlFileFormat.xlWorkbookDefault, Type.Missing, Type.Missing,
false, false, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlNoChange,
Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
}
}
}
}
workBook.Close(Type.Missing, Type.Missing, Type.Missing);
Excel.Quit();
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(Excel);
Excel = null;
}
I would highly suggest trying to use ClosedXML as it makes working with Excel so much easier. Specifically with ClosedXML you can have a line like this:
ws.Row(5).Delete();
where ws is your initialized worksheet, and it handles the heavy lifting for deleting that row.
Getting or setting cell data is just as simple:
ws.Cell(2, 2).Value = "Initial Value";
or alternatively
ws.Cell("B2").Value = "Value;
They also have type specific value assignment like this:
ws.Cell("B2").SetValue<T>(object);
The documentation is very thorough, and you can get the package through nuget (note it requires the DocumentFormat.OpenXML package installed as well)
EDIT:
I missed the part about multiple worksheets so here it is. The XLWorkbook type has a property Worksheets, which is an enumerable of all the worksheets in the workbook. Use this to get the worksheets you want to delete rows on
I am trying to export 2 datagridviews to excel but it is missing the last line of data for both of the sets of data grid views, I have checked the code and I cant see what I have done wrong? Also it is creating a temporary file when exporting and then locking the file and not exiting gracefully and only a reboot allows you to delete the file? Any help would be great code is below. For example if i save as test.xlsx I get 2 files ~$test.xlsx and test.xlsx and both both files are locked.
private void exprtbtn_Click(object sender, EventArgs e)
{
Microsoft.Office.Interop.Excel._Application app = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel._Workbook workbook = app.Workbooks.Add(Type.Missing);
try
{
// creating new Excelsheet in workbook
Microsoft.Office.Interop.Excel._Worksheet worksheet1 = null;
Microsoft.Office.Interop.Excel._Worksheet worksheet2 = null;
// get the reference of first sheet. By default its name is Sheet1.
// store its reference to worksheet
worksheet1 = workbook.Sheets["Sheet1"];
worksheet1 = workbook.ActiveSheet;
// changing the name of active sheet
worksheet1.Name = "Switch Totals";
// storing header part in Excel
for (int i = 1; i < switchtotalgrd.Columns.Count + 1; i++)
{
worksheet1.Cells[1, i] = switchtotalgrd.Columns[i - 1].HeaderText;
}
// storing Each row and column value to excel sheet
for (int i = 0; i < switchtotalgrd.Rows.Count - 1; i++)
{
for (int j = 0; j < switchtotalgrd.Columns.Count; j++)
{
worksheet1.Cells[i + 2, j + 1] = switchtotalgrd.Rows[i].Cells[j].Value.ToString();
}
}
// Adding second worksheet
int count = workbook.Worksheets.Count;
Excel.Worksheet addedSheet = workbook.Worksheets.Add(Type.Missing,
workbook.Worksheets[count], Type.Missing, Type.Missing);
// get the reference of first sheet. By default its name is Sheet1.
// store its reference to worksheet
worksheet2 = workbook.Sheets["Sheet2"];
worksheet2 = workbook.ActiveSheet;
// changing the name of active sheet
worksheet2.Name = "Itemised Extn";
// storing header part in Excel
for (int i = 1; i < fullresult.Columns.Count + 1; i++)
{
worksheet2.Cells[1, i] = fullresult.Columns[i - 1].HeaderText;
}
// storing Each row and column value to excel sheet
for (int i = 0; i < fullresult.Rows.Count - 1; i++)
{
for (int j = 0; j < fullresult.Columns.Count; j++)
{
if (fullresult.Rows[i].Cells[j].Value == null)
{
fullresult.Rows[i].Cells[j].Value = "NA";
}
worksheet2.Cells[i + 2, j + 1] = fullresult.Rows[i].Cells[j].Value.ToString();
}
}
// save the application
string fileName = String.Empty;
SaveFileDialog saveFileDialog1 = new SaveFileDialog();
saveFileDialog1.Filter = "Excel files |*.xls|All files (*.*)|*.*";
saveFileDialog1.FilterIndex = 2;
saveFileDialog1.RestoreDirectory = true;
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
fileName = saveFileDialog1.FileName;
workbook.SaveAs(fileName, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlExclusive, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
}
else
return;
}
//Catch all errors.
catch (System.Exception)
{
}
finally
{
workbook = null;
app = null;
}
}
You probably might want to double-check your outer for loop again, e.g. for (int i = 0; i < fullresult.Rows.Count - 1; i++), shouldn't it be using less than and equal perhaps?
Since you are using Excel com interop, you will need to call this method to be able to release the resource after you are done with it, Marshal.ReleaseComObject.
A good practice is to use try{...}catch{...}finally{...}, and release com object in the finally block.
I have this code that export an excel file using c# from 1 listview. My problem now is if I have 2 listviews that will be generated in 1 excel file, my plan is listview1 is for sheet1 and listview2 is for sheet2.
this is my code generates listview1 to excel into sheet1:
string[] st = new string[listView1.Columns.Count];
DirectoryInfo di = new DirectoryInfo(Environment.ExpandEnvironmentVariables("%USERPROFILE%") + #"\Desktop\");
if (di.Exists == false)
di.Create();
fileName f = new fileName();
if (f.ShowDialog() == DialogResult.OK)
{
StreamWriter sw = new StreamWriter(Environment.ExpandEnvironmentVariables("%USERPROFILE%") + #"\Desktop\" + f.Filenam + ".xls", false);
sw.AutoFlush = true;
string header = "";
for (int col = 0; col < listView1.Columns.Count; col++)
{
header += listView1.Columns[col].Text.ToString() + "\t";
}
sw.Write(header);
int rowIndex = 1;
int row = 0;
string st1 = "";
for (row = 0; row < listView1.Items.Count; row++)
{
if (rowIndex <= listView1.Items.Count)
rowIndex++;
st1 = "\n";
for (int col = 0; col < listView1.Columns.Count; col++)
{
st1 = st1 + listView1.Items[row].SubItems[col].Text.ToString() + "\t";
}
sw.Write(st1);
}
sw.Close();
FileInfo fil = new FileInfo(Environment.ExpandEnvironmentVariables("%USERPROFILE%") + #"\Desktop\" + f.Filenam + ".xls");
if (fil.Exists == true)
MessageBox.Show("Process Completed", "Export to Excel", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
I have used EPPlus, its free, give performance benefits, and provides many Excel functions. Other option you can look for is Microsoft InterOp for Excel export, but it has performance problems.
As Irfan already mentioned, you could do that with Microsoft.Office.Interop
Excel.Application xlsApp = new Excel.Application();
Excel.Workbook workbook;
workbook = xlsApp.Workbooks.Open(configuration.XLSExportedFile, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
foreach (Excel.Worksheet sheet in workbook.Sheets)
{
workbook.Activate();
sheet.Activate();
}
That would help you to step through all your sheets in your Excel file.
Now in case you want to expand it with multiple sheets, you can read C# how to add Excel Worksheet programmatically Office XP / 2003 in order to find how to add additional sheets.
What you could do now, is put your text into a variable for example HTML or any kind of information from your listbox.
string html = Clipboard.GetText(TextDataFormat.Html);
Now you can play around with the Clipboard(alternative solution, but to avoid).
Clipboard.SetText(html);
It actually enters information into your Clipboard, what you could do is pass all your listbox values into the Clipboard.
And now the final step would be to paste it at the position that you want.
sheet.Range(cellmapp).PasteSpecial();
Where cellmap is supposed to be for example A1. In case your text that you have in your listbox is too long you can adapt your rows/columns.
//Auto fits all columns and rows
//https://stackoverflow.com/questions/14748322/c-sharp-autofit-method-for-excel-sheet
sheet.Columns.AutoFit();
sheet.Rows.AutoFit();
Don't forget, if you work with COM processes, close every object and file.
workbook.SaveAs(configuration.XLSExportedFile);
workbook.Close();
xlsApp.Quit();
xlsApp.Dispose();
I don't say that would be the best solution to do, but you could look up for OpenXML also.
I've used ClosedXML before, the syntax is really clean and simple and you can get this sort of task done in just a few lines
This block shows how to add a list to a new sheet and save it
List<string> list = new List<string>();
var workbook = new XLWorkbook();
var worksheet = workbook.Worksheets.Add("Sample Sheet");
worksheet.Cell(1, 1).Value = list;
workbook.SaveAs("HelloWorld.xlsx");