Reputation: 1369
I am looking to have a validation in an excel sheet which is generated using C# such that it allows either date value or the text "train" in the excel cell. I found XlDVType.xlValidateDate
for validating date in a cell and XlDVType.xlValidateList
to allow text values. But I want a combination of both, user should either be able to enter date or a particular text in the cell. Can this be accomplished using XlDVType.xlValidateCustom
??
any help on this would be greatly appreciated.
Upvotes: 0
Views: 2830
Reputation: 17383
I want a combination of both, user should either be able to enter date or a particular text in the cell.
The following code snippet sets the desired validation for cell A1 in your worksheet:
Excel.Range range = xlWorkSheet.Range["A1"];
range.ClearFormats();
range.Validation.Delete();
range.Validation.Add(Excel.XlDVType.xlValidateCustom,
Formula1: "=OR(EXACT(LEFT(CELL(\"format\",A1)),\"D\"),EXACT(A1,\"train\"))");
The most complicated part is the actual validation formula. It uses the following functions:
EXACT(cell,string)
compares the contents of a cell with a literal string and returns TRUE
only if they are exactly the same.
CELL("format",cell)
returns a code containing the format of the indicated cell, where the code for a date always starts with a D
. See Office help for CELL
for an explanation and a list of all possible codes. This snippet only looks at the first character, which has to be a D
in order for the contents to be formatted as some kind of date.
LEFT(text,count)
returns the leftmost count
characters in text
, with count
defaulting to 1. In this case, it returns TRUE
if the contents are some kind of date.
OR(logical1, logical2)
returns logical1 OR logical2
, so TRUE
if the contents are either a date, or exactly equal to the string "train"
.
This solution is not yet ideal, because A1
is hardcoded into the formula. There is a way around that using INDIRECT
, described here. You might need that, for example if you want to apply the validation to a whole range of cells in one go. In that case, the hardcoded A1
needs to be replaced by INDIRECT("RC",FALSE)
, which is the mechanism to indicate the current shell. You can read it as a short-cut for INDIRECT("R"&ROW()&"C"&COLUMN(),FALSE)
.
With that adjustment, he last line of code then looks like this (tested in Excel, but not from C#):
range.Validation.Add(Excel.XlDVType.xlValidateCustom,
Formula1: "=OR(EXACT(LEFT(CELL(\"format\",INDIRECT(\"RC\",FALSE))),\"D\"),EXACT(INDIRECT(\"RC\",FALSE),\"train\"))"
Update
As the OP points out, there appears to be a problem with this approach if a date has first been entered into the cell, and then is changed to an incorrect string or number value -- see the comments below. Using the CELL
function therefore does not seem to be the best approach.
However, if the cell format is explicitly set to the (more flexible) Text
format, it is possible to impose the validation with the following lines:
range.Validation.Delete();
range.NumberFormat = "Text";
range.Validation.Add(Excel.XlDVType.xlValidateCustom,
Formula1: =OR(ISNUMBER(DATEVALUE(INDIRECT(\"RC\",FALSE))),EXACT(INDIRECT(\"RC\",FALSE),\"train\"));
Again tested in Excel, but not from C#.
Upvotes: 2