I am currently creating a small program that will allow a user to input data into a windows form. Once this data has been input into the form it will then be added to a Excel Document using OleDb.
I have no problems with the above section and I can input data no bother however my problem comes when I try to change the colour of the Excel Row.
I am looking to change the colour of the row to red if the row currently has no fill.
The code I am currently using:
Excel.Application application = new Excel.Application();
Excel.Workbook workbook = application.Workbooks.Open(#"C:\Users\jhughes\Desktop\ScreenUpdate.xls");
Excel.Worksheet worksheet = (Excel.Worksheet)workbook.Sheets["DailyWork"];
Excel.Range usedRange = worksheet.UsedRange;
Excel.Range rows = usedRange.Rows;
try
{
foreach (Excel.Range row in rows)
{
if (row.Cells.EntireRow.Interior.ColorIndex = 0)
{
row.Interior.Color = System.Drawing.Color.Red;
}
}
}
catch(Exception ex)
{
MessageBox.Show(ex.ToString());
}
I am getting the error "Cannot implicitly convert type int to bool" at the line "If(row.Cells.EntireRow....)"
You are attempting to set the ColorIndex to 0, not comparing it to 0. Use == when you compare.
foreach (Excel.Range row in rows)
{
if (row.Cells.EntireRow.Interior.ColorIndex == 0) // changed = to ==
{
row.Interior.Color = System.Drawing.Color.Red;
}
}
You need to use == operator instead of = operator. == operator for equality but = operator is for assignment.
if (row.Cells.EntireRow.Interior.ColorIndex == 0)
= operators simply assign right operand to the left variable/property/indexer and returns the value as its result. That's why when you write
if (row.Cells.EntireRow.Interior.ColorIndex = 0)
it is equal to
if(0)
which is won't compile since if statement expects boolean expression.
I think you not added saving to workbook and change in if condition. Somehow the default colorindex is coming as -4142. Tested now able to change the change color
Excel.Application application = new Excel.Application();
Excel.Workbook workbook = application.Workbooks.Open(#"C:\Users\MyPath\Desktop\ColorBook.xls");
Excel.Worksheet worksheet = (Excel.Worksheet)workbook.Sheets["DailyWork"];
Excel.Range usedRange = worksheet.UsedRange;
Excel.Range rows = usedRange.Rows;
try
{
foreach (Excel.Range row in rows)
{
if (row.Cells.EntireRow.Interior.ColorIndex == -4142)
{
row.Interior.Color = System.Drawing.Color.Red;
}
}
workbook.Save();
workbook.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
Related
I have created the following AutoFilter:
excelRange = excelWorksheet.get_Range("G1");
excelRange.AutoFilter(Field: 7, Criteria1: "Part Number");
excelRange.AutoFilter(Field: 7, Criteria1: ">A*", Operator: Microsoft.Office.Interop.Excel.XlAutoFilterOperator.xlAnd);
excelRange.AutoFilter(Field: 4, Criteria1: "<2023-01-01", Operator: Microsoft.Office.Interop.Excel.XlAutoFilterOperator.xlAnd);
This reduced the rows down to a number let's say 935. How do I loop through the 935 rows produced by the AutoFilter?
Using your range, call SpecialCells method with parameter xlCellTypeVisible.
var filteredRange = excelRange.SpecialCells(XlCellType.xlCellTypeVisible);
foreach (Range cell in filteredRange)
{
Console.WriteLine($"Cell({cell.Column}:{cell.Row}) = {cell.Value}");
}
This worked. It was posted on another forum:
Excel.Application app=new Excel.Application();
Excel.Workbook workbook = app.Workbooks.Open("test.xlsx");
Excel.Worksheet worksheet = workbook.Worksheets[1];
Excel.Range visibleCells = worksheet.UsedRange.SpecialCells(
Excel.XlCellType.xlCellTypeVisible,
Type.Missing);
Excel.Range visibleCells = worksheet.UsedRange.SpecialCells(
Excel.XlCellType.xlCellTypeVisible,
Type.Missing);
foreach (Excel.Range area in visibleCells.Areas)
{
foreach (Excel.Range row in area.Rows)
{
if (row.Row!=935)
{
Console.WriteLine(row.Row);
}
else
{
break;
}
}
}
workbook.Close();
I'm trying to create a program that will read through a new spreadsheet every time. This program has to find a column named "ID" and store all the IDs below and store the corresponding status of that ID.
Column A
Test ID
Column C
Column D
Status
TEXT
123456
TEXT
TEXT
Pass
TEXT
123457
TEXT
TEXT
Pass
TEXT
123458
TEXT
TEXT
Fail
For example I want to store only all values of Column B(ID) along with Column D(Status). As this data will be exported to another spreadsheet with the corresponding IDs while updating the status of this ID.
However, these columns are not static as these spreadsheets are generated randomly per person using the program. Column B(ID) may be Column F next time, and Column D(Status) may be column A.
Example:
Status
Column B
Test ID
Column D
Column E
Pass
TEXT
123456
TEXT
TEXT
Fail
TEXT
123457
TEXT
TEXT
Pass
TEXT
123458
TEXT
TEXT
You'll want to get the indexes for the columns you are interested in so you know which column to look in for each workbook.
The code example below shows a very simple example of getting those column index values.
private static void ProcessExcelFile(string fileName)
{
FileInfo fi = new FileInfo(fileName);
Console.WriteLine($"Processing Excel File: {fi.Name}");
Excel.Application xlApp = null;
Excel.Workbook xlWb = null;
Excel.Worksheet xlWs = null;
Excel.Range xlRange = null;
try
{
// Instantiate the Excel objects
xlApp = new Excel.Application();
xlWb = xlApp.Workbooks.Open(fileName);
xlWs = xlWb.Worksheets[1];
xlRange = xlWs.UsedRange;
// Note: Excel indexes are 1 based so an index of 0 is invalid
int idColumnIndex = 0;
int statusColumnIndex = 0;
// Get the number of columns in the Excel sheet
int colCount = xlRange.Columns.Count;
for (int i = 1; i <= colCount; i++)
{
if (xlRange.Cells[1, i]?.Value?.ToString().ToLower() == "test id")
{
// get the Id column index
idColumnIndex = i;
}
else if (xlRange.Cells[1, i]?.Value?.ToString().ToLower() == "status")
{
// Get the status column index
statusColumnIndex = i;
}
// we've got all our values so exit the loop
if (idColumnIndex > 0 && statusColumnIndex > 0)
{
break;
}
}
// Show what indexes we've found.
if (idColumnIndex > 0)
{
Console.WriteLine($"Id column index is {idColumnIndex}.");
}
else
{
Console.WriteLine($"Id column not found.");
}
if (statusColumnIndex > 0)
{
Console.WriteLine($"Status column index is {statusColumnIndex}.");
}
else
{
Console.WriteLine($"Status column not found.");
}
// Now that you have your ID and STATUS column indexes
// You just need to loop through the rows to pull the values
// for each row.
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
Console.WriteLine();
//release com objects to fully kill excel process from running in the background
if (xlRange != null)
Marshal.ReleaseComObject(xlRange);
if (xlWs != null)
Marshal.ReleaseComObject(xlWs);
//close and release
if (xlWb != null)
{
xlWb.Close();
Marshal.ReleaseComObject(xlWb);
}
//quit and release
if (xlApp != null)
{
xlApp.Quit();
Marshal.ReleaseComObject(xlApp);
}
}
}
I want to export all my DataGridViews in one Excell document.
For every DataGridView there shoud be a own sheet in the Excell File.
But with my code i only recive the Error: System.Runtime.InteropServices.COMException: HRESULT: 0x800A03EC"
I think there is something wrong with my parameters.
private void exportToExcellButton_Click(object sender, EventArgs e)
{
SaveFileDialog saveFileD = new SaveFileDialog();
string fileName = truckListBox.SelectedItem.ToString() + "__" + DateTime.Now.ToShortDateString();
saveFileD.InitialDirectory = #"C:/TML/";
saveFileD.FileName = fileName;
if (!Directory.Exists(#"C:/TML/"))
Directory.CreateDirectory(#"C:/TML/");
List<DataGridView> dataGridViews = getAllDataGridViews();
Microsoft.Office.Interop.Excel.Application app;
Microsoft.Office.Interop.Excel.Workbook book;
Microsoft.Office.Interop.Excel.Worksheet sheet;
app = new Excel.Application();
app.Visible = true;
book = app.Workbooks.Add(System.Reflection.Missing.Value);
foreach (var grid in dataGridViews)
{
int count = book.Worksheets.Count;
sheet = (Worksheet)book.Sheets.Add(Type.Missing, book.Worksheets[count], Type.Missing, Type.Missing);
sheet.Name = grid.Name.ToString().Remove(0, 13);
int cMin = 0, rMin = 0;
int c = cMin, r = rMin;
// Set Headers
foreach (DataGridViewColumn column in grid.Columns)
{
//Here appears the Error: System.Runtime.InteropServices.COMException: HRESULT: 0x800A03EC"
sheet.Cells[r, c] = column.HeaderText;
c++;
}
sheet.Range[sheet.Cells[r, cMin], sheet.Cells[r, c]].Font.Bold = true;
sheet.Range[sheet.Cells[r, cMin], sheet.Cells[r, c]].VerticalAlignment = Microsoft.Office.Interop.Excel.XlVAlign.xlVAlignCenter;
// Set Rows
foreach (DataGridViewRow row in grid.Rows)
{
r++;
c = cMin;
// Set Cells
foreach (DataGridViewCell item in row.Cells)
{
sheet.Cells[r, c++] = item.Value;
}
}
}
book.Save();
book.Close();
app.Quit();
}
Spended allready days into it and cant get it work.
Thx for your Help!
EDIT: Fixed one error to get to the new one.
There are a few problems you may have with the posted code. Therefore, I will break them down.
For starters, it appears you are using a SaveFileDialog however I do not see where it is being used. The code sets the InitalDirectory and FileName, but it is never used. This is not that important as a dialog is not really needed, however the way the code is getting the file name is going to have some problems. The line of code…
string fileName = truckListBox.SelectedItem.ToString() + "__" + DateTime.Now.ToShortDateString();
is going to have problems if you try to save the file name because the string returned from DateTime.Now.ToShortDateString() is going to be in a format like “2019\11\26”… Obviously the “\” characters are going to be interpreted as a path (folder) and will most likely fail when the code tries to save the file. Creating a method that returns a string that uses some other character should be easy to fix this.
Next is the fact that Excel files are NOT zero based on their rows and columns. Therefore, setting the initial Excel row column variables (int c = 0, r = 0;) will fail on the first try. These values should be one (1).
Another problem is on the line…
book.Save();
Is most likely going to save the file to the users “Documents” folder using the file name of “Book1.xlsx.” When saving the file you need to supply the complete path and file name which as stated earlier does not appear to be used.
Lastly, anytime you use “COM” objects such as Excel apps, workbooks and worksheets, it is very important for the code to “RELEASE” the com objects your code creates before you exit the program. In the current posted code, it is highly likely that there are lingering “Excel” resources still running. Therefore, to avoid leaking resources, it is important for your code to release the com objects it creates.
In my example below the code to release the resources is in the finally clause of the try/catch/finally statement.
private void button1_Click(object sender, EventArgs e) {
//SaveFileDialog saveFileD = new SaveFileDialog();
//string fileName = truckListBox.SelectedItem.ToString() + "__" + DateTime.Now.ToShortDateString();
string fileName = #"C:\Users\John\Desktop\Grr\TestExcelFile" + "__" + DateTime.Now.Year + "_" + DateTime.Now.Month;
//saveFileD.InitialDirectory = #"C:\Users\John\Desktop\Grr\";
//saveFileD.FileName = fileName;
//if (!Directory.Exists(#"C:/TML/"))
// Directory.CreateDirectory(#"C:/TML/");
//List<DataGridView> dataGridViews = getAllDataGridViews();
List<DataGridView> dataGridViews = getGrids();
Microsoft.Office.Interop.Excel.Application app = null;
Microsoft.Office.Interop.Excel.Workbook book = null;
Microsoft.Office.Interop.Excel.Worksheet sheet = null;
app = new Microsoft.Office.Interop.Excel.Application();
app.Visible = true;
book = app.Workbooks.Add(System.Reflection.Missing.Value);
try {
foreach (var grid in dataGridViews) {
int count = book.Worksheets.Count;
//sheet = (Microsoft.Office.Interop.Excel.Worksheet)book.Sheets.Add(Type.Missing, book.Worksheets[count], Type.Missing, Type.Missing);
sheet = (Microsoft.Office.Interop.Excel.Worksheet)book.Worksheets.Add();
//sheet.Name = grid.Name.ToString().Remove(0, 13);
sheet.Name = grid.Name.ToString();
int cMin = 1, rMin = 1;
int c = cMin, r = rMin;
// Set Headers
foreach (DataGridViewColumn column in grid.Columns) {
//Here appears the Error: System.Runtime.InteropServices.COMException: HRESULT: 0x800A03EC"
sheet.Cells[r, c] = column.HeaderText;
c++;
}
sheet.Range[sheet.Cells[r, cMin], sheet.Cells[r, c]].Font.Bold = true;
sheet.Range[sheet.Cells[r, cMin], sheet.Cells[r, c]].VerticalAlignment = Microsoft.Office.Interop.Excel.XlVAlign.xlVAlignCenter;
// Set Rows
foreach (DataGridViewRow row in grid.Rows) {
r++;
c = cMin;
// Set Cells
foreach (DataGridViewCell item in row.Cells) {
sheet.Cells[r, c++] = item.Value;
}
}
}
book.SaveAs(fileName, Type.Missing, Type.Missing, Type.Missing);
book.Close();
app.Quit();
}
catch (Exception ex) {
MessageBox.Show("Error writing to excel: " + ex.Message);
}
finally {
if (sheet != null)
Marshal.ReleaseComObject(sheet);
if (book != null)
Marshal.ReleaseComObject(book);
if (app != null)
Marshal.ReleaseComObject(app);
}
}
Hope this helps.
Simply Make a method and pass DataGridView
using Excel = Microsoft.Office.Interop.Excel;
public void ete(DataGridView dgv)//ExportToExcel
{
// Creating a Excel object.
Excel._Application excel = new Excel.Application();
Excel._Workbook workbook = excel.Workbooks.Add(Type.Missing);
Excel._Worksheet worksheet = null;
excel.Columns.ColumnWidth = 20;
try
{
worksheet = workbook.ActiveSheet;
worksheet.Name = "ExportedFromDatGrid";
int cellRowIndex = 1;
int cellColumnIndex = 1;
//Loop through each row and read value from each column.
for (int i = -1; i < dgv.Rows.Count; i++)
{
for (int j = 0; j < dgv.Columns.Count; j++)
{
// Excel index starts from 1,1. As first Row would have the Column headers, adding a condition check.
if (cellRowIndex == 1)
{
worksheet.Cells[cellRowIndex, cellColumnIndex] = dgv.Columns[j].HeaderText;
}
else
{
worksheet.Cells[cellRowIndex, cellColumnIndex] = dgv.Rows[i].Cells[j].Value.ToString();
}
cellColumnIndex++;
}
cellColumnIndex = 1;
cellRowIndex++;
}
//Getting the location and file name of the excel to save from user.
SaveFileDialog saveDialog = new SaveFileDialog();
saveDialog.Filter = "Excel files (*.xlsx)|*.xlsx|All files (*.*)|*.*";
saveDialog.FilterIndex = 2;
if (saveDialog.ShowDialog() == DialogResult.OK)
{
workbook.SaveAs(saveDialog.FileName.ToString());
MessageBox.Show("Export Successful");
}
}
catch (System.Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
excel.Quit();
workbook = null;
excel = null;
}
}
Now Call Method
ete(datagridview1);
I'm trying to get all Excel selected range values including blank entries. What I have worked until is,when a blank is hit and then it exits the loop. I need to recognize the blank, do something with it and then go on to the next cell in the selected range.
This is my code:
// Get active excel instance
Excel.Application xlApp = (Excel.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application");
// Get active excel workbook
string wbn = xlApp.ActiveWorkbook.Name;
Excel.Workbook xlWorkBook = (Excel.Workbook)xlApp.ActiveWorkbook;
// Get active excel worksheet
Excel.Worksheet xlWorkSheet = (Excel.Worksheet)xlWorkBook.ActiveSheet;
// Get range of values from Excel
Microsoft.Office.Interop.Excel.Range SelectedRange = xlApp.Selection as Microsoft.Office.Interop.Excel.Range;
string[] ExcelSelection = new string[1000];
int counter = 0;
foreach (object cell in xlApp.Selection.Cells) //original loop stopping when it hits a blank cell
{
try
{
ExcelSelection[counter] = ((Excel.Range)cell).Value2.ToString().Trim();
//run query to return SAP Description for Excel Active Cell Text
dataGridView1.DataSource = GetSAPDescription(ExcelSelection[counter]);
counter++;
}
catch
{
}
}
}
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);
}
}