2017-05-04 1 views
2

Je rencontre des problèmes avec le ci-dessous. Le premier bit de code fonctionne en tirant toutes les valeurs distinctes dans une zone de liste pour l'utilisateur à examiner. Cependant, quand les données sont filtrées, il tire toujours dans toutes les valeurs cachées ce qui n'est pas ce que je veux. Quand j'ai essayé de tirer seulement des cellules visibles dans la gamme, il a cassé la conversion de ma gamme en une liste distincte. Des pensées sur pourquoi briser la gamme brise cela? Le code casse sur la ligne System.Array myvalues ​​avec l'erreur "Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: Impossible de convertir le type 'string' en 'System.Array'". Cela me semble étrange.Liste distincte de non linéaire Excel Range C#

Code du travail:

Range values = sht.Range[cell1, cell2]; 
System.Array myvalues = (System.Array)values.Cells.Value; 
string[] listValues = myvalues.OfType<object>().Select(o => o.ToString()).ToArray(); 
string[] listValues2 = listValues.Distinct().ToArray(); 

Briser le code:

Range values = sht.Range[cell1, cell2].SpecialCells(XlCellType.xlCellTypeVisible); 
System.Array myvalues = (System.Array)values.Cells.Value; 
string[] listValues = myvalues.OfType<object>().Select(o => o.ToString()).ToArray(); 
string[] listValues2 = listValues.Distinct().ToArray(); 

EDIT:

code de travail pour gérer lorsque la plage est cachée et quand il est pas:

var extractedFromSheet = new List<object>(); 
      foreach (Range area in values.Areas) 
      { 
       var areaValue = area.Value; 
       if (areaValue is Array) // The area contains multiple cells 
       { 
        var arr = (Array)areaValue; 
        extractedFromSheet.AddRange(arr.OfType<object>().Select(o => o .ToString())); 
       } 
       else // The area contains one cell 
       { 
        extractedFromSheet.Add(areaValue); 
       } 
      } 
      var distinct = extractedFromSheet.Distinct(); 
+0

Impossible de reproduire l'erreur. Ce que je vois, c'est que la gamme est divisée en 'Areas' quand certaines parties de la gamme sont cachées par le filtre. Mais cela ne conduit pas à une erreur, mais 'Value' renvoie juste le premier' Area'. – dee

Répondre

2

xlCellTypeVisible renvoie un Range non contigu. Cette plage a une propriété .Areas, dont chacune est également Range. Essayez itérer par values.Areas et obtenir les valeurs de chacune de ces plages.

Vous devrez également vérifier chacune de ces valeurs car il peut s'agir d'une valeur unique ou d'une matrice selon que la zone contient une ou plusieurs cellules. C'est probablement l'erreur que vous voyez. Il lit une chaîne unique à partir d'une cellule afin de ne pas retourner un tableau.

Cela devrait le faire ou être proche:

var extractedFromSheet = new List<object>(); 
foreach(Range area in values.Areas) 
{ 
    var areaValue = area.Value; 
    if(areaValue is Array) // The area contains multiple cells 
    { 
     extractedFromSheet.AddRange((System.Array)areaValue); 
    } 
    else // The area contains one cell 
    { 
     extractedFromSheet.AddRange(areaValue); 
    } 
} 
var distinct = extractedFromSheet.Distinct(); 

Il est un peu foiré qu'une propriété peut retourner tout type d'objet ou un tableau. Je ne me rappelle même pas tout ce que vous devez faire pour vous assurer que les références aux objets COM sont nettoyées.

https://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel.range.areas.aspx

+0

Merci, je ne savais pas à propos de la propriété .Areas. Je vais essayer ça aujourd'hui. – Clouse24

+1

Moi non plus, et j'ai travaillé avec Excel pendant un moment. C'est déroutant car il casse/ignore tous les principes de la POO. Un 'Range' devrait se comporter comme un' Range' qui se comporte comme un 'Range'. Mais au lieu de savoir que vous avez un 'Range' ne vous dit pas comment il se comporte. –

+0

J'ai donc dû modifier votre instruction If pour qu'elle fonctionne dans tous les scénarios. C'est une manière tellement bizarre pour ces objets de se comporter. if (areaValue is Array) // La zone contient plusieurs cellules { var arr = (Array) areaValue; extraitFromSheet.AddRange (arr.OfType () .Select (o => o .ToString())); } else // La zone contient une cellule { extraitFromSheet.Add (areaValue); } – Clouse24