C#Excel依赖select与validation和间接

下面是从C#中dynamic创build依赖选项列表的一般性尝试。 当从pick1中select值“A”时,pick2应该显示来自SecondaryRangeA的值。

这个代码几乎可以工作,但不是显示SecondaryRangeA,而是显示文字值“A”。

pick2.Validation.Add(XlDVType.xlValidateList, XlDVAlertStyle.xlValidAlertStop, XlFormatConditionOperator.xlBetween, "=INDIRECT(\"A5\")"); 

当我打开excel后,它出口并修改数据validation它显示公式。

 =INDIRECT("A5") 

如果我在Excel中手动修改公式以排除引号,它按预期工作。

 =INDIRECT(A5) 

当我修改代码到以下我得到一个exception。 有任何想法吗?

 pick2.Validation.Add(XlDVType.xlValidateList, XlDVAlertStyle.xlValidAlertStop, XlFormatConditionOperator.xlBetween, "=INDIRECT(A5)"); 

例外:

 System.Runtime.InteropServices.COMException was unhandled ErrorCode=-2146827284 Message=Exception from HRESULT: 0x800A03EC Source="" StackTrace: at System.RuntimeType.ForwardCallToInvokeMember(String memberName, BindingFlags flags, Object target, Int32[] aWrapperTypes, MessageData& msgData) at Microsoft.Office.Interop.Excel.Validation.Add(XlDVType Type, Object AlertStyle, Object Operator, Object Formula1, Object Formula2) at TestExcelValidation.Program.Main(String[] args) in C:\TFS\ExcelInterop\TestExcelValidation\Program.cs:line 44 at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args) at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart() InnerException: 

完整的例子:

 using System.Collections.Generic; using System.IO; using System.Linq; using Microsoft.Office.Interop.Excel; namespace TestExcelValidation { class Program { static void Main(string[] args) { string temporaryPath = Path.GetTempPath(); string temporaryFile = Path.GetTempFileName(); Application appl = new Application(); appl.Visible = true; Workbook workbook = appl.Workbooks.Open(temporaryFile, 0, true, 5, "", "", true, XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0); Worksheet worksheet = (Worksheet)workbook.Worksheets.Add(); List<string> primaryList = new List<string>(); primaryList.Add("A"); primaryList.Add("B"); List<string> secondaryListA = new List<string>(); secondaryListA.Add("A1"); secondaryListA.Add("A2"); secondaryListA.Add("A3"); List<string> secondaryListB = new List<string>(); secondaryListB.Add("B1"); secondaryListB.Add("B2"); secondaryListB.Add("B3"); Range primaryRange = AddToExcelNamedRange(worksheet, primaryList, 'A', 1, "PrimaryRange"); Range secondaryRangeA = AddToExcelNamedRange(worksheet, secondaryListA, 'B', 1, "A"); Range secondaryRangeB = AddToExcelNamedRange(worksheet, secondaryListB, 'C', 1, "B"); Range pick1 = worksheet.Range["A5"]; pick1.Validation.Add(XlDVType.xlValidateList, XlDVAlertStyle.xlValidAlertStop, XlFormatConditionOperator.xlBetween, "=PrimaryRange"); Range pick2 = worksheet.Range["A6"]; pick2.Validation.Delete(); pick2.NumberFormat = "Text"; pick2.Validation.Add(XlDVType.xlValidateList, XlDVAlertStyle.xlValidAlertStop, XlFormatConditionOperator.xlBetween, "=INDIRECT(\"A5\")"); pick2.Validation.InCellDropdown = true; pick2.Validation.IgnoreBlank = true; } private static Range AddToExcelNamedRange(Worksheet worksheet, List<string> primaryList, char col, int row, string rangeName) { Range range = worksheet.Range[col.ToString() + row.ToString(), col.ToString() + primaryList.Count().ToString()]; range.Name = rangeName; foreach (string item in primaryList) { worksheet.Cells[row, col - 64] = item; row++; } return range; } } } 

我有一个解决方法,但我想知道为什么这不起作用。 我相信我会再次遇到这个问题。

这是英文的答案,上帝只知道另外两个人在说什么。

问题

使用C#(或VBA)在Excel中进行validation来添加级联下拉列表将失败,并显示COMException 0x800A03EC。

原因

它不工作的原因是因为来源实际上是空的。

让我告诉你我是如何解决这个问题的。 我在Excel中注入一个macros并运行它:

 Range pick1 = worksheet.Range["A5"]; pick1.Validation.Add(XlDVType.xlValidateList, XlDVAlertStyle.xlValidAlertStop, XlFormatConditionOperator.xlBetween, "=PrimaryRange"); Range pick2 = worksheet.Range["A6"]; StringBuilder sb = new StringBuilder(); sb.Append("Sub InsertCascadingDropDown()" + Environment.NewLine); sb.Append(" Range(\"A6\").Select" + Environment.NewLine); sb.Append(" With Selection.Validation" + Environment.NewLine); sb.Append(" .Delete" + Environment.NewLine); sb.Append(" .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= xlBetween, Formula1:=\"=INDIRECT(A5)\"" + Environment.NewLine); sb.Append(" .IgnoreBlank = True" + Environment.NewLine); sb.Append(" .InCellDropdown = True" + Environment.NewLine); sb.Append(" .ShowInput = True" + Environment.NewLine); sb.Append(" .ShowError = True" + Environment.NewLine); sb.Append(" End With" + Environment.NewLine); sb.Append("End Sub" + Environment.NewLine); //You need to add a COM reference to Microsoft Visual Basic for Applications Extensibility for this to work var xlmodule = workbook.VBProject.VBComponents.Add(Microsoft.Vbe.Interop.vbext_ComponentType.vbext_ct_StdModule); xlmodule.CodeModule.AddFromString(sb.ToString()); appl.Run("InsertCascadingDropDown"); 

这会导致运行时错误“1004”macros执行行添加validation:

 .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:=xlBetween, Formula1:="=INDIRECT(A5)" 

在这里输入图像说明

所以这导致我相信select对象没有被定义(或者更多的是空的,这取决于你如何解释单词select )。

我玩了这个,并最终停止了代码控制,并添加了手动validation,当我发现这一点:

在这里输入图像说明

源目前评估为错误

这是一个吸烟枪, select对象不是空的,这是A5下拉列表的select/价值是事实上是空的!

添加级联下拉列表需要其父项有一个值!

所以这就是你需要做的一切:

 pick1.Value2 = "A"; //< set the parent to have a value pick2.Validation.Delete(); //<- this is not really needed, unless you run this again pick2.Validation.Add(XlDVType.xlValidateList, XlDVAlertStyle.xlValidAlertStop, XlFormatConditionOperator.xlBetween, "=INDIRECT(A5)"); 

例如,如果A5的值是B=INDIRECT(A5)=INDIRECT("B")相同,这与=B是相同的,这不是有效的公式或单元格引用。

=INDIRECT("A5")=A5相同

至less在Excel 2007和2010中,当在单元格中使用时, =Indirect(A5)不带引号的=Indirect(A5)计算为#REF。 我在想如何从C#传递的代码与exception有关(因为它会计算错误)。 另外,手动创buildValidation时使用相同的函数也会给出在Excel中发生错误的消息。 编辑:虽然我站在这里纠正了更多的研究。

Indirect()期望的input需要A1或R1C1格式的string值,而不是实际的单元格引用。 除非,目标范围是一个单元格参考例如:A5是A1。

根据MSDN,Indirect()将只计算文件打开并在内存MSDN 151323 。 打开工作簿并更改validation列表并正确评估并不意味着在C#中的代码运行时错误不存在。