Copying A Formula--And applying it to a new cell range - c#

So here's what I am going through. I am using the Excel dll with c# in order to go inside a big and nasty excel sheet so that others don't have to.
We have a formula in one cell that is rather large and we don't want to copy it to every row because of this. This formula uses multiple values on the row that it is placed on. If it is on row 1, it uses lots of cells from that row.
When one copies this formula normally in excel, the new ranges of the cells are modified to reflect the new starting position.
The problem is that when I copy the formula like this, it still gives me all of the values that have to do with the first row instead of the row where I pasted it.....Here is my code:
sheet.Cells[77][row].Formula = sheet.Cells[77][1].Formula;
Can somebody let me know how to make the formula actually apply to the new row instead of row 1?

This will probably work, as it works from VBA... in most cases.
sheet.Cells[77][row].FormulaR1C1 = sheet.Cells[77][1].FormulaR1C1;
This would work because FormulaR1C1(not a very informative link) uses R1C1 notation which describes the referenced cells location in relation to the current cell instead of saying which cells to use. This means the actual references are dependent on the cell with the formula. When you just use Formula, you're copying the string of the Formula exactly including the hard coded cell references.

You could use Application.ConvertFormula
So, let's say my Cell = Cells77 has a formula that says =Sum(B77,C77) (Cells from the same row).
if want to copy it to a cell right below it, you would do something like:
string formula = Sheet1.Cells[77][2].Formula;
Sheet1.Cells[77][2].Formula = app.ConvertFormula(formula, XlReferenceStyle.xlA1, XlReferenceStyle.xlR1C1, XlReferenceType.xlRelative, Sheet1.Cells[77][3]);
Full console app that works (You need to modify cells though).
static void Main(string[] args)
{
var app = new Microsoft.Office.Interop.Excel.Application();
var workbook = app.Workbooks.Open(#"C:\Users\user\Desktop\Book1.xlsx");
Microsoft.Office.Interop.Excel.Worksheet Sheet1 = (Microsoft.Office.Interop.Excel.Worksheet)workbook.Worksheets.get_Item("Sheet1");
string formula = Sheet1.Cells[5][3].Formula;
Sheet1.Cells[5][4].Formula = app.ConvertFormula(formula, XlReferenceStyle.xlA1, XlReferenceStyle.xlR1C1, XlReferenceType.xlRelative, Sheet1.Cells[5][3]);
workbook.SaveAs(#"C:\Users\user\desktop\test.xlsx");
workbook.Close();
}
You can modify third and forth parameter of ConvertFormula method to your liking. Read more about the method here: ConvertFormula.
If you want to stretch formula accross multiple rows, you can try to use range.AutoFill()

Hi guys m posting this because this code is used to copy the formula behind a cell in Excel:
public void copy_Formula_behind_cell()
{
Excel.Application xlapp;
Excel.Workbook xlworkbook;
Excel.Worksheet xlworksheet;
Excel.Range xlrng;
object misValue = System.Reflection.Missing.Value;
xlapp = new Excel.Application();
xlworkbook =xlapp.Workbooks.Open("YOUR_FILE", 0, true, 5, "",
"",true,Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t",
false,
false, 0, true, 1, 0);
xlworksheet = (Excel.Worksheet)xlworkbook.Worksheets.get_Item(1);
string sp = xlworksheet.Cells[3,2].Formula;//It will Select Formula using Fromula method//
xlworksheet.Cells[8,2].Formula =
xlapp.ConvertFormula(sp,XlReferenceStyle.xlA1,
XlReferenceStyle.xlR1C1, XlReferenceType.xlAbsolute,
xlworksheet.Cells[8][2]);
//This is used to Copy the exact formula to where you want//
xlapp.Visible = true;
xlworkbook.Close(true, misValue, misValue);
xlapp.Quit();
releaseObject(xlworksheet);
releaseObject(xlworkbook);
releaseObject(xlapp);
}
private void releaseObject(object obj)
{
try
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
obj = null;
}
catch (Exception ex)
{
obj = null;
MessageBox.Show("Unable to release the Object " + ex.ToString());
}
finally
{
GC.Collect();
}
}

I am posting this code for range the excel formulas using c# code and Microsoft.Office.Interop.Excel Library:
class Program
{
static void Main(string[] args)
{
Program p = new Program();
p.Excel();
}
public void Excel()
{
Application xlApp = new Application();
Workbook xlWorkBook;
Worksheet xlWorkSheet;
object misValue = Missing.Value;
xlWorkBook = xlApp.Workbooks.Add(misValue);
xlWorkSheet = (Worksheet)xlWorkBook.Worksheets.get_Item(1);
for (int r = 1; r < 5; r++) //r stands for ExcelRow and c for ExcelColumn
{
// Its a my sample example: Excel row and column start positions for writing Row=1 and Col=1
for (int c = 1; c < 3; c++)
{
if (c == 2)
{
if (r == 1)
{
xlWorkSheet.Cells[r, c].Formula = "=SUM(A1+200)";
}
continue;
}
xlWorkSheet.Cells[r, c] = r;
}
}
Range rng = xlWorkSheet.get_Range("B1");
// This is the main code we can range our excel sheet formulas
rng.AutoFill(xlWorkSheet.get_Range("B1", "B4"), XlAutoFillType.xlLinearTrend);
xlWorkBook.Worksheets[1].Name = "MySheetData";//Renaming the Sheet1 to MySheet
xlWorkBook.SaveAs(#"E:\test.xlsx");
xlWorkBook.Close();
Marshal.ReleaseComObject(xlWorkSheet);
Marshal.ReleaseComObject(xlWorkBook);
Marshal.ReleaseComObject(xlApp);
}
}

Related

C# Read data using using Microsoft.Office.Interop.Excel

I have a table of data which i need to read from excel based on user input and store it in VS as an array.
If the user enters C1, search and get the associated data:
array[0]: X1E1M101
array[1]: F2G1M202
If the user enters C2:
array[0]: X1E1M105
array[1]: F1G2M304
my data:
A B C D E
1 C1
2
3 X1 E1 M1 01
4 F2 G1 M2 02
5
6 C2
7
8 X1 E1 M1 05
9 F1 G2 M3 04
10
my code:
//I declared the Interop
using Excel = Microsoft.Office.Interop.Excel;
Excel.Application xlApp;
Excel.Workbook xlWorkBook;
Excel.Worksheet xlWorkSheet;
Excel.Range range;
xlApp = new Excel.Application();
xlWorkBook = xlApp.Workbooks.Open(ManufacturingFile);
//xlWorkSheet = ("Default Value"); // i get an error here when trying to define the worksheet name i want to select. "Cannot impicitly convert type string to ... excel.worksheet'
xlWorkSheet = ((Excel.Worksheet)this.Application.ActiveWorkbook.Sheets[1]).Select(); // This method also I get an error.
xlWorkSheet.Activate();
I am stuck after this part as I am new to using Interop.
Hope someone can help me, I am a beginner in C# and your help is much appreciated.
You will have to open your woorkbook and worksheet , there are a number of example explaining how to do that , here is a sample
Excel.Application xlApp;
Excel.Workbook xlWorkBook;
Excel.Worksheet xlWorkSheet;
Excel.Range range;
string str;
int rCnt = 0;
int cCnt = 0;
object misValue = System.Reflection.Missing.Value;
xlApp = new Excel.Application();
xlWorkBook = xlApp.Workbooks.Open("testone.xlsx", 0, true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);
range = xlWorkSheet.UsedRange;
Microsoft.Office.Interop.Excel.Range xlFound =range.EntireRow.Find("C2",misValue, Excel.XlFindLookIn.xlValues, Excel.XlLookAt.xlPart,Excel.XlSearchOrder.xlByColumns,Excel.XlSearchDirection.xlNext,true, misValue, misValue);
if (!(xlFound == null))
{
int ID_Number = xlFound.Column;
int rownum = xlFound.Row;
Console.WriteLine(ID_Number);
Console.WriteLine(rownum);
Console.Read();
}
You could 1st get the range value of the search for example if 'C1' is at a1 the you will have to read the whole row from a(n+2) and stop when it finds an empty row.
Above code is not compiled its takenfrom here
If you're going to just read data from excel files I recommend you use the ExcelDataReader library instead, it offers better performance and doesn't leave ghost processes as opposed to the Interop one. Here's some sample code to set you up:
IExcelDataReader reader = null;
string FilePath = "PathToExcelFile";
//Load file into a stream
FileStream stream = File.Open(FilePath, FileMode.Open, FileAccess.Read);
//Must check file extension to adjust the reader to the excel file type
if (System.IO.Path.GetExtension(FilePath).Equals(".xls"))
{
reader = ExcelReaderFactory.CreateBinaryReader(stream);
}
else if (System.IO.Path.GetExtension(FilePath).Equals(".xlsx"))
{
reader = ExcelReaderFactory.CreateBinaryReader(stream);
}
if (reader != null)
{
//Fill DataSet
System.Data.DataSet result = reader.AsDataSet();
try
{
//Loop through rows for the desired worksheet
//In this case I use the table index "0" to pick the first worksheet in the workbook
foreach (DataRow row in result.Tables[0].Rows)
{
string FirstColumn = row[0].ToString();
}
}
catch
{
}
}

How to read cell values from existing excel file

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);

Open, Modify, SaveAs an Excel Workbook in the background (Winforms, C#)

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");
}

How do I search for specific text in an Excel worksheet and get the address that the text is occupying using C#?

I am writing a program that will allow me to open excel spreadsheets and get some specific information off of them. Each sheet contains the same information that I need, but the information is not always in the same location.
I am trying to find a way to search for specific text in an Excel sheet and have the address of the cell that text is in.
For example:
If I was looking for the text "apples", the function will find the cell that contains apples and return its address (i.e., A5).
For accessing the Excel spreadsheet I am using Excel = Microsoft.Office.Interop.Excel.
I have been looking all weekend for an efficient way to to do this and have been horribly unsuccessful so far. Any help I can get would be greatly appreciated.
Edit:
This is part of a much larger project, but for this particular function, I have the ability to open and close the Excel file. I have yet to start writing the search function yet, because to be perfectly honest, I am not exactly sure on even how to go about doing this. But here is what I have at this point.
public string searchExcel(string findThis)
{
Excel.Application xlApp;
Excel.Workbook xlWorkBook;
Excel.WorkSheet xlWorkSheet;
object misvalue;
//This part will open the Excel document.
misValue = System.Reflection.Missing.Value;
xlApp = new Excel.ApplicationClass();
xlWorkBook = xlApp.Workbooks.Open("C:\\temp2\\excelDocument.xlsm",
0, true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows,
"\t", false, false, 0, true, 1, 0);
//Search and get address of cell
//This part will close the Excel document
xlWorkBook.Close(true, misValue, misvalue);
xlApp.Quit();
releaseObject(xlWorkSheet);
releaseObject(xlWorkBook);
releaseObject(xlApp);
xlWorkSheet = null;
xlWorkBook = null;
xlApp = null;
}
private void releaseObject(object obj)
{
try
{
System.Runtime.Interopservices.Marshal.ReleaseComObject(obj);
obj = null;
}
catch(Exception e)
{
obj = null;
MessageBox.Show("Unable to release the object " + e.ToString());
}
finally
{
GC.Collect();
}
}
I think something like this should do what you want:
var app = (Excel.Application)Marshal.GetActiveObject("Excel.Application");
var wb = app.ActiveWorkbook;
var ws = wb.Worksheets[1] as Excel.Worksheet;
var cells = ws.Cells;
var match = cells.Find("apples", LookAt:=Excel.XlLookAt.xlPart) as Excel.Range;
var matchAdd = match != null ? match.Address : null;
This will search in the first Worksheet of the current active workbook of a current Excel session.
Adjusting to fit your code:
xlWorksheet = xlWorkBook.Worksheets[1] as Excel.Worksheet;
Excel.Range cells = ws.Cells;
Excel.Range match = cells.Find("apples", LookAt:=Excel.XlLookAt.xlPart) as Excel.Range;
string matchAdd = match != null ? match.Address : null;
if (match != null) releaseObject(match);
releaseObject(cells);
One thing, is this assumes .Net 4.0 as I use missing arguments for the find call. If you are using a previous version you will need to pass in misValue for any parameter not used.

Writing to nextline in Excel 2007

Currently, I have the following method that writes to excel 2007.
public static void createSpreadsheet(String msg)
{
Excel.Application oXL;
Excel.Workbook oWB;
Excel.Worksheet oSheet;
Excel.Range oRng;
oXL = (Excel.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application");
oWB = oXL.Workbooks.get_Item(1);
oSheet = (Excel.Worksheet)oWB.ActiveSheet;
oXL.Visible = true;
oXL.UserControl = false;
oRng = oSheet.get_Range("A1", "A" + 1);
oRng.Value2 = msg;
}
However, whatever msg I sent, it only get to write to column A1 which is evident from the code above.
How do I expand the code above so that whenever additional messages are sent, they are appended below the previously written column.??
In a console app, I could do this: Console.writeline(msg). How do I achieve that in excel?
Eg: Msg 1 (Col A1)
Msg 2 (Col A2)
Msg 3 (Col A3)
....
Define a variable called currentColumn and pass it to the method:
public static void createSpreadsheet(String msg, column)
In calling:
// there is an integer variable called currentColumn
createSpreadsheet("a message", currentColumn++)
You're only getting the A1 cell currently. If you want to write to some other row, just change the parameters to your range. For example:
oRng = oSheet.Range["A" + rowNumber, "A" + rowNumber];
oRng.Value = msg;
And now you can dynamically increment rowNumber after each message. Same thing works for columns, just replace "A" with the appropriate column.

Categories

Resources