6

問題を始める前に、それをやる気にさせたいと思います。私の仕事はExcelシートの変更を分析することですが、ビルド内のメカニズムを介して変更を記録するのとは異なり、変更はプログラムで検出する必要があります。ユーザーが変更の記録を無効にしたり、Excel-AddInがインストールされていない場合でも変更を検出する必要があります。そのため、Microsoft.Interop.Excel-Libraryを使用して、シートとその中のセルにアクセスしました。

ここで問題になります。変更を見つけるために、ユーザーがデータを並べ替えたり移動したりした場合でも、移動またはコピーした場合でも、セルごとに一意のIDを保持する必要がありました。もちろん、コピーされた場合、IDはシートに2回あり、新しく追加されたセルにはIDがありませんが、それは問題ありません。さらに、このIDはユーザーに表示されないようにし、ユーザーがIDを変更または削除できないようにする必要があります。

そこで、フィールドを探して、単一のセルを表すことができ、アクセスできるさまざまなメンバーを持つRange-Objectを見つけました。私が探していたもののように見えるIDフィールドという1つの特別なフィールドが私の注意を引きました。

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を試しましたが、どちらもユーザーに表示され、簡単に変更できます。

または、シートを保存するときにIDフィールドも保存するようにExcelに指示する方法はありますか?

テストのために、プロジェクトを作成し、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-CellにIDを配置する方法についてのアイデアをいただければ幸いです。

よろしくお願いします、アレックス

アップデート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

存在しない名前フィールドにアクセスすると、すでに例外がスローされるためです。

4

3 に答える 3

2

実際、私が思っているように、IDをシートに直接保持する方法はありません。IDフィールド(永続化されない)にも、名前(一意の名前のみが許可される)またはコメント(ユーザーに表示される)としても表示されません。

ただし、ワークブックには文字列を保持できるCustomPropertiesの概念があり、シリアル化可能なすべてのクラスを文字列にマーシャリングできるため、プログラマーはIDを個別に保持し、ワークブックの読み込み時に復元できます。

とにかく、私の目的のために、各行のハッシュ値を計算し、代わりにline-hash-valuesを比較する別のアプローチが使用されました。

于 2011-07-13T06:52:15.183 に答える
1

セルごとに名前付き範囲を使用してみることができます。名前は存続します。私はこれを相互運用で試していませんが、古き良き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 

私が理解していることから、ブック内の名前付き範囲の数に論理的な制限はありません。

于 2011-05-13T21:09:03.720 に答える
0

使用してみてください:FormatConditions activecell.FormatConditions.Add xlExpression、formula1:= "test_1234"を使用して、ID IDRange = mid(activecell.FormatConditions(1).formula1,2)"test_1234"の値を取得します

于 2016-02-15T04:49:14.163 に答える