2010-01-21 31 views
5

Estoy usando Microsoft.Office.Interop.Excel, y no puedo encontrar una forma de devolver las filas seleccionadas. Lo que quiero decir con "seleccionado" es, los números de fila a sí mismos cuando hace clic en el canal de fila de la izquierda y selecciona una o más filas contiguas o no contiguas (que resaltan toda la fila). Esto es diferente de seleccionar una región o área en la hoja misma.Excel: recuperar las filas seleccionadas

Hasta ahora, he visto app.Selection, app.Cells, app.Rows, y ninguno de estos parece darme las filas. app.Selection me da el contenido de la celda real, que NO es lo que quiero.

¿Alguna idea? ¡Gracias!

Respuesta

8

Para hacer esto, debe enumerar cada Área en el Rango, y luego enumerar las Filas dentro de cada área. De manera algo confusa, la propiedad Excel.Range.Rows devuelve una colección de rangos (cada uno representa una fila), mientras que la propiedad Excel.Range.Row devuelve el número de fila de la celda superior izquierda en el rango.

Por lo tanto, para obtener los números de fila, debe enumerar las colecciones de Áreas y Filas y luego acceder al Rango.Raíz. Por ejemplo:

Excel.Range range = (Excel.Range)excelApp.Selection; 

List<int> rowNumbers = new List<int>(); 

// Enumerate the Rows within each Area of the Range. 
foreach (Excel.Range area in range.Areas) 
{ 
    foreach (Excel.Range row in area.Rows) 
    { 
     rowNumbers.Add(row.Row); 
    } 
} 

// Report the results. 
foreach (int rowNumber in rowNumbers) 
{ 
    MessageBox.Show(rowNumber.ToString()); 
} 

Incluso podría usar Linq si lo desea.

Utilizando la sintaxis de consulta:

IEnumerable<int> rowNumbers = 
    from area in range.Areas.Cast<Excel.Range>() 
    from row in area.Rows.Cast<Excel.Range>() 
    select row.Row; 

Usando Método Sintaxis:

IEnumerable<int> rowNumbers = 
    range.Areas.Cast<Excel.Range>() 
    .SelectMany(area => area.Rows.Cast<Excel.Range>() 
         .Select(row => row.Row)); 

Actualización: Cómo devolver Distintos números Row:

Para regresar números de las filas distintas (que puede ocurrir cuando se selecciona un rango de áreas múltiples donde las áreas no comprenden filas enteras).

(1) Lo más fácil es usar Linq y hacer uso del operador Distinct. Por ejemplo:

Utilizando la sintaxis de consulta:

IEnumerable<int> distinctRowNumbers = 
    (from area in range.Areas.Cast<Excel.Range>() 
    from row in area.Rows.Cast<Excel.Range>() 
    select row.Row) 
    .Distinct(); 

Usando Método Sintaxis:

IEnumerable<int> distinctRowNumbers = 
    range.Areas.Cast<Excel.Range>() 
    .SelectMany(area => area.Rows.Cast<Excel.Range>() 
         .Select(row => row.Row)) 
    .Distinct(); 

(2) Si no hacer uso de LINQ, a continuación, se puede utilizar un HashSet. Por ejemplo:

Excel.Range range = (Excel.Range)excelApp.Selection; 

HashSet<int> distinctRowNumbers = new HashSet<int>(); 

// Enumerate the Rows within each Area of the Range. 
foreach (Excel.Range area in range.Areas) 
{ 
    foreach (Excel.Range row in area.Rows) 
    { 
     distinctRowNumbers.Add(row.Row); 
    } 
} 

// Report the results. 
foreach (int rowNumber in distinctRowNumbers) 
{ 
    MessageBox.Show(rowNumber.ToString()); 
} 

(3) Quizás el enfoque más intuitivo es convertir su área de distribución original de filas enteras en primer lugar, y luego repetir las filas. En este caso, las filas ya están garantizadas como únicas, por lo que no es necesario utilizar un operador HashSet o Distinct.

En estos ejemplos, tenga en cuenta el uso Excel.Range.EntireRow, que se aplica a la gama original antes de la enumeración de las áreas y filas:

enumerar sin utilizar Linq:

List<int> distinctRowNumbers = new List<int>(); 

foreach (Excel.Range area in range.EntireRow.Areas) 
{ 
    foreach (Excel.Range row in area.Rows) 
    { 
     distinctRowNumbers.Add(row.Row); 
    } 
} 

Linq usando sintaxis de consulta:

IEnumerable<int> distinctRowNumbers = 
    from area in range.EntireRow.Areas.Cast<Excel.Range>() 
    from row in area.Rows.Cast<Excel.Range>() 
    select row.Row; 

Linq utilizando la sintaxis de método:

IEnumerable<int> distinctRowNumbers = 
    range.EntireRow.Areas.Cast<Excel.Range>() 
    .SelectMany(area => area.Rows.Cast<Excel.Range>() 
         .Select(row => row.Row)); 

Tenga en cuenta que el Range.EntireRow May Return Incorrect Result, pero, si entiendo esto correctamente, esto solo se aplica a Excel '95 y siguientes, que es completamente obsoleto. (No me preocuparía ninguna versión de Excel por debajo de Excel '97). Sin embargo, si le preocupan los problemas de control de versiones y no tiene el lujo de realizar pruebas en todas las versiones de Excel, entonces quizás quiera seguir usando un HashSet. , o use Linq junto con el operador Distinct, para asegurarse de que sus números de fila sean únicos.

Espero que esto ayude!

Mike

+0

Sugiero que agregue una prueba adicional para evitar entradas duplicadas en rowNumbers. –

+0

¡Buen punto, Doc Brown! Ahora agregado arriba ... :-) –

+0

Mike, ¡eso fue fantástico! ¡¡¡Muchas gracias!!! –

0

No hay necesidad de enumerar las filas, sólo las áreas:

var rows = new SortedSet<int>();     // distinct and sorted 

foreach (Excel.Range a in app.Selection.Areas) 
    foreach (int r in Enumerable.Range(a.Row, a.Rows.Count)) 
     rows.Add(r); 
1

Estoy revolviendo el mamut y añadiendo aquí un poco de información real:
Ahora podemos usar simplemente para xlApp.ActiveCell.Row eso :)

Cuestiones relacionadas