繁体   English   中英

C#:Microsoft.Office.Interop.Excel.Range的ID字段不会与Excel表一起保留

[英]C#: ID-field of Microsoft.Office.Interop.Excel.Range is not persisted with an Excel-sheet

在我开始解决问题之前,我想激励它。 我的任务是分析Excel工作表中的更改,但不同于通过内置机制记录更改,应该以编程方式检测更改,即使用户已停用更改记录或未安装Excel-AddIn。 因此,我使用Microsoft.Interop.Excel-Library来访问工作表和其中的单元格。

现在问题是:为了找到更改,即使用户已经对数据进行了排序或移动,我希望每个单元格都有一个uniqe id,即使被移动或复制也会依赖它。 当然如果复制,表中的id是两次,新添加的单元格没有id,但是没关系。 此外,该ID不应该对用户可见,并且用户不应该能够修改或删除它。

所以我查找了一个字段并找到了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字段不会被保留,我不知道为什么。 我的意思是在关闭并重新打开工作簿之后,所有ID都消失了。

所以我的问题是,如果Range对象中有任何其他成员,那么它可以包含一个字符串(= Guid),并且对用户不可见。 我尝试了Name-Member和Comment-Member,但它们都对用户可见,并且可以轻松修改。

或者有没有办法告诉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);

}

我很感激任何想法,如何在保存工作表或任何有关此主题的内容时将ID存入Excel-Worksheet-Cell。

非常感谢,Alex

更新14.5.2011:

由于以下原因,名称字段似乎不是我的问题的解决方案:

首先,最严重的是这样的事实,似乎名称必须是唯一的,但我想给连续的所有单元格提供相同的ID,这不起作用。

其次,访问C#中的Name-Field对我来说并不是很清楚。 您可以使用设置值

((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,因为第一个Name-field不是字符串而是整个Name-Object,里面有另一个Name-Field,它包含一个字符串。

最后,如果你想检查它是否有名字,你不能做类似的事情:

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

因为它在访问不存在的名称字段时已经抛出异常。

您可以尝试为每个单元格使用命名范围。 这个名字会持续存在。 我没有尝试使用互操作,但它适用于旧的vba。 在下面的代码中,请注意可以向用户隐藏名称。

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 

据我所知,工作簿中命名范围的数量没有逻辑限制

实际上,就像我一样,没有办法直接将ID保存在工作表中。 既不是ID字段(不是持久的),也不是名称(只允许使用唯一名称)或注释(对用户可见)。

但是工作簿中有CustomProperties的概念,它可以包含字符串,并且由于所有可序列化的类都可以编组为字符串,因此程序员可以单独保存ID并在加载工作簿时还原它们。

无论如何,为了我的目的,使用了另一种方法,它计算每一行的哈希值,并比较行哈希值。

尝试使用:FormatConditions activecell.FormatConditions.Add xlExpression,formula1:=“test_1234”获取ID IDRange = mid的值(activecell.FormatConditions(1).formula1,2)“test_1234”

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM