2016-08-15 7 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

私は回避策を持っていると同じですが、私はこれが動作しない理由を知りたいです。私はこれをもう一度実行すると確信しています。

ここでは、答えは英語で、神だけが他の2人が何を言っているか知っています。

通報

カスケードは、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

を。

選択オブジェクトがnullではない喫煙銃だったのは、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

は、少なくともエクセル2007と2010で、引用符なし=Indirect(A5)は、セル内で使用する場合#REFと評価します。私はこのコードがC#からどのように渡されたのかと考えています(エラーに評価されるため)例外と何か関係があります。また、検証を手動で作成するときに同じ機能を使用すると、Excelでエラーと評価されるメッセージも表示されます。編集:私はここでいくつかの点を修正して立っているが、より多くの研究がある。

Indirect()からの入力は、実際のセル参照ではなく、A1またはR1C1形式の文字列値を必要とします。ターゲット範囲はセル参照です。例:A5はA1です。

MSDNによれば、Indirect()はファイルが開いているときとメモリ内にあるときのみを計算しますMSDN 151323。ワークブックを開いて検証リストを変更しても正しく評価されていても、C#のコードを実行してもエラーは存在しません。

0

A5の値がBある例えば場合、=INDIRECT(A5)は、有効な数式またはセル参照されない=Bと同じである=INDIRECT("B")と同じです。

=INDIRECT("A5")=A5

関連する問題