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).
Related
I have 5 columns(Name,department,Sales Details,Address in sheet(.xlsm) i have to fill this sheet using class object using for loop and fill the sheet after filling this sheet,same object data some information need to fill sheet2 .I am new for excel sheet operations and interop as well, can some one let me know how to fill this data and programmatically how to switch to next sheet to fill the remaining data in sheet2.
for(int masterValues = 0; masterValues < frequencyValues.Count(); masterValues++)
{ MasterDataHeader name= new MasterDataHeader();
masterDataHeader.department = Kvp[0].ToString();
masterDataHeader.salesdetails= Kvp[1].ToString();
masterDataHeader.adress = Kvp[2].ToString();
masterDataHeader.Gebaude_art = Kvp[3].ToString();
masterdtaheader.frequencyinfo=kvp[4]//need to update sheet2
}
You must have Microsoft Office Excel 2007, or later versions, installed on your computer or on your server where this code will be executed.
Add reference to Assemblies -> Extensions ->Microsoft.Office.Interop.Excel.
If you do not see the assemblies, see How to: Install Office Primary Interop Assemblies.
Here simple example how to add new workbook, add two new sheets, add data to those sheets, save the workbook and quit excel.
using MSExcel = Microsoft.Office.Interop.Excel;
public static void FillExcel(IEnumerable<MasterDataHeader> data)
{
MSExcel.Application excel = new MSExcel.Application { Visible = true };
MSExcel.Workbook workbook = excel.Workbooks.Add();
MSExcel.Worksheet sheet1 = workbook.Worksheets.Add();
MSExcel.Worksheet sheet2 = workbook.Worksheets.Add();
MasterDataHeader[] masterDataHeaders = data as MasterDataHeader[] ?? data.ToArray();
int row = 0;
foreach (var item in masterDataHeaders)
{
row++;
sheet1.Cells[row, 1] = item.Name;
sheet1.Cells[row, 2] = item.Department;
sheet1.Cells[row, 3] = item.SalesDetails;
sheet1.Cells[row, 4] = item.Adress;
}
row = 0;
foreach (var item in masterDataHeaders)
{
row++;
sheet2.Cells[row, 1] = item.GebaudeArt;
sheet2.Cells[row, 2] = item.Frequencyinfo;
}
workbook.Save();
excel.Quit();
}
How to search for a employee number in sheet1 and to find just the first occurrence
object missing = System.Type.Missing;
const int employeeNumber = 16845374;
MSExcel.Range employeeNumberFound = null;
employeeNumberFound = sheet1.UsedRange.Find(employeeNumber, missing,
MSExcel.XlFindLookIn.xlValues, MSExcel.XlLookAt.xlPart,
MSExcel.XlSearchOrder.xlByRows, MSExcel.XlSearchDirection.xlNext, false,
missing, missing);
if (employeeNumberFound != null)
{
Debug.WriteLine($"Employee number '{employeeNumber}' was found in cell '[{employeeNumberFound.Row},{employeeNumberFound.Column}]'");
}
else
{
Debug.WriteLine($"Employee number '{employeeNumber}' was not found");
}
For more information look e.g. here.
Get last row in table2 and insert new row below it. Last row remains 32 in case when table2 is empty. And new row will not be incremented in case when table2 is empty.
var lastRowAsRange = sheet1.Cells[32, 2].CurrentRegion.Columns[1].Cells.Find("*", missing, missing, missing,
XlSearchOrder.xlByRows, XlSearchDirection.xlPrevious, false, missing, missing);
var lastRow = lastRowAsRange != null
? lastRowAsRange.Row
: 32;
var newRow = lastRowAsRange != null
? lastRow + 1
: lastRow;
bool inserted = sheet1.Rows[newRow].Insert(XlDirection.xlDown, XlInsertFormatOrigin.xlFormatFromLeftOrAbove);
if (inserted)
{
sheet1.Cells[newRow, 1] = "IT";
sheet1.Cells[newRow, 2] = "100";
sheet1.Cells[newRow, 3] = "hyd";
}
I am unable to export data from multiple rows in DTG to specific columns in excel. I have tried multiple methods from forums. So far, the results are excel opened but no data are exported (empty cells) or only the last row of DTG are copied to the specific columns in excel.
I want this excel sheet to compile the DTG data. Hence, example user open form 1st time, enter DTG data, saves to excel and closes form. User then open form 2nd time and enter another DTG data, the 2nd DTG data will go into the same excel columns but on the next empty row (underneath the row of the 1st DTG data).
Most codes that I've tried comes from this link [Programmatically getting the last filled excel row using C# ]. I did not put the column part as I only want last row. Do note that the skeleton of all the codes are the same but the way lastUsedRow was initialized are different.
Codes below gives empty cells
Excel.Application oXL;
Excel._Workbook oWB;
Excel._Worksheet oSheet;
try
{
oXL = new Microsoft.Office.Interop.Excel.Application();
oWB = oXL.Workbooks.Open("C:\\Users\\User\\Test.xlsx");
oSheet = oXL.Worksheets["Vehicles"];
Excel.Range last = oSheet.Cells.SpecialCells(Excel.XlCellType.xlCellTypeLastCell, Type.Missing);
Excel.Range range = sheet.get_Range("A1", last);
int lastUsedRow = last.Row;
for (int i = 0; i < dataGridView1.Rows.Count; i++)
{
for (int j = 1; j < dataGridView1.Columns.Count; j++)
{
oSheet.Cells[lastUsedRow, j+1] = dataGridView1.Rows[i].Cells[j].Value.ToString();
}
}
OR
int lasUsedRow = oSheet.Cells.SpecialCells(XlCellType.xlCellTypeLastCell, Type.Missing).Row;
Codes below shows only last row of DTG
int lastUsedRow = oSheet.Cells.Find("*",System.Reflection.Missing.Value,
System.Reflection.Missing.Value, System.Reflection.Missing.Value, Excel.XlSearchOrder.xlByRows,Excel.XlSearchDirection.xlPrevious, false,System.Reflection.Missing.Value,System.Reflection.Missing.Value).Row;
OR
int lastUsedRow = oSheet.Range["B" + oSheet.Rows.Count].End[Excel.XlDirection.xlUp].Row+1;
Hope to get some help. Thank you so much!
As per Yoshi's comment, below is the updated code where it allows multiple datagridview rows to be added and compiled into excel.
Excel.Application oXL;
Excel._Workbook oWB;
Excel._Worksheet oSheet;
try
{
//Start Excel and get Application object.
oXL = new Microsoft.Office.Interop.Excel.Application();
//Get a new workbook.
oWB = oXL.Workbooks.Open("C:\\Users\\User\\Test.xlsx");
//Specify different sheet names
oSheet = oXL.Worksheets["Vehicles"];
//Define last row
int _lastRow = oSheet.Range["B" + oSheet.Rows.Count].End[Excel.XlDirection.xlUp].Row+1;
for (int i = 0; i < dataGridView1.Rows.Count; i++)
{
for (int j = 1; j < dataGridView1.Columns.Count; j++)
{
oSheet.Cells[_lastRow, j+1] = dataGridView1.Rows[i].Cells[j].Value.ToString();
}
_lastRow++;
}
//Make sure Excel open and give the user control of Microsoft Excel's lifetime.
oXL.Visible = true;
oXL.UserControl = true;
//Autosave excel file
oWB.Save();
Marshal.ReleaseComObject(oXL);
}
catch (Exception theException)
{
String errorMessage;
errorMessage = "Error: ";
errorMessage = String.Concat(errorMessage, theException.Message);
errorMessage = String.Concat(errorMessage, " Line: ");
errorMessage = String.Concat(errorMessage, theException.Source);
MessageBox.Show(errorMessage, "Error");
}
}
I'm copying data from first sheet of different excel files to a single workbook. I already have tried it with different alternatives like npoi, spire.xls and Interop which works good, but it kills too much of my time. It would really be thankful if anyone can suggest me with a better one. Been through many forms on the web, but couldn't find.
FYI: Each of My files are more than 50 MB in size. A few being 10 MB or less.
This is one of which I have tried (Uses Spire.xls):
workbook = new Workbook();
//laod first file
workbook.LoadFromFile(names[0]);
//load the remaining files starting with second file
for (int i = 1; i < cnt; i++)
{
LoadFIle(names[i]);
//merge the loaded file immediately and than load next file
MergeData();
}
private void LoadFIle(string filePath)
{
//load other workbooks starting with 2nd workbbook
tempbook = new Workbook();
tempbook.LoadFromFile(filePath);
}
private void MergeData()
{
try
{
int c1 = workbook.ActiveSheet.LastRow, c2 = tempbook.Worksheets[0].LastRow;
//check if you have exceeded 1st sheet limit
if ((c1 + c2) <= 1048575)
{
//import the second workbook's worksheet into the first workbook using a datatable
//load 1st sheet of tempbook into sheet
Worksheet sheet = tempbook.Worksheets[0];
//copy data from sheet into a datatable
DataTable dataTable = sheet.ExportDataTable();
//load sheet1
Worksheet sheet1 = workbook.Worksheets[workbook.ActiveSheetIndex];
sheet1.InsertDataTable(dataTable, false, sheet1.LastRow + 1, 1);
}
else if ((c1 >= 1048575 && c2 >= 1048575) || c1 >= 1048575 || c2 >= 1048575 || (c1 + c2) >= 1048575)
{
workbook.Worksheets.AddCopy(tempbook.Worksheets[0]);
indx = workbook.ActiveSheet.Index;
workbook.ActiveSheetIndex = ++indx;
}
else
{
//import the second workbook's worksheet into the first workbook using a datatable
//load 1st sheet of tempbook into sheet
Worksheet sheet = tempbook.Worksheets[0];
//copy data from sheet into a datatable
DataTable dataTable = sheet.ExportDataTable();
//load sheet1
Worksheet sheet1 = workbook.Worksheets[workbook.ActiveSheetIndex];
sheet1.InsertDataTable(dataTable, false, sheet1.LastRow + 1, 1);
}
}
catch (IndexOutOfRangeException)
{
}
}
}
Well, this works good but as said takes a long time. Any suggestions are welcome. Thanks in advance.
Here is my (fastest I know of) implementation using Excel interop. Although I looked carefully to release all (must have missed one), 2 Excel instances remain in the processes list, they are closed after the program ends.
The key is to only have 2 Open Excel instances and to copy the data as a Block using Range.Value2.
//Helper function to cleanup
public void ReleaseObject(object obj)
{
if (obj != null && Marshal.IsComObject(obj))
{
Marshal.ReleaseComObject(obj);
}
}
public void CopyIntoOne(List<string> pSourceFiles, string pDestinationFile)
{
var sourceExcelApp = new Microsoft.Office.Interop.Excel.Application();
var destinationExcelApp = new Microsoft.Office.Interop.Excel.Application();
// TODO: Check if it exists
destinationExcelApp.Workbooks.Open(pDestinationFile);
// for debug
//destinationExcelApp.Visible = true;
//sourceExcelApp.Visible = true;
int i = 0;
var sheets = destinationExcelApp.ActiveWorkbook.Sheets;
var lastsheet = destinationExcelApp.ActiveWorkbook.Sheets[sheets.Count];
ReleaseObject(sheets);
foreach (var srcFile in pSourceFiles)
{
sourceExcelApp.Workbooks.Open(srcFile);
// get extends
var lastRow = sourceExcelApp.ActiveSheet.Cells.Find("*", System.Reflection.Missing.Value,
System.Reflection.Missing.Value, System.Reflection.Missing.Value, XlSearchOrder.xlByRows,
XlSearchDirection.xlPrevious, false, System.Reflection.Missing.Value, System.Reflection.Missing.Value);
var lastCol = sourceExcelApp.ActiveSheet.Cells.Find("*", System.Reflection.Missing.Value, System.Reflection.Missing.Value,
System.Reflection.Missing.Value, XlSearchOrder.xlByColumns, XlSearchDirection.xlPrevious, false,
System.Reflection.Missing.Value, System.Reflection.Missing.Value);
var startCell = (Range) sourceExcelApp.ActiveWorkbook.ActiveSheet.Cells[1, 1];
var endCell = (Range) sourceExcelApp.ActiveWorkbook.ActiveSheet.Cells[lastRow.Row, lastCol.Column];
var myRange = sourceExcelApp.ActiveWorkbook.ActiveSheet.Range[startCell, endCell];
// copy the values
var value = myRange.Value2;
// create sheet in new Workbook at the end
Worksheet newSheet = destinationExcelApp.ActiveWorkbook.Sheets.Add(After: lastsheet);
ReleaseObject(lastsheet);
lastsheet = newSheet;
//its even faster when adding it at the front
//Worksheet newSheet = destinationExcelApp.ActiveWorkbook.Sheets.Add();
// change that to a good name
newSheet.Name = ++i + "";
var dstStartCell = (Range) destinationExcelApp.ActiveWorkbook.ActiveSheet.Cells[1, 1];
var dstEndCell = (Range) destinationExcelApp.ActiveWorkbook.ActiveSheet.Cells[lastRow.Row, lastCol.Column];
var dstRange = destinationExcelApp.ActiveWorkbook.ActiveSheet.Range[dstStartCell, dstEndCell];
// this is the actual paste
dstRange.Value2 = value;
//cleanup
ReleaseObject(startCell);
ReleaseObject(endCell);
ReleaseObject(myRange);
ReleaseObject(value);// cannot hurt, but not necessary since its a simple array
ReleaseObject(dstStartCell);
ReleaseObject(dstEndCell);
ReleaseObject(dstRange);
ReleaseObject(newSheet);
ReleaseObject(lastRow);
ReleaseObject(lastCol);
sourceExcelApp.ActiveWorkbook.Close(false);
}
ReleaseObject(lastsheet);
sourceExcelApp.Quit();
ReleaseObject(sourceExcelApp);
destinationExcelApp.ActiveWorkbook.Save();
destinationExcelApp.Quit();
ReleaseObject(destinationExcelApp);
destinationExcelApp = null;
sourceExcelApp = null;
}
I have tested it on small excel files and are curious how it behaves with larger files.
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.
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.