прежде чем я начну с проблемы, я хочу мотивировать ее. Моя задача состоит в том, чтобы проанализировать изменения в Excel-Sheet, но в отличие от записи изменений через встроенный механизм, изменения должны обнаруживаться программно, и даже если пользователь деактивировал запись изменений или мой Excel-AddIn не установлен. Для этого я использовал Microsoft.Interop.Excel-Library для доступа к листу и ячейкам внутри.
Теперь к проблеме: для поиска изменений, даже если пользователь отсортировал или переместил данные, я хотел иметь уникальный идентификатор для каждой ячейки, которая остается в ней, даже если она перемещена или скопирована. Конечно, если скопировано, идентификатор будет дважды на листе, а новые добавленные ячейки не будут иметь идентификатора, но это нормально. Кроме того, этот идентификатор не должен быть виден пользователю, и пользователь не должен иметь возможность изменять или удалять его.
Итак, я искал поле и нашел Range-Object , который может представлять одну ячейку и имеет разные члены, к которым можно получить доступ. Одно специальное поле привлекло мое внимание, поле ID, которое выглядело так, как я искал.
Guid guid = Guid.NewGuid();
((Range) worksheet.Cells[rowNr, columnNr]).ID = guid.ToString();
, а также читается как
Guid guid = Guid.Parse(((Range) worksheet.Cells[rowNr, columnNr]).ID);
Это было прекрасно, потому что я смог сохранить строку (в данном случае Guid в виде строки, например 123463-fc34-c43a-a391-399fc2) и прочитать ее. Он также прилип к ячейке и был перемещен, когда ячейка была перемещена и т. Д.
Но, к сожалению, это поле ID не сохраняется при сохранении файла, и я не знаю почему. Я имею в виду, что после закрытия и повторного открытия книги все идентификаторы исчезли.
Так что мой вопрос, если есть какой-либо другой член объекта Range, который может содержать строку (= Guid) и который невидим для пользователя. Я пробовал имя-участника и комментарий-члена, но оба они видимы для пользователя и могут быть легко изменены.
Или есть способ сообщить Excel, что я тоже хочу сохранить поле ID при сохранении листа?
Для тестирования вы можете создать проект, добавить ссылку на Microsoft.Office.Interop.Excel-Dll и добавить следующий код (в вашей системе должен быть установлен Excel). Это юнит-тест, который работает с JUnit, но просто удалите Assert-Command, чтобы протестировать его и без JUnit:
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);
}
Буду признателен за любую идею о том, как сохранить идентификатор в ячейке Excel-Worksheet, который сохраняется при сохранении листа или чего-либо еще на эту тему.
Большое спасибо заранее,
Alex
Обновление 14.5.2011:
Поле имени, похоже, не является решением моей проблемы по следующим причинам:
Во-первых, и самым серьезным является тот факт, что кажется, что имя должно быть уникальным, но я хотел дать всем ячейкам подряд один и тот же идентификатор, который не работает.
Во-вторых, доступ к полю имени в C # мне не совсем понятен. Вы можете установить значение с помощью
((Range)worksheet.Cells[rowNr, columnNr]).Name = guid.ToString();
//Remark: Special dealing with guids required,
//if they start with a number or contain special characters.
но у него есть серьезные проблемы. Если имя уже задано, выдается исключение, если имя не было задано, и вы пытаетесь получить к нему доступ с помощью
string name = ((Range)worksheet.Cells[rowNr, columnNr]).Name.Name;
вы получаете исключение. И вам понадобится Name.Name, потому что первое поле имени - это не строка, а целый объект имени, внутри которого есть другое поле имени, содержащее строку.
И, наконец, если вы хотите проверить, есть ли у него имя или нет, вы не можете сделать что-то вроде:
if(((Range)worksheet.Cells[rowNr, columnNr]).Name == null)
//Do something
потому что он уже генерирует исключение при доступе к несуществующему полю имени.