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.