2016-08-15 25 views
5

下面是從C#動態創建依賴選項列表的一般性嘗試。當從pick1中選擇值'A'時,pick2應該顯示SecondaryRangeA中的值。帶有驗證和間接的C#Excel依賴選項表

這段代碼幾乎可以工作,但不是顯示SecondaryRangeA,而是顯示字面值'A'。

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

當我打開excel後,它出口並修改數據驗證它顯示公式。

=INDIRECT("A5") 

如果我在Excel中手動修改公式以排除引號,它將按預期工作。

=INDIRECT(A5) 

當我修改下面的代碼時,我得到一個異常。有任何想法嗎?

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; 
     } 
    } 
} 

回答

3

我有一個解決辦法,但我想知道爲什麼這是行不通的。我相信我會再次遇到這個問題。

這是英文的答案,上帝只知道其他兩個人在說什麼。

問題

添加級聯經由C#(或VBA)使用驗證在Excel下拉列表失敗,收到COMException 0x800A03EC。

原因

它不工作的原因是因爲實際上是空的。

讓我告訴你我是如何工作的。我在Excel中注入了宏並運行它:

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」當宏執行行添加驗證:

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

enter image description here

所以這讓我相信選擇對象沒有被定義(或者更多的是它是空的,這取決於你如何解釋單詞選擇)。

解決方案

我這個發揮各地,並最終停止了代碼控制和手動添加的驗證,當我發現這一點:

enter image description here

源目前的計算結果爲錯誤

這是一個吸菸槍,選擇對象不爲空,它是A5下拉列表的選擇/值是事實上是空的!

添加級聯下拉列表需要其父項有一個值!

因此,這是所有你需要做的:

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)"); 
+0

這並獲得成功! –

0

至少在Excel 2007和2010,=Indirect(A5)不帶引號評估在小區中使用時#REF。我在想如何從C#傳遞的代碼與異常有關(因爲它會計算出錯誤)。另外,手動創建Validation時使用相同的函數也會給出評估爲excel錯誤的消息。編輯:雖然我在這裏更多的研究糾正了一些觀點。

來自Indirect()的預期輸入需要A1或R1C1格式的字符串值,而不是實際的單元格引用。除非,目標範圍是單元格引用ex:A5是A1。

根據MSDN,Indirect()只會在文件打開時和內存中計算MSDN 151323。打開工作簿並更改驗證列表並正確評估它並不意味着當C#中的代碼運行時,錯誤不存在。

0

如果例如在A5值爲B然後=INDIRECT(A5)相同=INDIRECT("B")其是相同=B這不是有效的公式或單元格引用。

=INDIRECT("A5")相同=A5