简体   繁体   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

before I start with the problem, I want to motivate it. 在我开始解决问题之前,我想激励它。 My task is to analyse changes in an Excel-Sheet, but different from recording changes via the in-build mechanism the changes should be detected programmatically and even if the user deactivated the recording of changes or my Excel-AddIn is not installed. 我的任务是分析Excel工作表中的更改,但不同于通过内置机制记录更改,应该以编程方式检测更改,即使用户已停用更改记录或未安装Excel-AddIn。 Therefor I've used Microsoft.Interop.Excel-Library to access a sheet and the cells within. 因此,我使用Microsoft.Interop.Excel-Library来访问工作表和其中的单元格。

Now to the problem: For finding changes, even if the user has sorted or moved the data, I wanted to have a uniqe id per cell, which sticks to it, even if moved or copied. 现在问题是:为了找到更改,即使用户已经对数据进行了排序或移动,我希望每个单元格都有一个uniqe id,即使被移动或复制也会依赖它。 Of course if copied, the id is twice in the sheet and new added cells have no id, but that is ok. 当然如果复制,表中的id是两次,新添加的单元格没有id,但是没关系。 Further on, this ID should not be visible to the user and the user should not be able to modify or delete it. 此外,该ID不应该对用户可见,并且用户不应该能够修改或删除它。

So I looked for a field and found the Range-Object which can represent a single cell and has different members which can be accessed. 所以我查找了一个字段并找到了Range-Object ,它可以代表一个单元格,并且具有可以访问的不同成员。 One special field drew my attention, the ID-field, which looked like what I was searching for. 一个特殊的领域引起了我的注意,ID领域,看起来像我正在寻找的。

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

and also be read like 并且也可以像

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

This was perfect, because I was able to store a string (in this case a Guid as a string, like 123463-fc34-c43a-a391-399fc2) and read it. 这是完美的,因为我能够存储一个字符串(在这种情况下是一个字符串Guid,如123463-fc34-c43a-a391-399fc2)并读取它。 It also stuck to the cell, and was moved, when the cell was moved etc. 当细胞移动时,它也粘在细胞上,移动了

But unfortunately this ID-field is not persisted, when the file is saved, and I don't know why. 但不幸的是,当文件被保存时,这个ID字段不会被保留,我不知道为什么。 I mean that after closing and reopening a workbook, all IDs are gone. 我的意思是在关闭并重新打开工作簿之后,所有ID都消失了。

So my question is, if there is any other member of the Range object, that can hold a string (=Guid), and which is not visible to the user. 所以我的问题是,如果Range对象中有任何其他成员,那么它可以包含一个字符串(= Guid),并且对用户不可见。 I tried the Name-Member and the Comment-Member, but both of them are visible to the user, and can be modified easily. 我尝试了Name-Member和Comment-Member,但它们都对用户可见,并且可以轻松修改。

Or is there a way of telling Excel, that I want to save the ID-field too, when saving the sheet? 或者有没有办法告诉Excel,我还想在保存工作表时保存ID字段?

For testing, you can create a project, add a reference to the Microsoft.Office.Interop.Excel-Dll and add the following code (you must have Excel installed on your system). 对于测试,您可以创建项目,添加对Microsoft.Office.Interop.Excel-Dll的引用并添加以下代码(您必须在系统上安装Excel)。 It is a unit-test, that runs with JUnit, but simply remove the Assert-Command to test it without JUnit too: 它是一个单元测试,使用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);

}

I would appreciate any idea, how to put an ID to an Excel-Worksheet-Cell that is persisted, when saving the worksheet or anything on this subject. 我很感激任何想法,如何在保存工作表或任何有关此主题的内容时将ID存入Excel-Worksheet-Cell。

Many thanks in advance, Alex 非常感谢,Alex

Update 14.5.2011: 更新14.5.2011:

The Name-field seems not to be a solution to my problem for the following reasons: 由于以下原因,名称字段似乎不是我的问题的解决方案:

First, and most serious is the fact, that it seems that the name must be unique, but I wanted to give all cells in a row the same ID, which doesn't work. 首先,最严重的是这样的事实,似乎名称必须是唯一的,但我想给连续的所有单元格提供相同的ID,这不起作用。

Second, to access the Name-Field in C# is not really clear to me. 其次,访问C#中的Name-Field对我来说并不是很清楚。 You can set the value with 您可以使用设置值

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

but it has serious issues. 但它有严重的问题。 If the name was already set, it throws an exception, if no name was set, and you try to access it with 如果名称已设置,则会抛出异常,如果未设置名称,则尝试使用该名称进行访问

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

you get an exception. 你得到一个例外。 And you need the Name.Name, because the first Name-field is not the string but a whole Name-Object, which inside has another Name-Field which contains a string. 你需要Name.Name,因为第一个Name-field不是字符串而是整个Name-Object,里面有另一个Name-Field,它包含一个字符串。

And finally, if you want to check if it has a name or not, you cannot do something like: 最后,如果你想检查它是否有名字,你不能做类似的事情:

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

because it already throws an exception when accessing a not existing Name-field. 因为它在访问不存在的名称字段时已经抛出异常。

You can try using a named range for each cell. 您可以尝试为每个单元格使用命名范围。 The name will persist. 这个名字会持续存在。 I have not tried this with interop but it works with good old vba. 我没有尝试使用互操作,但它适用于旧的vba。 In the code below, note that the names can be hidden from the user. 在下面的代码中,请注意可以向用户隐藏名称。

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 

From what I understand there is no logical limit to the number of named ranges in a workbook. 据我所知,工作簿中命名范围的数量没有逻辑限制

Actually there is no way to persist the ID directly in the sheet as I though of it. 实际上,就像我一样,没有办法直接将ID保存在工作表中。 Neither in the ID-field (which is not persisted), nor as Names (only unique names allowed) or Comments (are visible to the user). 既不是ID字段(不是持久的),也不是名称(只允许使用唯一名称)或注释(对用户可见)。

But there is the concept of CustomProperties in a workbook, which can hold strings, and since all serializable classes can be marshalled to strings, this allows the programmer to persist the IDs separately and restore them upon loading of a workbook. 但是工作簿中有CustomProperties的概念,它可以包含字符串,并且由于所有可序列化的类都可以编组为字符串,因此程序员可以单独保存ID并在加载工作簿时还原它们。

Anyway, for my purpose another approach was used, that calculates hash-values of each line and compares the line-hash-values instead. 无论如何,为了我的目的,使用了另一种方法,它计算每一行的哈希值,并比较行哈希值。

尝试使用: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.

相关问题 C#Excel插件-编译警告-类型库导出器找不到Microsoft.Office.Interop.Excel.Range的类型库 - C# Excel Addon - Compilation warning - Type library exporter could not find the type library for Microsoft.Office.Interop.Excel.Range 获取Microsoft.Office.Interop.Excel.Range的所有单元格坐标 - Get all cells coordinates for a Microsoft.Office.Interop.Excel.Range 如何使用Moq模拟Microsoft.Office.Interop.Excel.Range? - How to mock Microsoft.Office.Interop.Excel.Range with Moq? 无法将透明代理转换为类型“Microsoft.Office.Interop.Excel.Range” - Unable to cast transparent proxy to type 'Microsoft.Office.Interop.Excel.Range' 使用Microsoft.Office.Interop在C#中的Excel工作表中行和列范围的条件着色 - using Microsoft.Office.Interop Conditional coloring of the rows and column range in a excel sheet in C# 无法将类型“对象”隐式转换为“ Microsoft.Office.Interop.Excel.Range” - Cannot implicitly convert type 'object' to 'Microsoft.Office.Interop.Excel.Range' 使用Mock将属性Row设置为Mocked Microsoft.Office.Interop.Excel.Range - Setting property Row to Mocked Microsoft.Office.Interop.Excel.Range with Mock Microsoft.Office.Interop.Excel.Range的Type.GetProperties返回空数组 - Type.GetProperties of Microsoft.Office.Interop.Excel.Range returns empty array 'Microsoft.Office.Interop.Excel.Range'不包含'get_Default'的定义 - 'Microsoft.Office.Interop.Excel.Range' does not contain a definition for 'get_Default' 使用旧版本 Excel (2003) 的 Microsoft.Office.Interop.Excel.Range 对象获取索引超出范围异常 - Get Index out of range exception using Microsoft.Office.Interop.Excel.Range object for old version of Excel (2003)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM