C #: ID-field de Microsoft.Office.Interop.Excel.Range n'est pas persisté avec une feuille Excel

Avant de commencer par le problème, je veux le motiver. Ma tâche est d'parsingr les changements dans une feuille de Excel, mais différente des modifications d'logging via le mécanisme de construction, les modifications doivent être détectées par programme et même si l'user a désactivé l'logging des modifications ou mon Excel-AddIn n'est pas installé. Pour cela, j'ai utilisé Microsoft.Interop.Excel-Library pour accéder à une feuille et aux cellules.

Maintenant au problème: pour find des changements, même si l'user a sortingé ou déplacé datatables, je voulais avoir un identifiant uniqe par cellule, ce qui y adhère, même s'il est déplacé ou copié. Bien sûr, si copié, l'id est deux fois dans la feuille et les nouvelles cellules ajoutées n'ont pas d'identifiant, mais ça va. Plus loin, cette ID ne devrait pas être visible pour l'user et l'user ne devrait pas pouvoir le modifier ou le supprimer.

J'ai donc cherché un champ et trouvé l' object Range qui peut représenter une seule cellule et a des membres différents auxquels on peut accéder. Un domaine spécial a attiré mon attention, le champ d'identification, qui ressemblait à ce que je recherchais.

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

et aussi être lu comme

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

C'était parfait, parce que je pouvais stocker une string (dans ce cas un Guid en tant que string, comme 123463-fc34-c43a-a391-399fc2) et la lire. Il a également collé à la cellule, et a été déplacé, lorsque la cellule a été déplacée, etc.

Mais malheureusement, ce champ d'identification n'est pas persisté, lorsque le file est sauvegardé et je ne sais pas pourquoi. Je veux dire qu'après la fermeture et la réouverture d'un classur, tous les identifiants sont partis.

Donc, ma question est, s'il y a un autre membre de l'object Range, qui peut contenir une string (= Guid) et qui n'est pas visible pour l'user. J'ai essayé le nom-membre et le membre du commentaire, mais tous deux sont visibles pour l'user et peuvent être modifiés facilement.

Ou y a-t-il un moyen de dire à Excel, que je veux save le champ ID, lors de la sauvegarde de la feuille?

Pour tester, vous pouvez créer un projet, append une reference à Microsoft.Office.Interop.Excel-Dll et append le code suivant (vous devez avoir installé Excel sur votre système). C'est un test unitaire, qui fonctionne avec JUnit, mais supprimez simplement Assert-Command pour le tester sans JUnit aussi:

 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 ssortingng 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.ToSsortingng(); //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 ssortingng 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.ToSsortingng(), guid1); } système d'utilisation; 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 ssortingng 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.ToSsortingng(); //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 ssortingng 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.ToSsortingng(), guid1); } { 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 ssortingng 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.ToSsortingng(); //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 ssortingng 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.ToSsortingng(), guid1); } 

J'apprécierais toute idée, comment mettre un identifiant dans une feuille de calcul Excel qui persiste lors de la sauvegarde de la feuille de calcul ou de tout ce sujet sur ce sujet.

Merci beaucoup, Alex

Mise à jour 14.5.2011:

Le champ Nom ne semble pas être une solution à mon problème pour les raisons suivantes:

Tout d'abord, et le plus sérieux est le fait qu'il semble que le nom doit être unique, mais je voulais donner à toutes les cellules d'une même ligne le même identifiant, ce qui ne fonctionne pas.

Deuxièmement, l'access au champ Nom dans C # n'est pas vraiment clair pour moi. Vous pouvez définir la valeur avec

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

mais il a des problèmes sérieux. Si le nom était déjà défini, il lance une exception, si aucun nom n'a été défini, et vous essayez d'y accéder

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

vous obtenez une exception. Et vous avez besoin du Name.Name, car le premier Name-field n'est pas la string, mais un Name-Object entier, qui possède un autre champ de nom contenant une string.

Et enfin, si vous voulez vérifier s'il a un nom ou non, vous ne pouvez pas faire quelque chose comme:

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

car il jette déjà une exception lors de l'access à un champ de nom existant.

Vous pouvez essayer d'utiliser une plage nommée pour chaque cellule. Le nom persistera. Je n'ai pas essayé cela avec interop mais ça marche avec un bon vieux vba. Dans le code ci-dessous, notez que les noms peuvent être cachés à l'user.

 Function try() Dim x As Integer Dim y As Ssortingng 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 

D'après ce que je comprends, il n'y a pas de limite logique au nombre de plages nommées dans un classur.

En fait, il n'y a aucun moyen de persister l'ID directement dans la feuille, car je l'ai fait. Ni dans le champ ID (qui n'est pas persisté), ni comme noms (seuls les noms uniques exclus) ou les commentaires (sont visibles pour l'user).

Mais il existe le concept de CustomProperties dans un classur, qui peut contenir des strings de caractères, et puisque toutes les classs sérialisables peuvent être transmises aux strings, cela permet au programmeur de persévérer les identifiants séparément et de les restaurer lors du chargement d'un classur.

Quoi qu'il en soit, pour mon but, une autre approche a été utilisée, qui calcule les valeurs de hash de chaque ligne et compare les valeurs de ligne-hash à la place.

essayez d'utiliser: FormatConditions activecell.FormatConditions.Add xlExpression, formula1: = "test_1234" pour get une valeur pour ID IDRange = mid (activecell.FormatConditions (1) .formula1,2) "test_1234"