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.
Related
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'm tying to read an Excel-Sheet into an array, but when I read out of the array all values of the whole row are saved in the first column separated by ';'.
How can I save them properly in a 2-dimensional array?
This is my code:
using Microsoft.Office.Interop.Excel;
using System;
using System.IO;
namespace BB_Entwurf_2
{
class Program
{
public static void Main(string[] args)
{
ApplicationClass app = new ApplicationClass();
Workbook book = null;
Worksheet sheet = null;
string currentDir = Environment.CurrentDirectory;
string excelPath;
excelPath = Path.Combine(currentDir, "MyFile.csv");
app.Visible = false;
app.ScreenUpdating = false;
app.DisplayAlerts = false;
book = app.Workbooks.Open(excelPath);
sheet = (Worksheet)book.Worksheets[1];
int rowCount = sheet.UsedRange.Rows.Count;
Console.WriteLine(rowCount);
Range range = sheet.UsedRange;
object[,] myExcelFileValues = (object[,])range.Value2;
range = null;
string test = (Convert.ToString(myExcelFileValues[1,1]));
Console.WriteLine(test);
test = (Convert.ToString(myExcelFileValues[2,2]));
Console.WriteLine(test);
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(sheet);
sheet = null;
book.Close(false);
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(book);
book = null;
app.Quit();
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(app);
app = null;
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
}
}
}
I'll agree with the comments about a CSV parser, but if you're dead set on using Excel, it won't automatically delimit on your semicolon. You'll need to perform a text to columns first. Something like:
range.TextToColumns(range[1, 1], XlTextParsingType.xlDelimited, XlTextQualifier.xlTextQualifierDoubleQuote, Semicolon: true);
If most/all of the values are strings, you could just split in your c#.
The aforementioned "CSV parser" solution would just be:
excelPath = Path.Combine(currentDir, "MyFile.csv");
string[] lines = File.ReadAllLines(excelPath);
List<string[]> values = new List<string[]>();
foreach (string line in lines)
{
values.Add(line.Split(';'));
}
// parse strings into int, double, date, etc.
Actually less code and no required installations...
You can take first blank array and take a loop to get value one by one as follow
string[] arr = new string[];
Excel.Application application = new Excel.Application();
Excel.Workbook workbook = application.Workbooks.Open(path);
Excel.Worksheet worksheet = workbook.ActiveSheet;
Excel.Range range = worksheet.UsedRange;
for (int row = 1; row <= range.Rows.Count; row++)
{
arr[row-1] = ((Excel.Range)range.Cells[row, 1]).Text;
}
I am trying to read all cell values(dates) from a .CSV file in a range using the Worksheet.get_Range method.
The values(dates) within the cells are being converted in DateTime objects which can be found within range.Value. Unfortunately the converted dates and months are being switched. It is obviously assuming on US date/time formatting rather than UK.
How can I get the these dates to be interpreted using the UK format of 'dd/mm/yy'?
So far I have tried this (although had no luck).
System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-GB");
Here is how I am using the get_range method
Microsoft.Office.Interop.Excel.Application excelApp = null;
Workbooks workBooks = null;
Workbook workBook = null;
Worksheet workSheet = new Worksheet();
excelApp = new Microsoft.Office.Interop.Excel.Application();
excelApp.DisplayAlerts = false;
workBooks = excelApp.Workbooks;
workBook = workBooks.Open(filePath, AddToMru: false);
workSheet = workBook.Worksheets.get_Item(1);
int activeRowCount = workSheet.UsedRange.Rows.Count;
string startCell = row + "1";
string endCell = row + activeRowCount.ToString();
Range xlRng = workSheet.get_Range(startCell, endCell)
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).
I want to read the each cell value in excel file, But i am not able to get the cell values even after trying different examples in NET. I am not getting result with the following code, can any one get back on this. I am using .net framework 2.0
string filePath = "F:/BulkTest.xlsx";
Microsoft.Office.Interop.Excel.Application ExcelApp = new Microsoft.Office.Interop.Excel.Application();
ExcelApp.Visible = true;
Microsoft.Office.Interop.Excel.Workbook wb = ExcelApp.Workbooks.Open(filePath, Missing.Value,Missing.Value,Missing.Value,Missing.Value,Missing.Value,Missing.Value,Missing.Value,Missing.Value,Missing.Value,Missing.Value,Missing.Value,Missing.Value,Missing.Value,Missing.Value);
Microsoft.Office.Interop.Excel.Worksheet sh = (Microsoft.Office.Interop.Excel.Worksheet)wb.Sheets["Sheet1"];
Range excelRange = sh.UsedRange;
for (int i=2; i<= excelRange.Count + 1 ; i++)
{
string values = sh.Cells[i,2].ToString();
}
Till now i am trying to take cell values directly to variables, now i will try to take cell values to an array using Range. Thanks!!!! – Teja Varma 13 mins ago
No. I didn't even mean that :) As I mentioned in the comment that you can store the entire range in an array. That doesn't mean that you need to loop though each cell to store it in an array. You can directly assign the values of the range to the array. See this example.
xlRng = xlWorkSheet.get_Range("A1", "A20");
Object arr = xlRng.Value;
foreach (object s in (Array)arr)
{
MessageBox.Show(s.ToString());
}
The correct answer would be to use:
Sheet.Cells[row,col].Value.ToString();
C# code
Tested OK
string s = xlSheet.UsedRange.Cells[1, 7].Value.ToString();
//or
string d = xlSheet.UsedRange.Cells[1, "G"].Value.ToString();
Full Code
Excel.Application xlApp = new Excel.Application();
Excel.Workbook xlBook;
Excel.Worksheet xlSheet;
string Path = System.IO.Path.GetDirectoryName(Application.ExecutablePath);
xlBook = xlApp.Workbooks.Open(Path + "\\myfile.xlsx");
xlApp.Visible = true;
xlSheet = xlBook.ActiveSheet;
string s = xlSheet.UsedRange.Cells[1, 7].Value.ToString();
string d = xlSheet.UsedRange.Cells[1, "G"].Value.ToString();
xlBook.Close();
xlApp.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlSheet);
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlBook);
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);