Visual Studio Excel Pivot Table not showing data - c#

I am writing an application to add a pivot table sheet in an existing excel workbook. Here's the code:
Console.WriteLine("File: " + e.FullPath + " " + e.ChangeType);
if (e.Name.StartsWith("~$"))
return;
Excel.Application oApp;
Excel.Worksheet oSheet;
Excel.Workbook oBook;
oApp = new Excel.Application();
try
{
oBook = oApp.Workbooks.Open(e.FullPath);
oSheet = (Excel.Worksheet)oBook.Worksheets.get_Item(1);
//Excel.Range finalCell = oSheet.Cells[2, oSheet.Rows.Count];
Excel.Range oRange = oSheet.get_Range("A1", "M9");
if (oApp.Application.Sheets.Count < 2)
{
oSheet = (Excel.Worksheet)oBook.Worksheets.Add();
}
else
{
oSheet = oApp.Worksheets[2];
}
oSheet.Name = "Pivot Table";
// specify first cell for pivot table
Excel.Range oRange2 = oSheet.Cells[3,1];
// create Pivot Cache and Pivot Table
Excel.PivotCache oPivotCache = (Excel.PivotCache)oBook.PivotCaches().Add(Excel.XlPivotTableSourceType.xlDatabase, oRange);
Excel.PivotTable oPivotTable = (Excel.PivotTable)oSheet.PivotTables().Add(PivotCache: oPivotCache, TableDestination: oRange2, TableName: "Summary");
Excel.PivotField oPivotField1 = (Excel.PivotField)oPivotTable.PivotFields("Field1");
oPivotField1.Orientation = Excel.XlPivotFieldOrientation.xlRowField;
oPivotField1.Position = 1;
oPivotField1.Name = "Field1";
Excel.PivotField oPivotField2 = (Excel.PivotField)oPivotTable.PivotFields("Field2");
oPivotField2.Orientation = Excel.XlPivotFieldOrientation.xlRowField;
oPivotField2.Position = 2;
oPivotField2.Name = "Field2";
oBook.Save();
Console.WriteLine("Operation Complete");
}
This is inside a FileSystemWatcher's event handler for file creation. The program runs and creates the sheet for the Pivot table, but data values are not listed and also i get two separate columns. Here's the screen
Please let me know what i'm doing wrong. Using Visual Studio 2015 and project type is Windows Form Application.

Replace the pivot cache/table creation lines:
Excel.PivotCache oPivotCache = (Excel.PivotCache)oBook.PivotCaches().Add(Excel.XlPivotTableSourceType.xlDatabase, oRange);
Excel.PivotTable oPivotTable = (Excel.PivotTable)oSheet.PivotTables().Add(PivotCache: oPivotCache, TableDestination: oRange2, TableName: "Summary");
with
PivotCache oPivotCache = oBook.PivotCaches().Create(XlPivotTableSourceType.xlDatabase, oRange, XlPivotTableVersionList.xlPivotTableVersion14);
PivotTable oPivotTable = oPivotCache.CreatePivotTable(TableDestination: oRange2, TableName: "Summary");
Note that you are doing a lot of redundant casting. You generally don't have to cast all those pivotCache and pivotfield variables.

Related

Copying excel worksheet to a different workbook

I'm trying to copy a worksheet to a different workbook into the last worksheet of the target workbook.
My workbooks and worksheets are created like this:
public Microsoft.Office.Interop.Excel.Workbook xlWorkbookMatrix;
public Microsoft.Office.Interop.Excel._Worksheet xlWorksheetMatrix;
I tried using worksheet.copy:
xlWorksheetMatrix.Copy(Type.Missing, xlWorkbookEvaluation.Sheets[xlWorkbookEvaluation.Sheets.Count]);
and worksheet.UsedRange.Copy:
xlWorksheetMatrix.UsedRange.Copy(xlWorkbookEvaluation.Sheets[xlWorkbookEvaluation.Sheets.Count]);
With both different methods I always get an error.
For worksheet.Copy:
System.Runtime.InteropServices.COMException occured in System.Dynamic.dll
The Copy-property of the worksheet object can't be assigned
For worksheet.UsedRange.Copy:
System.Runtime.InteropServices.COMException occured in System.Dynamic.dll
The Copy-property of the Range object can't be assigned
Having a template sheet you want to fill many times, Hope this helps :
public void test()
{
Excel.Application excelApp;
string fileTarget = "C:\target.xlsx";
string fileTemplate = "C:\template.xlsx";
excelApp = new Excel.Application();
Excel.Workbook wbTemp, wbTarget;
Excel.Worksheet sh;
//Create target workbook
wbTarget = excelApp.Workbooks.Open(fileTemplate);
//Fill target workbook
//Open the template sheet
sh = wbTarget.Worksheets["TEMPLATE"];
//Fill in some data
sh.Cells[1, 1] = "HELLO WORLD!";
//Rename sheet
sh.Name = "1. SHEET";
//Save file
wbTarget.SaveAs(fileTarget);
//Iterate through the rest of the files
for (int i = 1; i < 3; i++)
{
//Open template file in temporary workbook
wbTemp = excelApp.Workbooks.Open(fileTemplate);
//Fill temporary workbook
//Open the template sheet
sh = wbTemp.Worksheets["TEMPLATE"];
//Fill in some data
sh.Cells[1, 1] = "HELLO WORLD! FOR THE " + i + ".TH TIME";
//Rename sheet
sh.Name = i + ". SHEET";
//Copy sheet to target workbook
sh.Copy(wbTarget.Worksheets[1]);
//Close temporary workbook without saving
wbTemp.Close(false);
}
//Close and save target workbook
wbTarget.Close(true);
//Kill excelapp
excelApp.Quit();
}

(C# - Excel) How do I write a formula to a newly created column for each existing row?

Say you have an excel file with a bunch of numbers and rows, about 100 rows.
I want to programatically write a column with a formula that adds the values of a bunch of fields together for each existing row.
So first of all, of course, I would create the Openfiledialog for the Excel file, find the path, open it up through OleDb. Got this down. Now say I have the following table:
[Friends | Money | Money Lost | Days passed | Solution]
Bilbo , 50 , 50 , 7 , *Formula here
Bilso , 80 , 50 , 7 , *Formula here
etc...
Problem is, I don't have an exact number for the rows so I'll have to enumerate whatever is found by the OleDb connection.
The formula would be something like =(B2-C2)*D2 but 2 is also wrong and it would have to be relative to whatever row it's on, ie: row 3 would be =(B3-C3)*D3. I'm not sure how to do this.
I found out writing directly to the cell also doesn't make the formula process the numbers outright.
=====
EDIT:
private Excel.Application Xls;
private Excel.Workbooks WBs;
private Excel.Workbook WB;
private Excel.Worksheet WS;
private Excel.Sheets SS;
Excel.Range cellsRange = null;
Excel.Range columnRange = null;
Excel.Range rowRange = null;
int numberOfColumns = 0;
int numberOfRows = 0;
private void btnColumn_Click(object sender, EventArgs e)
{
if (btnColumn.FlatStyle == FlatStyle.Flat)
btnColumn.FlatStyle = FlatStyle.Standard;
else
{
btnColumn.FlatStyle = FlatStyle.Flat;
}
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "Excel Files|*.xls;*.xlsx";
openFileDialog.ShowDialog();
string pather = openFileDialog.FileName;
if (pather == "" || pather == " " || pather == null)
{
return;
}
if (!string.IsNullOrEmpty(openFileDialog.FileName))
{
try
{
Xls = new Excel.Application();
WBs = Xls.Workbooks;
WB = WBs.Open(pather, 0, false, 5, "", "", true,
XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
SS = WB.Worksheets;
WS = SS.get_Item(1);
cellsRange = WS.Cells;
columnRange = cellsRange.Columns;
rowRange = cellsRange.Rows;
numberOfColumns = columnRange.Count;
numberOfRows = rowRange.Count;
int LastCell = numberOfColumns+1;
WS.Cells[1, LastCell] = "Tax Formula";
for (int i = 2; i < numberOfRows; i++)
{
//string niceFormula = "=SUM(L" + i + ",M" + i + ")*N"+ i ;
//WS.Cells[i, LastCell].Formula = niceFormula;
WS.Cells[i, LastCell].Value = (WS.Cells[i, 12] + WS.Cells[i, 13]) * WS.Cells[i, 14];
}
//==========================
WB.Save();
}
catch (Exception ex)
{
MessageBox.Show("Write Excel: " + ex.Message);
}
finally
{
GC.Collect();
GC.WaitForPendingFinalizers();
WB.Close();
Xls.Quit();
releaseObject(cellsRange);
releaseObject(columnRange);
releaseObject(rowRange);
releaseObject(SS);
releaseObject(WS);
releaseObject(WBs);
releaseObject(WB);
releaseObject(Xls);
}
MessageBox.Show("Finished Updating File", "Task complete");
}
}
Anyone know why this code is throwing the following error on write attempt?
HRESULT: 0x800A03EC
Repasted entire code for your convenience. It's still spitting out the HRESULT error.
Targeted item is 4 rows deep with 1 row of headers and about 16 columns wide.
Edit:
You may want to try this:
numberOfColumns = WS.UsedRange.Columns.CountLarge;
numberOfRows = WS.UsedRange.Rows.CountLarge;
Ugh, also change them to long instead of int if you use CountLarge instead of Count
Okay - I got this working finally - no clue why I was having so many issues.
For me, I apparently have to make the application visible or it doesn't work.
There may be another workaround - I pulled it from here: https://stackoverflow.com/a/17061714/1274820
This code worked for me finally:
Note that this is a console application (figured I would rule that out), but you should just be able to add the magic lines.
Application excelApp = new Application();
excelApp.SheetsInNewWorkbook = 1;
////////////////////////////////////////////
//Add these lines to make it work???
////////////////////////////////////////////
try {
excelApp.Visible = true;
}
catch {}
////////////////////////////////////////////
Workbook excelWB = excelApp.Workbooks.Open(#"C:\test.xls", Type.Missing, false);
_Worksheet excelWS = excelWB.Sheets[1];
Range cellsRange = excelWS.UsedRange;
long LastCell = cellsRange.Columns.CountLarge + 1;
long numberOfRows = cellsRange.Rows.CountLarge;
excelWS.Cells[1, LastCell] = "Tax Formula";
for (int i = 2; i <= numberOfRows; i++)
{
string niceFormula = "=SUM(L" + i + ",M" + i + ")*N" + i;
excelWS.Cells[i, LastCell].Formula = niceFormula;
}
excelWB.Close(true);
excelApp.Quit();
Before:
After:
How to fill a DataTable with an excel spreadsheet:
//////////////////////////////////////////////////////////////////////////////////
//This function is absolute magic >.> - Fill DataTable with excel spreadsheet
//HDR=YES means "Spreadsheet has headers" Change to NO if not.
//name = "Log"; - This is the Sheet name to pull the data from
//////////////////////////////////////////////////////////////////////////////////
//oconn takes an SQL like command (Select Everything from name sheet) using con
//HDR=YES means that our data has headers :)
//////////////////////////////////////////////////////////////////////////////////
String constr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + copyToPath + ";Extended Properties='Excel 12.0 XML;HDR=YES;';";
OleDbConnection con = new OleDbConnection(constr);
OleDbCommand oconn = new OleDbCommand("Select * From [Log$]", con);
con.Open();
OleDbDataAdapter sda = new OleDbDataAdapter(oconn);
DataTable data = new DataTable();
sda.Fill(data);
con.Close();
//////////////////////////////////////////////////////////////////////////////////
Why not use the R1C1 reference style? That way your formula does not need to be relative to the column.
For reference:
https://excelmate.wordpress.com/2013/04/22/excel-r1c1-reference-style-vs-a1/

Excel worksheet won't delete [C#, WPF, VS 2010]

Microsoft.Office.Interop.Excel._Application app = new Microsoft.Office.Interop.Excel.Application();
object misValue = System.Reflection.Missing.Value;
// creating new WorkBook within Excel application
Microsoft.Office.Interop.Excel._Workbook workbook = app.Workbooks.Open(System.IO.Directory.GetCurrentDirectory() + #"\Report.xlsx");
// Get current worksheet and clear it
Microsoft.Office.Interop.Excel._Worksheet worksheet1 = workbook.Worksheets[1];
Microsoft.Office.Interop.Excel._Worksheet worksheet2 = workbook.Worksheets[2];
app.DisplayAlerts = false;
worksheet1.Delete();
worksheet2.Delete();
app.DisplayAlerts = true;
//app.Worksheets[1].Delete();
//app.Worksheets[2].Delete();
workbook.Save();
Microsoft.Office.Interop.Excel._Worksheet worksheet = (Excel.Worksheet)app.Worksheets.Add(); ;
// storing header part in Excel
for (int i = 1; i < mydatatable.Columns.Count + 1; i++)
{
worksheet.Cells[1, i] = mydatatable.Columns[i - 1].ColumnName.ToString();
}
// storing Each row and column value to excel sheet
for (int i = 0; i < mydatatable.Rows.Count; i++)
{
for (int j = 0; j < mydatatable.Columns.Count; j++)
{
worksheet.Cells[i + 2, j + 1] = mydatatable.Rows[i][j].ToString();
}
worksheet.Columns.AutoFit();
}
Excel.Range chartRange;
Excel.ChartObjects xlCharts = (Excel.ChartObjects)worksheet.ChartObjects(Type.Missing);
Excel.ChartObject myChart = (Excel.ChartObject)xlCharts.Add(10, 80, 300, 250);
Excel.Chart chartPage = myChart.Chart;
chartRange = worksheet.get_Range("C1", "E20");
chartPage.SetSourceData(chartRange);
chartPage.ChartType = Excel.XlChartType.xlColumnClustered;
chartPage.Location(Excel.XlChartLocation.xlLocationAsNewSheet,"Chart");
workbook.Save();
workbook.Close(misValue);
Marshal.ReleaseComObject(worksheet);
app.Quit();
It creates the new worksheet perfectly, but doesn't delete the old one first. I even have two codes to delete it and it doesn't. I have more than one sheet in the app.
EDIT: I just noticed that the first time I run the code it deletes the given sheets, but if I run it a second time (etc) it won't delete them anymore and gives me error, because aparently EXCEL proccess is still open in the background for some reason, altough I use "app.Quit()". Please help!
One of the problems could be that you have one worksheet when you're trying to delete it. Make sure that you're not deleting last worksheet or it won't work. So, create new one, then delete old one; not the other way around.
EDIT:
Try this code:
app.DisplayAlerts = false;
worksheetdel.Delete();
app.DisplayAlerts = true;
Source: https://stackoverflow.com/a/678795/2006048

Automatically obtain the range of an excel sheet

Can any body tell me how to automatically obtain the range of an excel sheet .The data in the sheet varies every day and i am getting this data from database.
These date should be then updated in a pivot table that is present another sheet .
This should be done using c# code.
Update from answer posted:
My code is as follows..
Worksheet pivotWorkSheet = (Worksheet)Workbook.Sheets["Template"];
pivotWorkSheet.Activate();
Worksheet WorkSheet1 = (Worksheet)Workbook.Sheets["Sheet1"];
Microsoft.Office.Interop.Excel.Range xlRange = WorkSheet1.UsedRange;
if (xlRange != null)
{
int nRows = xlRange.Rows.Count;
PivotTable pivotMST= (PivotTable)pivotWorkSheet.PivotTables("PivotTableMagazineSummeryStatus");
int MSTResultSetRow = nRows;
pivotMST.SourceData = "Sheet1!R1C1:R" + MSTResultSetRow + "C3";
pivotMST.RefreshTable();
}
My code is as follows..
Worksheet pivotWorkSheet = (Worksheet)Workbook.Sheets["Template"];
pivotWorkSheet.Activate();
Worksheet WorkSheet1 = (Worksheet)Workbook.Sheets["Sheet1"];
Microsoft.Office.Interop.Excel.Range xlRange = WorkSheet1.UsedRange;
if (xlRange != null)
{
int nRows = xlRange.Rows.Count;
PivotTable pivotMST= (PivotTable)pivotWorkSheet.PivotTables("PivotTableMagazineSummeryStatus");
int MSTResultSetRow = nRows;
pivotMST.SourceData = "Sheet1!R1C1:R" + MSTResultSetRow + "C3";
pivotMST.RefreshTable();
}
Check Worksheet.UsedRange property (MSDN).

DateTimePicker value from Excel

I am wondering if it is possible to set the value of a DateTimePicker from a queried row in excel. I have tried different ways of doing it but have never came close and anyone help?
Also it all is displayed on a windows form
public void ReadAndWriteToExcel()
{
string myPath = #"C:\Excel.xls";
FileInfo fi = new FileInfo(myPath);
if (!fi.Exists)
{
Console.Out.WriteLine("file doesn't exists!");
}
else
{
var excelApp = new Microsoft.Office.Interop.Excel.Application();
var workbook = excelApp.Workbooks.Open(myPath);
Worksheet worksheet = workbook.ActiveSheet as Worksheet;
// To write to excel
Microsoft.Office.Interop.Excel.Range range = worksheet.Cells[1, 1] as Range;
DateTime dt = dateTimePicker1.Value;
range.NumberFormat = "dd/MMM/yyyy";
range.Value2 = dt;
// To read,
var date = worksheet.Cells[1, 1].Value;
Console.Out.WriteLine(date.ToString());
workbook.Save();
workbook.Close();
}
}
you must add "Microsoft.Office.Core" and "Microsoft.Office.Interop.Excel" references to your project and use them.

Categories

Resources