I have an excel application, that gets consolidated lists from SharePoint using power query. I have set the property to refresh on open of the excel application, to refresh the dataset. When I manually open the excel, it refreshes and i get the updated data. However, I am using this excel in my winform application to get the data.
So in order to refresh the data, i am trying to open and close the excel from code.
But the data doesn't get refreshed, and it screws up the power query addin. When I manually open the excel sheet again, after running the code i get the error "The query did not run, or the database table could not be opened."
And the Power Query is not seen anymore on the ribbon.
Below is the code i use to open and close the Excel application:
Excel.Application excelApp = new Excel.Application();
excelApp.Visible = true;
string workbookPath = #"C:\Test\Test.xlsx";
Excel.Workbook excelWorkbook = excelApp.Workbooks.Open(workbookPath,
0, false, 5, "", "", false, Excel.XlPlatform.xlWindows, "",
true, false, 0, true, false, false);
Excel.Sheets excelSheets = excelWorkbook.Worksheets;
string currentSheet = "Sheet1";
Excel.Worksheet excelWorksheet = (Excel.Worksheet)excelSheets.get_Item(currentSheet);
Excel.Range excelCell = (Excel.Range)excelWorksheet.get_Range("A1", "A2");
excelWorkbook.Close(true, "Test.xlxs", null);
Is this the best way to refresh the data?
If your Power Query/BI implementation does not allow usage of the Data Management Gateway (DMG) as suggested by a previous poster, you may want to explore a new piece of software called Power Update to set the update to a schedule.
Plus you may be able to run their Excel data-source update tasks from within your C# application if this is part of the requirement.
Two things to be aware of.
Connections in excel default to background (asynchronous) refresh, which can make your programmatic refresh code non-deterministic.
Power Query does polling to update the status of the query refresh. So if you close the workbook right after the refresh the status won't have a chance to update and next time you open the workbook the status will indicate an error.
In order to get a reliable refresh, you will need to set the connections to no longer background refresh, so the refresh blocks, and then also sleep for a short time after the refresh to let Power Query's polling discover that the refresh is complete.
I would change your script to this
Excel.Application excelApp = new Excel.Application();
excelApp.Visible = true;
string workbookPath = #"C:\Test\Test.xlsx";
Excel.Workbook excelWorkbook = excelApp.Workbooks.Open(workbookPath,
0, false, 5, "", "", false, Excel.XlPlatform.xlWindows, "",
true, false, 0, true, false, false);
excelWorkbook.RefreshAll();
System.Threading.Thread.Sleep(2000);
excelWorkbook.Close(true, "Test.xlxs", null);
You could make this code even better by looping through the queries and setting them to not background refresh like this vba code does
https://social.technet.microsoft.com/Forums/en-US/9cbdd731-d139-49ee-8f30-89de371ba74d/multiple-queries-run-one-after-another?forum=powerquery#df2947a7-585a-4f75-8337-e0ead5068254
Related
I have a Excel Sheet that i need to copy into Data table and later insert into Mysql Database table.I am trying to use Microsoft.Office.Interop.Excel.here is the codes that i have tried.
Workbook workbook = new Workbook();
Microsoft.Office.Interop.Excel.DataTable dataTable = sheet.ExportDataTable();
But i dont know how to import sheet from the directory.I am trying these things in Windows Form Application.
Please help me.
Assuming you're trying to open an existing Excel file from the file system, here's a link to a CodeProject article on how to manipulate Excel files using C#. This snippet of code is right on the article's page showing how to open an existing Excel spreadsheet:
string workbookPath = "c:/SomeWorkBook.xls";
Excel.Workbook excelWorkbook = excelApp.Workbooks.Open(workbookPath,
0, false, 5, "", "", false, Excel.XlPlatform.xlWindows, "",
true, false, 0, true, false, false);
As you can see, you have to use the Application object's Workbooks property to open the Workbook and add it to the Workbooks collection.
Take a look at Workbook.Sheets[0] (each of those links to the msdn reference). I don't see a direct way to pull that into a DataTable, but you could iterate through the Rows(of class Range) member and simply add to your DataTable that way. From a DataTable it would then be trivial to generate a query using any of the MySQL libraries.
I have a WinForms app written in C# that uses the following code to open an Excel Template, prior to exporting data from a SQL database into the Worksheets of the Template.
Microsoft.Office.Interop.Excel.Application oXL = new Microsoft.Office.Interop.Excel.Application();
oXL.Visible = true;
oXL.DisplayAlerts = false;
Microsoft.Office.Interop.Excel.Workbook mWorkBook = oXL.Workbooks.Open(path, 0, false, 5, "", "", false, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "", true, false, 0, true, false, false);
Excel.Worksheet mWorkSheet = mWorkBook.Worksheets["Invoice"];
However, this code actually opens the Template itself, so that any data exported from SQL into the workbook, is saved to the Template. What I want is to programmatically open a copy of the template in the same way this works when you double click a template directly in Windows Explorer and a copy is automatically created, without the original Template being touched.
How can I do this programmatically?
You can actually use the Workbooks.Add function of your Excel Application object, and pass in the template path as a parameter. Any future changes that you do programmatically will be done to an as-yet-to-be-saved copy in memory.
I've found that this is useful when you want to prepare / preformat a new excel workbook for a user to interact with later.
string templatePath = "c:\\temp\\template.xlsx";
Workbook wb = oXL.Workbooks.Add(templatePath);
//wb will be a memory copy of template.xlsx
then copy the file you want to open to the destination of your choice and open the copy...
System.IO.File.Copy(sourceFile, destFile, true);
the sourcefile is the original file;
the destFile is your copy
and you open the destfile with oXL.Workbooks.Opeen("path to destfile",....)
So your original file is never touched:)
Im trying to pass 8 string values in to a row in an already existing excel spreadsheet and then be able to select that row programmatically using C#. I am using a Windows Service with a file system watcher that is constantly monitoring a directory for a file to be added once the file is added it needs to extract the file contents in to object properties and then write them to an excel sheet. Would anyone have any idea how to do this without having to pay for any additional excel extensions? I am using excel 2007 and Visual Studio 2012. Any help would be much appreciated.
Thanks
Bernard
Hi I actually got it working there. I used the following code to write to a specific cell in an already existing excel sheet:
string path = #"C:\ProjectTesting\TwsDde.xlsm";
oXL = new Microsoft.Office.Interop.Excel.Application();
oXL.Visible = true;
oXL.DisplayAlerts = false;
mWorkBook = oXL.Workbooks.Open(path, 0, false, 5, "", "", false, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "", true, false, 0, true, false, false);
//Get all the sheets in the workbook
mWorkSheets = mWorkBook.Worksheets;
//Get the allready exists sheet
mWSheet1 = (Microsoft.Office.Interop.Excel.Worksheet)mWorkSheets.get_Item("Basic Orders");
Microsoft.Office.Interop.Excel.Range range= mWSheet1.UsedRange;
mWSheet1.Cells[12, 1] = "bla bla bla";
This code was taken from this article which also goes on to save the excel sheet:
http://rmanimaran.wordpress.com/2011/02/15/programmatically-insert-to-existing-excel-file-using-c/
I hope this helps somebody else.
Thanks
Bernard
static void Main()
{
Application excelapp = new Application();
Workbook book = excelapp.Workbooks.Open(#"C:\HWYFAB.xlsx",
0, false, 5, "", "", false, XlPlatform.xlWindows , "",
true, false, 0, true, false, false);
Worksheet sheet = (Worksheet)book.Sheets[1];
Range cell = (Range)sheet.Cells[3, 2];
Console.WriteLine(cell.Text);
cell.ClearContents();
book.Close(true, "HWYFAB.xlsx", false);
excelapp.Quit();
}
This program runs and exits as expected. It does print the correct value that's in cell B3 to the console. When closing it asks if I want to replace the existing file. I click yes. When I open the spreadsheet in Excel, the value is still in cell B3 despite the cell.ClearContents().
Any thoughts?
Your call to cell.ClearContents() will clear formulas and value constants from the cell. This should absolutely be working. You can confirm this after your call to cell.ClearContents() by testing if cell.Value2 == null, which should be true.
I believe that the problem with your code is in the call to book.Close(true, "HWYFAB.xlsx", false). The problem is that you are explicitly passing in the name of your workbook, but you are leaving off the path. (Note that when you open the workbook you are including the full path, including the "C:\" directory.) By leaving off the full path to the workbook when you save, you are saving to the current directory, which could be "My Documents" or anywhere else.
If you wish to save the workbook in-place, at its original location, then you should pass in Type.Missing for the Filename parameter. For example:
book.Close(true, Type.Missing, false);
This idea is untested, but I'm fairly confident that this should work for you. Give it a try...
-- Mike
I have created a C# application whose inputs are some large Excel files.
In my code, I open it, process and then close it. The whole process takes some 15-20 minutes. During this time when I try to open some other Excel files(1) externally, anyone of the input Excel files(2) (which is currently being processed) is also getting opened along with this. When I try to close this(2), exception occurs and the tool aborts its process.
I think the problem occurs because the Excel files are opened under the same instance. How can I avoid this?
SpreadsheetGear for .NET will open only the workbooks you want it to open and in most cases runs much faster than using the Excel COM Interop APIs from .NET.
You can see samples here and download a free trial here if you want to try it yourself.
Disclaimer: I own SpreadsheetGear LLC
The following is the code:
Excel.ApplicationClass objExcelApp = new Excel.ApplicationClass();
Excel.Workbook objWorkbook = objExcelApp.Workbooks.Open("File Name",0, true, 1, "", "", true, Excel.XlPlatform.xlWindows,Type.Missing, false, false, 0,true);
Excel.Worksheet objWorksheet = (Excel.Worksheet) objWorkbook.Worksheets.get_Item(1);
Excel.Range objRangeData =objWorksheet.UsedRange;
// Some proces
GC.Collect();
objRangeData.Clear ();
objWorkbook.Close(false, strDictFile, false);
objExcelApp.Workbooks.Close();
objExcelApp.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(objRangeData);
System.Runtime.InteropServices.Marshal.ReleaseComObject(objWorksheet);
System.Runtime.InteropServices.Marshal.ReleaseComObject(objWorkbook); System.Runtime.InteropServices.Marshal.ReleaseComObject(objExcelApp);
objWorksheet = null;
objWorkbook = null;
objExcelApp = null;
GC.Collect();
GC.WaitForPendingFinalizers();