Seeing if comment in cell is null using Excel interlop c#.net - c#

Hey all I am using the code below in order to find out if a cell in the Excel sheet that I am parsing thru has a comment or not.
int columnCount = ws.UsedRange.Columns.Count;
Dictionary<string,bool> storedValidaters = new Dictionary<string, bool>();
for (int c = 1; c < columnCount; c++)
{
if (ws.Cells[2, c].Comment.Shape.AlternativeText != null)
{
string columnName = ws.Cells[2, c].Value2.ToString();
string myComment = ws.Cells[2, c].Comment.Shape.AlternativeText.ToString().Replace("Text Box: ", "");
storedValidaters.Add(columnName, true);
} else {
//the value is null so its false
string columnName = ws.Cells[2, c].Value2.ToString();
storedValidaters.Add(columnName, false);
}
}
It loops a few times but once it gets to a cell that does not have a comment, it poops.
Having the error of Cannot perform runtime binding on a null reference.
I did a few searches to find out if anyone else had working code in order to check for null but have been unable to find a working example.
Anyone know of a way to do this?

I would recommend changing:
Comment.Shape.AlternativeText
to:
Comment?.Shape?.AlternativeText
The null conditional operator will ensure that the code will continue to work as expected regardless of whether the Comment is null, or the Shape is null or the AlternativeText is null.

Related

ExcelDNA throwing exception accessing Range.Value2

I am porting an excel addin (used shimloader) to exceldna, and yeah, I have seen the other SO (and off SO) questions but nothing resolves my question, and I'm hoping there are newer solutions.
The code is simple.
[ExcelFunction(Name="DoSomething")]
string DoSomething()
{
var xl = ExcelDna.Application;
var callerCell = xl.Caller;
var row = getRow(excelReference.RowFirst+1, callerCell.WorkSheet) ;
}
In GetRow():
var row = (Range)worksheet.Rows[row];
var cell = (Range)bracketRow.Columns[4];
When I check debugger, I can see the retrieved cell is 100% correct because cell.FormulaLocal matches the excel row and column formula.
The value in FormulaLocal is "OtherSheet!A12".
But for some reason, whenever I try cell.Value2, it throws a COMException and nothing else. This is not a multithreaded application and I can't understand why this is happening.
Any ideas?
EDIT:
When I modify the formula to the value it should have gotten had the sheet reference been successful, it doesn't throw.
EDIT 2:
I got around this by adding IsMacroType=true attribute to the excel function. But now xl.Caller returns null, argh
Two issues needed solving:
range.Value2 threw a COMException if the cell has an invalid value e.g. #VALUE in excel.
range.Value2 threw a COMException if the cell referenced another worksheet in the same workbook e.g. "OtherSheet!A2"
To solve this, I set the IsMacroType attribute to true:
[ExcelFunction(Name="DoSomething",IsMacroType=true)]
string DoSomething()
{
var xl = ExcelDna.Application;
var callerCell = xl.Caller;
var row = getRow(excelReference.RowFirst+1, callerCell.WorkSheet) ;
}
The problem now though is, IsMacroType causes xl.Caller will now return null.
I got around this by:
ExcelReference reference = (ExcelReference)XlCall.Excel(XlCall.xlfCaller);
string sheetName = (string)XlCall.Excel(XlCall.xlSheetNm,reference);
int index = sheetName.IndexOf(']', 0) + 1;
int endIndex = sheetName.Length - index;
sheetName = sheetName.Substring(index, endIndex);
var worksheet = (Worksheet)xl.ActiveWorkbook.Sheets[sheetName];
This is my first rodeo to Excel world, is there any side effect to enabling IsMacroType? 'Cause I saw #Govert expressing some concerns of undefined behavior...

C# Cannot implicitly convert type System.DBNull to string

Cannot implicitly convert type 'System.DBNull' to 'string'
I am trying to pull data from a worksheet and I get the above error. It happens on the string Text line. What can I do convert this or ignore the null?
var excel = new Microsoft.Office.Interop.Excel.Application();
Workbook workbook = excel.Workbooks.Open(#"C:\Documents\ANIs.xlsx");
Worksheet worksheet = workbook.Worksheets[1];
Range a1 = worksheet.get_Range("A1","B2");
object rawValue = a1.Value;
string Text = a1.Text; //<--Error Occurs here.
for (int i = 0; i < a1.Count; i++)
{
if (a1.Text != null)
Console.WriteLine("{1}", rawValue, Text);
}
Console.ReadLine();
}
Basically, you need a Conditional Statement. If you call ToString() on certain types, if it is Null it will throw an exception. The easiest remedy would be:
if(!(a1 is DBNull))
{
// Do Something
}
Hopefully this clarifies a bit.
// Sample:
var range = worksheet.get_Range("A1","B2");
if(!(range is DBNull))
{
object raw = range.Value;
string text = range.Text;
// Loop here
}
Also, you need to not use Text as capital, that is predefined and can't be used as a variable. Another error in the code. Note in comments, what #RonBeyer said about the Text being used.

Compare string value to datagridview row 0 in any cell

I cannot find anything when I search for this question because I don't really know how to word it.
I have a dataGridView that is getting values from an excel file. That works fine, but I want to compare all the values in row 0 with a string value.
Here is the code I have
string mat = "test";
if(mat == dataGridView1[0,0].Value.ToString())
{
tst.Text = dataGridView1[1,0].Value.ToString();
}
Which only works for the cells in the first entry. I need to scan all values. I would think it would be something like:
string mat = "test";
int x = ???;
if(mat == dataGridView1[0,x].Value.ToString())
{
tst.Text = dataGridView1[1,x].Value.ToString();
}
This is driving me insane because it is such a simple thing that I know has to be possible. Otherwise I'm going to have to copy and paste with x equal to 1,2,3, etc. for however many values the sheet has.
Any suggestions would be greatly appreciated.
You can put you verrification in a loop
string mat = "test";
for(int i=0;i<dataGridView1.Rows[0].Cells.Count;i++){
if(dataGridView1[0,i].Value != null && mat == dataGridView1[0,i].Value.ToString())
{
tst.Text = dataGridView1[1,i].Value.ToString();
}
}
i STRONGLY remcommend that you read this article
if(dataGridView1 != null)
{
foreach (DataGridViewCell cell in dataGridView1.Rows[0].Cells)
{
if (cell.Value != null && cell.Value.Equals("test"))
{
tst.Text = cell.Value;
}
}
}

DataTable ItemArray Assignment Does Not Work

I'm sure it's trivial but it's been a long day.
I have a DataTable in which one row has an empty cell. I want to find the row that has the empty cell, and simply assign a string to that cells value.
However when I step through the code during debug, the value never gets plugged into the table. What am I doing wrong???
currentTime = DateTime.Now.ToString();
for (int i = 0; i < OwnersTable.Rows.Count; i++)
if (OwnersTable.Rows[i].ItemArray[9].ToString() == "")
OwnersTable.Rows[i].ItemArray[9] = currentTime;
I found to accomplish this I had to create an entirely new row, copy every cell's contents of the existing row over, and then add it back to the table.
What???
Why didn't the simple cell assignment work in the code above????
The getter of the DataRow.ItemArray returns an array containing entire values for the row, modifying it's elements does not make any change to the row values.
Gets or sets all the values for this row through an array.
So you need to assign an array to it instead (use the setter), but I do not recommend this way:
currentTime = DateTime.Now.ToString();
for (int i = 0; i < OwnersTable.Rows.Count; i++) {
object[] items = OwnersTable.Rows[i].ItemArray;
if (items[9].ToString() == string.Empty) {
items[9] = currentTime
OwnersTable.Rows[i].ItemArray = items;
}
}
You can use the SetField method of DataRow instead:
currentTime = DateTime.Now.ToString();
foreach (DataRow row in OwnersTable.Rows) {
string value = row.Field<string>(9);
if (string.IsNullOrEmpty(value)) {
row.SetField<string>(9, currentTime)
}
}
Note that I assumed the field is of string type.
Just came across this post after experiencing the same problem. A more direct way to do this that bypasses the ItemArray problem Mehrzad mentions is to both test and assign values using row[columnIndex] wherever row.ItemArray[columnIndex] is used. The direct indexer of the row does not reference a copy of the row's data. The code becomes:
for (int i = 0; i < OwnersTable.Rows.Count; i++)
if (OwnersTable.Rows[i][9].ToString() == "")
OwnersTable.Rows[i][9] = currentTime;
I was facing through same issue. Apparently you don't need the key word ItemArray while assigning the value.
So instead of
OwnersTable.Rows[i].ItemArray[9] = currentTime;
You could use
OwnersTable.Rows[i][9] = currentTime;

Specified cast is not valid while accessing column value

I am finding records in datatable. If the record matches then I want to compare value in the datarow and do some operation. Please see my code below for better explanation,
foreach (DataRow row2 in dtTo.Rows)
{
DataRow[] match = dtReturn.Select("Id = " + row2["Id"]);
if (match.Length > 0)
{
if (match[0]["boolInt"] == 1) // Getting error on this line
{
match[0]["NewValues"] = "";
}
}
}
I was getting error on below line
if (match[0]["boolInt"] == 1)
Then resharper suggested me to cast to bool. so I changed above line to
if( (bool) (match[0]["bClosed"] = 1))
But when I run the project I get run time error as "Specified cast is not valid" on above line.
In immediate window I get value as 1 when I type ,
(match[0]["bClosed"]
What should i do to get rid of this error?
According this:
No there wont be null. The field is tinyint
you code should look like this (AFAIR, tinyint in SQL server matches byte in CLR):
if ((byte)(match[0]["boolInt"]) == 1)
{
}
If you know the field type, there's no need to call Convert methods. The faster way is to cast directly to that known type.
You need to convert the value to int. You can do it like this:
if (Convert.ToInt32(match[0]["boolInt"]) == 1)
But if the column contains a value that can't be casted you wil get an error.
A better aproach would be:
int number;
bool result = Int32.TryParse(match[0]["boolInt"], out number);
if (result && number == 1)
Try this:
if ((match[0]["boolInt"] as int?) == 1)
{
match[0]["NewValues"] = "";
}
if value is null or not valid int it won't cause exception, but should be handled anyways.

Categories

Resources