I have the following function =AND(EXACT(B3;F3);EXACT(F3;J3)) which returns TRUE or FALSE.
I'd like to create a cell rule for coloring red the false and green the true values.
Trying to use the following code, but not working, what am i doing wrong?
Excel.FormatConditions fcs = xlWorkSheet.Cells[i,"M"].FormatConditions;
Excel.FormatCondition fc = (Excel.FormatCondition)fcs.Add(Excel.XlFormatConditionType.xlTextString, Excel.XlFormatConditionOperator.xlEqual, "TRUE");
Excel.Interior interior = fc.Interior;
interior.Color = ColorTranslator.ToOle(Color.LightGreen);
Excel.Font font = fc.Font;
font.Color = ColorTranslator.ToOle(Color.ForestGreen);
fc = (Excel.FormatCondition)fcs.Add(Excel.XlFormatConditionType.xlTextString, Excel.XlFormatConditionOperator.xlEqual, "FALSE");
interior.Color = ColorTranslator.ToOle(Color.LightSalmon);
font.Color = ColorTranslator.ToOle(Color.Red);
You are not associating the colors with the given rules (but with variables not related to the Conditional Formatting). Also you should better rely on xlCellValue. This code delivers what you are after:
Excel.FormatCondition fc = (Excel.FormatCondition)fcs.Add(Excel.XlFormatConditionType.xlCellValue, Excel.XlFormatConditionOperator.xlEqual, "TRUE", Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
fc.Interior.Color = ColorTranslator.ToOle(Color.LightGreen);
fc.Font.Color = ColorTranslator.ToOle(Color.ForestGreen);
fc = (Excel.FormatCondition)fcs.Add(Excel.XlFormatConditionType.xlCellValue, Excel.XlFormatConditionOperator.xlEqual, "FALSE", Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
fc.Interior.Color = ColorTranslator.ToOle(Color.LightSalmon);
fc.Font.Color = ColorTranslator.ToOle(Color.Red);
(Apologize for posting this as an answer, but I don't have enough rep to add a comment yet)
You have line:
Excel.FormatCondition fc = (Excel.FormatCondition)fcs.Add(Excel.XlFormatConditionType.xlTextString, Excel.XlFormatConditionOperator.xlEqual, "TRUE");
And your third parameter "TRUE" would normally represent the formula. If you want this to work, you'll need to change it to "=TRUE". Similarly, you have "FALSE" which should be updated to "=FALSE".
You'll also want to include #varocarbas suggestions above.
Related
After use MATCH formula to validationStr, my class went wrong.
Can anyone tell me why error happened?
ERROR:
System.Runtime.InteropServices.COMException: 'Exception from HRESULT: 0x800A03EC'
Thank you very much!
using Microsoft.Office.Interop.Excel;
string validationListStr = "=OFFSET($AB$12,1,MATCH($T$12,$AB$12:$AD$12,0)-1,COUNTA(OFFSET($AB$12,1,MATCH($T$12,$AB$12:$AD$12,0)-1,100,1)),1)";
workSheet.Cells[1, 1].Validation.Delete();
workSheet.Cells[1, 1].Validation.Add(XlDVType.xlValidateList, XlDVAlertStyle.xlValidAlertInformation, Type.Missing, validationListStr, Type.Missing);
workSheet.Cells[1, 1].Validation.IgnoreBlank = true;
workSheet.Cells[1, 1].Validation.InCellDropdown = true;
I set the formula to validation by hand in Excel. There was no problem.
However, I cannot set the formula by C#.
The wrong 'Missing' object is being passed to the Add function.
System.Type.Missing needs to be changed to System.Reflection.Missing.Value
workSheet.Cells[1, 1].Validation.Add(
XlDVType.xlValidateList,
XlDVAlertStyle.xlValidAlertInformation,
Missing.Value, // <-
validationListStr,
Missing.Value // <-
);
I want to avoid generated spreadsheets having empty/superfluous sheets named "Sheet1" and such. I thought I could do that by specifying how many sheets a workbook should have this way:
_xlApp = new Excel.Application { SheetsInNewWorkbook = 1 };
...But I'm still getting an unwanted "Sheet1" in addition to the sheet I create. Here is the pertinent code:
using Excel = Microsoft.Office.Interop.Excel;
. . .
private Excel.Application _xlApp;
private Excel.Workbook _xlBook;
private Excel.Sheets _xlSheets;
private Excel.Worksheet _xlSheet;
. . .
private void InitializeSheet()
{
_xlApp = new Excel.Application { SheetsInNewWorkbook = 1 };
_xlBook = _xlApp.Workbooks.Add(Type.Missing);
_xlBook.Worksheets.Add(Type.Missing, Type.Missing, Type.Missing, Type.Missing);
_xlSheets = _xlBook.Worksheets;
_xlSheet = (Excel.Worksheet)_xlSheets.Item[1];
_xlSheet.Name = String.Format("Price Compliance {0} {1}", _month, _year);
}
So since setting SheetsInNewWorkbook to 1 in the Excel.Application instance doesn't do the trick, what do I need to do to prevent these tramp sheets from showing up?
The answer to your question can be found in the documentation of the Template parameter on the Workbook.Add method.
[...] If this argument is omitted, Microsoft Excel creates a new
workbook with a number of blank sheets (the number of sheets is set by
the SheetsInNewWorkbook property).
Your code is omitting it, therefore it is creating a single Worksheet for you (since you've set SheetsInNewWorkbook to 1.
That property is also constrained to be between 1 and 255, so you aren't able to add a work book without a sheet (unless you use a file template).
Also from the Template parameter documentation:
If this argument is a constant, the new workbook contains a single
sheet of the specified
type. Can be one of the following Microsoft.Office.Interop.Excel.XlWBATemplate
constants: xlWBATChart, xlWBATExcel4IntlMacroSheet, xlWBATExcel4MacroSheet,
or xlWBATWorksheet.
So an alternative way to do this is:
_xlApp = new Excel.Application();
_xlBook = _xlApp.Workbooks.Add(Excel.XlWBATemplate.xlWBATWorksheet);
_xlSheets = _xlBook.Worksheets;
_xlSheet = (Excel.Worksheet)_xlSheets.Item[1];
_xlSheet.Name = String.Format("Price Compliance {0} {1}", _month, _year);
Which simply renames the single created sheet.
There's something weird about get_Caller(Type.Missing) method. It returns a negative integer, -2146826265, instead of the Range object as it should.
Has anyone come across this issue before? Why is that and how should I solve it?
Thanks.
Excel.Range range = (Excel.Range) application.get_Caller(System.Type.Missing);
The above code would fail if I try to explicitly user type Excel.Range. The error message says, 'Cannot convert type 'int' to 'Microsoft.Office.Interop.Excel.Range'.
EDIT:
The intention of getting caller of the cell is to pass it to my following function:
private string getResultFromResultSheet(Excel.Range originalSheetRange, Excel.Worksheet resultSheet)
{
string DataResult = "";
try
{
string os_currentAddress = originalSheetRange.get_Address(Type.Missing, Type.Missing, Excel.XlReferenceStyle.xlA1, Type.Missing, Type.Missing);
Excel.Range currentRRange = null;
currentRRange = resultSheet.get_Range(os_currentAddress, Type.Missing);
if (currentRRange != null)
{
if (string.IsNullOrEmpty(Convert.ToString(currentRRange.Value)))
DataResult = "";
else
DataResult = Convert.ToString(currentRRange.Value);
}
}
catch (Exception ex)
{
}
return DataResult;
}
With the return value from that function, I can pass it back to UDF and display it in the original cell. Is there any better way to implement the function?
Review the table at the end of this MSDN Library article about the Application.Caller property. You've discovered the value of the #REF! error. Google 'excel error 2023' for additional info. I kinda doubt you can use this property, given that the caller is your C# program.
I'm trying to use Interop.MSProject with C# to do something that conceptually, should be the simiplest thing in the world to do. However, I am having some trouble with it's cryptic api which has minimal documentation. All I wish to do is to find a row that contains a specific string in one of it's columns (cell) and remove that row. After I've done that, I just want to display the modified project file so that the user has the option to save it. Here is what I've tried:
MSProject.Application app = new MSProject.Application();
app.FileOpenEx(
filePath,
false,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
MSProject.PjPoolOpen.pjPoolReadWrite,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing);
foreach(MSProject.Task task in proj.Tasks)
{
if (task == null) continue;
string cellValue = task.OutlineCode3;
if (cellValue == searchString)
task.Delete();
}
app.Visible = true;
It seems as though task.Delete is not working. I've even tried to generalize this code to the following:
foreach (MSProject.Task task in proj.Tasks)
task.Delete()
and this did not work either. Does anyone know a way that I can remove a task or a row base on a value in one of the rows cells?
I faced the same conundrum yesterday.
Your approach is correct but it doesn't work because the tasks are Index-based. This is more obvious in a straight for loop.
If you have 10 tasks and delete one, let's say number 5, now the next task (6) is now 5 but your loop will try to delete 6 which is now 7. This will mess everything up.
If you want to delete all tasks you should do something like:
// Task Indexes are 1-based not 0-based
for(int i = 1; i <= proj.Tasks.Count; i++) {
proj.Tasks[i].Delete();
i--;
}
Following this train of thought let's apply this to a foreach loop
foreach(Task t in tasksToDelete) {
proj.Tasks[proj.GetTaskIndexByGuid(t.Guid)].Delete();
}
Why am I using GetTaskIndexByGuid? It seems that the Index property of each task if not properly (or immeadiately) updated when you delete a task but I found that using GetTaskIndexByGuid always returns the correct index.
Hope it helps
The following code won't build.
var Date = (Excel.PivotField)pivotTable.PivotFields("Date");
Date.Orientation = Excel.XlPivotFieldOrientation.xlColumnField;
Date.Position = 1;
Date.DataRange.Cells[1].Group(true, true, Type.Missing, GroupParam);
Group is marked as causing an error. The error message is 'object' does not contain a definition for 'Group' and no extension method 'Group' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?)
How can I fix this error?
I am using VS 2012 together with VSTO and add-in express
You should probably declare intermediate variables if you are experiencing compile issues. It fairly apparent from testing that the Group method exists and should be accessible by your code. Give the compiler some help and declare the variable:
The extreme version of this philosophy worked fine for me using Group:
private void button2_Click(object sender, EventArgs e)
{
Excel.Worksheet sht = app.ActiveSheet;
Excel.PivotTable pt = sht.PivotTables(1);
Excel.PivotField pf = pt.PivotFields("DATE");
Excel.Range rng = pf.DataRange;
Excel.Range cell = rng.Cells[1];
cell.Group(true, true, Type.Missing, new bool[] { false, false, false, false, true, true, false });
}
Excel.Range rng = pf.DataRange;
Excel.Range cell = rng.Cells[1];
cell.Group(true, true, Type.Missing, new bool[] { false, false, false, true, false, true, true });
As mentioned above, There are number of parameter passed as true and false in bool array. The value is set to true or false depending on filter you want like for month, year etc.
See image. The parameter order is same as the passed value