2016-08-15 2 views
5

Unten finden Sie einen allgemeinen Versuch, abhängige Auswahllisten dynamisch aus C# zu erstellen. Wenn der Wert 'A' von Pick1 ausgewählt wird, soll Pick2 die Werte von SecondaryRangeA anzeigen.C# Excel-abhängige Auswahlliste mit Validierung und Indirekt

Dieser Code funktioniert fast, aber anstatt den SecondaryRangeA anzuzeigen, wird der Literalwert 'A' angezeigt.

Wenn ich Excel öffne, nachdem es exportiert und die Datenüberprüfung geändert hat, zeigt es die Formel an.

Wenn ich die Formel manuell in Excel ändern, um die Anführungszeichen auszuschließen, funktioniert es wie erwartet.

=INDIRECT(A5) 

Wenn ich den Code zu den folgenden ändern, erhalte ich eine Ausnahme. Irgendwelche Ideen?

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

Ausnahme:

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: 

Voll Beispiel:

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

Antwort

3

Ich habe ein Problem zu umgehen, aber ich möchte wissen, warum dies nicht funktioniert. Ich bin mir sicher, dass ich noch einmal darüber stolpern werde.

hier eine Antwort auf Englisch ist, Gott allein weiß, was die anderen beiden sagen.

Problem

ein Cascading Dropdown-Liste mit einer Validierung in Excel über C# (oder VBA) nicht mit einem COMException 0x800A03EC Hinzufügen.

Ursache

Der Grund ist es nicht der Fall funktioniert, weil die Quelle tatsächlich leer ist.

Lassen Sie mich Ihnen zeigen, wie ich das ausgearbeitet habe. Ich injiziert, um ein Makro in Excel und lief es:

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

Dieser eine Laufzeitfehler verursacht ‚1004‘, wenn der Makro die Linie führt die Validierung hinzuzufügen:

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

enter image description here

Dies führte mich zu der Annahme Auswahl Objekt wurde nicht definiert (oder mehr zu dem Punkt, es war leer, je nachdem, wie Sie das Wort Auswahl interpretieren).

Lösung

ich damit um gespielt und schließlich den Code Steuerung gestoppt und die Validierung manuell hinzugefügt, wenn ich diese entdeckt:

enter image description here

Die Quelle auf einen Fehler wertet zur Zeit.

Das war eine rauchende Pistole, die Auswahl Objekt war nicht null, es war die A5 Dropdown-Listen 'Auswahl/Wert war tatsächlich leer!

Das Hinzufügen der Dropdown-Liste für die Kaskadierung benötigt einen Wert für das übergeordnete Element!

Also das ist alles, was Sie tun müssen:

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

Dieser der Trick! –

0

Mindestens mit Excel 2007 und 2010 =Indirect(A5) ohne Anführungszeichen wertet, wenn in einer Zelle verwendet, um #REF. Ich denke, wie dieser Code von C# übergeben wird, hat etwas mit der Ausnahme zu tun (da es einen Fehler auswerten würde). Wenn Sie bei der manuellen Erstellung der Validierung dieselbe Funktion verwenden, wird auch die Meldung ausgegeben, die in Excel als Fehler interpretiert wird. Edit: Obwohl ich hier einige Punkte mit mehr Nachforschungen korrigiert habe.

Der erwartete Eingang von Indirect() erwartet einen Zeichenfolgenwert im A1- oder R1C1-Format anstelle eines tatsächlichen Zellenverweises. Es sei denn, der Zielbereich ist eine Zellenreferenz ex: A5 war A1.

Nach MSDN, Indirect() würde nur berechnen, wenn die Datei geöffnet ist und im Speicher MSDN 151323. Das Öffnen der Arbeitsmappe und das Ändern der Validierungsliste und deren korrekte Auswertung bedeutet nicht, dass der Fehler nicht existiert, wenn der Code in C# ausgeführt wird.

0

Wenn zum Beispiel der Wert in A5B ist, dann ist die gleiche wie =INDIRECT(A5)=INDIRECT("B") die die gleiche wie =B ist, die nicht gültige Formel oder Zell Referenz.

=INDIRECT("A5") ist die gleiche wie =A5