The whole app works fine, when merging single tabbed workbooks. But then I added functionality to also merge all worksheets in a book, before merging the book with another.
It merges them (tested on a single multitabbed wbook), but at some point starts to mess it up.
For example
outcome:
sheet1
-empty lines- sheet2
-empty lines- sheet3+ half of sheet4
-empty lines- sheet2 again not all, with some values missing
etc...
Im not sure if is the code that needs something extra, or problems in certain worksheets.
Heres the crucial parts:
for (int i = 0; i < pathList.Count; i++)
{
List<string> Sheet = GetSheetName(path);
filename = GetFileName(path);
MyConnection = new System.Data.OleDb.OleDbConnection("provider=Microsoft.Jet.OLEDB.4.0;Data Source='" + path + "';Extended Properties='Excel 8.0;IMEX=1;'");
foreach (string SheetName in Sheet)
{
//OLEDB SECTION ***********************************************
MyCommand = new System.Data.OleDb.OleDbDataAdapter("select * from [" + SheetName + "$]", MyConnection);
MyCommand.TableMappings.Add(pathList.Count.ToString(), filename);
MyCommand.Fill(table);
lstTable.Add(table);
MyConnection.Close();
MyCommand.Dispose();
//*************************************************************
}
}
and the getSheetNames
List<string> GetSheetName(string path)
{
Microsoft.Office.Interop.Excel.Application xlApp;
Microsoft.Office.Interop.Excel.Workbook xlWorkBook;
Microsoft.Office.Interop.Excel.Worksheet xlWorkSheet;
List<string> names = new List<string>();
xlApp = new Microsoft.Office.Interop.Excel.Application();
xlWorkBook = xlApp.Workbooks.Open(path, 0, true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
foreach (Microsoft.Office.Interop.Excel.Worksheet i in xlWorkBook.Worksheets)
if (i.UsedRange.Count > 0)
names.Add(i.Name);
return names ;
}
Related
I'm new to C#. I have used the code below to read data from Excel, but I need help modifying it to read key-value pairs.
public String getData(int row, int col, String var)
{
Excel.Application excelApp = new Excel.Application();
if (excelApp != null)
{
List<string> prop = new List<string>(var.Split(new string[] {"."}, StringSplitOptions.None));
Excel.Workbook excelWorkbook = excelApp.Workbooks.Open(#"D:\\test.xlsx", 0, true, 5, "", "", true, Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
Excel.Worksheet excelWorksheet = (Excel.Worksheet)excelWorkbook.Sheets[prop[0]];
excelWorksheet.Select(Type.Missing);
Excel.Range range = (excelWorksheet.Cells[row, col] as Excel.Range);
string cellValue = range.Value.ToString();
excelWorkbook.Close();
excelApp.Quit();
return cellValue;
}
return null;
}
Here is an example; it assumes you have a using clause..
using Excel = Microsoft.Office.Interop.Excel;
..and prepared access to a worksheet:
Excel.Application xl = new Excel.Application();
xl.Workbooks.Open(filename);
Excel.Worksheet ws = xl.Workbooks[1].Worksheets[1]; // pick your sheet!
int keyColum = 3;
Now you can grab a Range of Cells:
Excel.Range keyRange= ws.Range["C3:C53"];
..or the whole column:
Excel.Range keyRange= ws.Range["C:C"];
And search all occurences of a search string:
Excel.Range keysFound = keyRange.Find(textBox1.Text);
Then you can access the range of found cells like this:
string msg1 = keysFound.Count + " records found.";
string msg2 = "1st in row " + keysFound.Row;
string msg3 = "value from next column is "
+ ws.Cells[keysFound.Row + 1, keyColum + 1].value;
notes:
indexing start with 0 in c# but not in excel (hence [keysFound.Row + 1, )
my value column is one column right of the keys. Best use named indices!
if nothing is found keysFound will be null! (do add a check!)
since you want to match a whole key, you will want to do an exact search:
Excel.Range keysFound = keyRange.Find(textBox1.Text, LookAt: Excel.XlLookAt.xlWhole);
I still think grabbing all data and stuffing them into a Dictionary will be the cleanest and fastest solution, unless, that is you only need to do one lookup..
i tired this code but it only paste the copied sheet as a embed sheet in my destination location. i want to create to create a window application that should make a copy of source excel file and paste to destination location.kindly help me
Excel.Application srcxlApp;
Excel.Workbook srcworkBook;
Excel.Worksheet srcworkSheet;
Excel.Range srcrange;
Excel.Application destxlApp;
Excel.Workbook destworkBook;
Excel.Worksheet destworkSheet;
Excel.Range destrange;
string srcPath;
string destPath;
//Opening of first worksheet and copying
srcPath = tbpath.Text;
srcxlApp = new Excel.Application();
srcworkBook = srcxlApp.Workbooks.Open(srcPath);
srcworkSheet = srcworkBook.Worksheets.get_Item(1);
srcrange = srcworkSheet.UsedRange;
srcrange.Copy(Type.Missing);
//opening of the second worksheet and pasting
destPath = "C:\\Users\\Dell\\Desktop\\don\\Book1.xlsx";
destxlApp = new Excel.Application();
destworkBook = destxlApp.Workbooks.Open(destPath, 0, false);
destworkSheet = destworkBook.Worksheets.get_Item(1);
destrange = destworkSheet.Cells[1, 1];
// destrange.Select();
destworkSheet.PasteSpecial(Excel.XlPasteType.xlPasteAll, Excel.XlPasteSpecialOperation.xlPasteSpecialOperationNone, false, false);
// destworkSheet.PasteSpecial(Type.Missing, Type.Missing);
destworkBook.SaveAs("C:\\Users\\Dell\\Desktop\\don" + DateTime.Now.ToString("MM_dd_yyyy") + ".xlsx");
srcxlApp.Application.DisplayAlerts = false;
destxlApp.Application.DisplayAlerts = false;
destworkBook.Close(true, null, null);
destxlApp.Quit();
srcworkBook.Close(false, null, null);
srcxlApp.Quit();
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/
in my app, I've saved a copy of a blank excel file form as a resources, I need to load this file, modify its both worksheets, save it in a new location with a new name.
user should not see that process.
I'm using C# 2010 with a SQL server, from which I'm gonna load my data and put it in the excel form.
Thank You For Your Time.
Use the Microsoft Interop Assemblies that can be found in .NET or COM (Microsoft.Office.Interop.Excel)
Then load all the required cells into a List and modify the data.
Something like this (code below):
string path = #"C:\temp\test.xls";
ApplicationClass excelApllication = null;
Workbook excelWorkBook = null;
Worksheet excelWorkSheet = null;
excelApllication = new ApplicationClass();
System.Threading.Thread.Sleep(2000);
excelWorkBook = excelApllication.Workbooks.Add();
excelWorkSheet = (Worksheet)excelWorkBook.Worksheets.get_Item(1);
// Attention: 1 indexed cells, [Row, Col]
excelWorkSheet.Cells[1, 1] = "Column A, Row 1";
excelWorkSheet.Cells[2, 5] = "Column E, Row 2";
excelWorkSheet.Cells[3, 3] = "Column C, Row 3";
excelWorkBook.SaveAs(path, XlFileFormat.xlWorkbookNormal);
excelWorkBook.Close();
excelApllication.Quit();
Marshal.FinalReleaseComObject(excelWorkSheet);
Marshal.FinalReleaseComObject(excelWorkBook);
Marshal.FinalReleaseComObject(excelApllication);
excelApllication = null;
excelWorkSheet = null;
//opens the created and saved Excel file
Process.Start(path);
That should happen inside a Thread, because you don't want a user to notice that task.
http://msdn.microsoft.com/en-us/library/aa645740%28v=vs.71%29.aspx
(Threading Tutorial)
I would try to avoid automating Excel if at all possible and use the OpenXML SDK (or a library wrapping the OpenXML SDK) for this task.
Here is an article that could help you get started.
I think you wanted to do this... at least worked for me. :)
private void btnExcel_Click(object sender, EventArgs e)
{
string newDirectoryPath = ValidateDirectory();
string newFilePath = Path.Combine(newDirectoryPath, "new.xls");
//brand new temporary file
string tempPath = System.IO.Path.GetTempFileName();
//to manage de temp file life
FileInfo tempFile = new FileInfo(tempPath);
//copy the structure and data of the template .xls
System.IO.File.WriteAllBytes(tempPath,Properties.Resources.SomeResource);
Excel.Application xlApp;
Excel.Workbook xlWorkBook;
Excel.Worksheet xlWorkSheet;
object misValue = System.Reflection.Missing.Value;
xlApp = new Excel.Application();
xlWorkBook = xlApp.Workbooks.Open(tempPath, 0, true, 5, "", "", true, Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);
//WorkTheExcelFile();
tempFile.Delete();
xlWorkBook.SaveAs(newFilePath);
xlWorkBook.Close(true, misValue, misValue);
xlApp.Quit();
releaseObject(xlWorkSheet);
releaseObject(xlWorkBook);
releaseObject(xlApp);
Process.Start(newFilePath + ".xlsx");
}
I'm gonna make a project to convert data and chart to powerpoint file to excel file.
but I found some problem here,,
I have make a project to convert chart, with this script
public static void GetChart(string strFilePath, string strDestPath)
{
xl.Application xlApp;
xl.Workbook xlWorkBook;
xl.Worksheet xlWorkSheet;
object misValue = System.Reflection.Missing.Value;
xlApp = new xl.ApplicationClass();
xlWorkBook = xlApp.Workbooks.Open(strFilePath, 0, true, 5,
"", "", true,
Microsoft.Office.Interop.Excel.XlPlatform.xlWindows,
"\t", false, false, 0, true, 1, 0);
xlWorkSheet =
(xl.Worksheet)xlWorkBook.Worksheets.get_Item(1);
xl.ChartObjects xlCharts =
(xl.ChartObjects)xlWorkSheet.ChartObjects(Type.Missing);
xl.ChartObject myChart = (xl.ChartObject)xlCharts.Item(1);
xl.Chart chartPage = myChart.Chart;
and then I convert it into an image with this script
GetChart(#"" + textBox1.Text + "", #"d:\" + textBox2.Text + ".jpeg");
label5.Text = #"D:\" + textBox2.Text + ".jpeg";
pictureBox1.Image = new Bitmap(#"" + label5.Text +
"");
but I think not all of excel file contains a chart, so I try to search a validation about how to detect a chart in every excel file.
How should I do ?
Try checking the number of items in the charts collection, ie xlCharts.Count