SpreadsheetGear API 本身无法解决您的问题。如果您的用户能够删除(或插入或重新排列)列,并且您无法知道哪些列受到了影响,那么鉴于您在上面提供的工作表方案,您完全不走运。
要考虑此类操作,您需要在工作表列中添加某种形式的“元数据”,以便您跟踪此操作。正如您所指出的,如果您有类似以下内容,其中 [括号] 行表示列标题...
[ A ] [ B ] [ C ] [ D ] [ E ] [ F ] [ G ]
1 2 3 4 5 6 7
...如果用户删除了 D 列和 E 列,您将得到以下信息:
[ A ] [ B ] [ C ] [ D ] [ E ] [ F ] [ G ]
1 2 3 6 7
要检测到这一点,您可以在每列的某处引入一些已知值,以便检查其是否存在,例如工作表第 1 行上您自己的“标题”行,例如:
[ A ] [ B ] [ C ] [ D ] [ E ] [ F ] [ G ]
Col A Col B Col C Col D Col E Col F Col G
1 2 3 4 5 6 7
如果 D 列和 E 列被删除,例如...
[ A ] [ B ] [ C ] [ D ] [ E ] [ F ] [ G ]
Col A Col B Col C Col F Col G
1 2 3 6 7
...那么当您遍历第一行中的每一列并将其与您自己的已知标题名称列表(即“Col A”、“Col B”等)进行比较时,您大概能够检测到.) 并相应地处理它。如果您的用户还可以插入列或重新排序列,您可能需要在此例程中构建更大的灵活性来处理此类情况。
如果您能够为客户提供一个“模板”文件,他们可以为其填充数据,而不是依赖于每列中某个单元格中是否存在某些信息,那么更强大的解决方案可能是将每一列设置为具有与其关联的定义名称。例如,下面的 SpreadsheetGear 代码将为列 A 到 D 指定特定名称:
using SpreadsheetGear;
...
IWorkbook workbook = Factory.GetWorkbook();
IWorksheet worksheet = workbook.Worksheets["Sheet1"];
worksheet.Names.Add("ProductColumn", "=$A:$A");
worksheet.Names.Add("PriceColumn", "=$B:$B");
worksheet.Names.Add("QuantityColumn", "=$C:$C");
worksheet.Names.Add("TotalColumn", "=$D:$D");
workbook.SaveAs(@"c:\path\to\workbook.xlsx", FileFormat.OpenXMLWorkbook);
// Give this workbook to your client to populate with data....
然后,当您取回填充的文件时,要检查已删除的列,您可以执行以下操作:
// Open populated workbook from customer. Columns could have been deleted, inserted or reordered...
IWorkbook workbook = Factory.GetWorkbook(@"c:\path\to\workbook.xlsx");
IWorksheet worksheet = workbook.Worksheets["Sheet1"];
// You'll need a list of known defined names for each column.
List<string> names = new List<string>() { "ProductColumn", "PriceColumn", "QuantityColumn", "TotalColumn" };
foreach (string name in names)
{
// The INames[...] indexer will return null if the name is not found.
IName definedName = worksheet.Names[name];
if (definedName == null)
{
Console.WriteLine($"They deleted column {name}!");
}
}
归根结底,您需要在工作表本身的每一列中拥有某种识别信息,以检测此类更改。如果您几乎无法控制原始工作簿,那么您可能无法检测到此类更改。