2011-05-13 5 views
6

antes de comenzar con el problema, quiero motivarlo. Mi tarea es analizar los cambios en una hoja de Excel, pero a diferencia de registrar cambios a través del mecanismo in-build, los cambios deben detectarse mediante programación e incluso si el usuario desactivó la grabación de cambios o mi Excel-AddIn no está instalado. Por lo tanto, he usado Microsoft.Interop.Excel-Library para acceder a una hoja y las celdas dentro de.C#: ID-field of Microsoft.Office.Interop.Excel.Range no se conserva con una hoja de Excel

Ahora al problema: Para encontrar cambios, incluso si el usuario ha ordenado o movido los datos, quería tener una identificación única por celda, que se adhiere a ella, incluso si se movió o se copió. Por supuesto, si se copia, la identificación está dos veces en la hoja y las nuevas celdas agregadas no tienen identificación, pero eso está bien. Además, esta identificación no debería ser visible para el usuario y el usuario no debería poder modificarla o eliminarla.

Así que busqué un campo y encontré el Range-Object que puede representar una sola celda y tiene diferentes miembros a los que se puede acceder. Un campo especial me llamó la atención, el campo de ID, que se parecía a lo que estaba buscando.

Guid guid = Guid.NewGuid(); 
((Range) worksheet.Cells[rowNr, columnNr]).ID = guid.ToString(); 

y también ser leído como

Guid guid = Guid.Parse(((Range) worksheet.Cells[rowNr, columnNr]).ID); 

Esto era perfecto, porque yo era capaz de almacenar una cadena (en este caso un GUID como una cadena, como 123463-FC34-c43a-a391- 399fc2) y léelo. También se pegó a la celda, y se movió, cuando se movió la celda, etc.

Pero desafortunadamente este campo de ID no se conserva, cuando se guarda el archivo, y no sé por qué. Quiero decir que después de cerrar y volver a abrir un libro de trabajo, todas las identificaciones se han ido.

Así que mi pregunta es, si hay algún otro miembro del objeto Range, que pueda contener una cadena (= Guid), y que no sea visible para el usuario. Probé el Name-Member y el Comment-Member, pero ambos son visibles para el usuario y pueden modificarse fácilmente.

¿O hay una forma de decirle a Excel que también quiero guardar el campo ID al guardar la hoja?

Para realizar pruebas, puede crear un proyecto, agregar una referencia a Microsoft.Office.Interop.Excel-Dll y agregar el siguiente código (debe tener Excel instalado en su sistema). Se trata de una unidad de prueba, que se ejecuta con JUnit, pero basta con quitar la aserción-comando para probar sin JUnit también:

using System; 
using System.IO; 
using Microsoft.Office.Interop.Excel; 
using Excel = Microsoft.Office.Interop.Excel; 
public void AddGuidAndRead() 
{ 
    Excel.Application excelApp = new Excel.Application(); 
    Workbook excelWorkbook = excelApp.Workbooks.Add(Type.Missing); 
    Worksheet worksheet = excelWorkbook.Sheets[1]; //1-based index 

    Guid rowGuid1 = Guid.NewGuid(); 
    const string filename = "C:\\temp\\anyTemporaryFilename.xlsx"; 

    //Make sure, this file does not exist previously 
    if (File.Exists(filename)) 
     File.Delete(filename); 

    //Write the ID to the worksheet 
    ((Range)worksheet.Cells[1, 1]).ID = rowGuid1.ToString(); 

    //Act (save and close the workbook) 
    excelWorkbook.SaveAs(filename); 
    excelWorkbook.Close(); 

    //Now open the workbook again 
    Workbook openedWorkbook = excelApp.Workbooks.Open(filename); 
    //Fetch the worksheet, where we worked previously 
    Worksheet openedWorksheet = openedWorkbook.Sheets[1]; //1-based index 

    //Read the ID from the cell 
    string guid1 = ((Range)openedWorksheet.Cells[1, 1]).ID; 

    //Cleanup 
    openedWorkbook.Close(false); 
    File.Delete(filename); 
    excelWorkbook.Close(false, Type.Missing, Type.Missing); 
    excelApp.Quit(); 

    //Assert - this fails!! 
    Assert.AreEqual(rowGuid1.ToString(), guid1); 

} 

Agradecería cualquier idea, cómo poner una identificación para un Excel-Worksheet- Celda que se conserva, al guardar la hoja de trabajo o cualquier cosa sobre este tema.

Muchas gracias de antemano, Alex

actualización 14.5.2011:

El Nombre de campo no parece ser una solución a mi problema por las siguientes razones:

En primer lugar, y lo más grave es el hecho de que parece que el nombre debe ser único, pero quería darles a todas las celdas de la misma ID, lo que no funciona.

En segundo lugar, para acceder al campo de nombre en C# no es muy claro para mí.Puede establecer el valor con

((Range)worksheet.Cells[rowNr, columnNr]).Name = guid.ToString(); 
//Remark: Special dealing with guids required, 
//if they start with a number or contain special characters. 

pero tiene serios problemas. Si el nombre ya se estableció, se produce una excepción, si se ha establecido ningún nombre, y se intenta acceder a ella con

string name = ((Range)worksheet.Cells[rowNr, columnNr]).Name.Name; 

se obtiene una excepción. Y necesita el Name.Name, porque el primer Name-field no es la cadena sino un Name-Object completo, que dentro tiene otro Name-Field que contiene una cadena.

Y por último, si desea comprobar si tiene un nombre o no, no se puede hacer algo como:

if(((Range)worksheet.Cells[rowNr, columnNr]).Name == null) 
    //Do something 

debido a que ya se produce una excepción cuando se accede a un nombre de campo no existente.

Respuesta

1

En realidad, no hay forma de conservar el ID directamente en la hoja, como lo pensé. Ni en el campo ID (que no se conserva), ni como Nombres (solo nombres únicos permitidos) o Comentarios (son visibles para el usuario).

Pero existe el concepto de CustomProperties en un libro, que puede contener cadenas, y dado que todas las clases serializables pueden organizarse para cadenas, esto permite al programador conservar los ID por separado y restaurarlos al cargar un libro.

De todos modos, para mi propósito se utilizó otro enfoque, que calcula los valores de hash de cada línea y compara los valores de hash de línea en su lugar.

1

Puede intentar usar un rango con nombre para cada celda. El nombre persistirá. No he intentado esto con interoperabilidad, pero funciona con un buen viejo vba. En el siguiente código, tenga en cuenta que los nombres pueden estar ocultos para el usuario.

Function try() 
    Dim x As Integer 
    Dim y As String 

    Worksheets("Sheet1").Range("a1").Name = "_firstCell" 
    Range("_firstCell").Value = 9999 
    Dim nm As Name 
    'hide 
    For Each nm In ActiveWorkbook.Names 
     If Left(nm.Name, 1) = "_" Then 
      nm.Visible = False 
     End If 
    Next 
    'move the named cell 
    Range("_firstCell").Cut Range("b1") 
    'check the value and address 
    x = Range("_firstCell").Value 
    y = Range("_firstCell").Address 

End Function 

Por lo que entiendo que no hay lógica limit al número de rangos con nombre en un libro de trabajo.

0

trate de usar: FormatConditions activecell.FormatConditions.Add xlExpression, formula1: = "test_1234" para obtener el valor de ID IDRange = centro (activecell.FormatConditions (1) .formula1,2) "test_1234"

Cuestiones relacionadas