在撤销 Excel 表自动扩展/调整大小后引用 ListObject 导致 COMException: 'Exception from HRESULT: 0x800A01A8'

问题描述

我正在处理一种 ListObject 数据的缓存,并发现了一个可能的错误,即在用户撤消表自动扩展/调整大小后 ListObject 对象引用消失了。

重现步骤:

  1. 使用如下图所示的简单表格创建 Excel 文件图片下方的 GIF 表示导致可能出现问题的操作)

enter image description here

enter image description here

  1. 创建 .NET Framework 控制台应用程序(在我的例子中是 4.7.2)

  2. 添加对 Microsoft.Office.Interop.Excel 的引用(最新版本没问题)

  3. 将以下代码复制并粘贴到 Program.cs 中(它会打开 Excel,打开示例工作簿,订阅 SheetChange 事件并可选择更改表格而不是您 - 如果您想手动研究问题 - 步骤重现在代码片段中,并在步骤 1 后查看提供的 GIF 以查看导致问题的操作)

  4. 进一步的复制步骤在代码注释中提到

     // Steps to replicate bug:
     // 1. Change filePath variable to point to the example file and uncomment the "DoAutomaticChanges()" line (50).
     // 2. Run app,watch the Excel window to view the steps and the SheetChange event handler will report 
     //    System.Runtime.InteropServices.COMException: 'Exception from HRESULT: 0x800A01A8' when trying to 
     //    access the ListObject after last cell value change in table.
     //
     // Manual way to replicate bug:
     // 1. Change filePath variable to point to the example file. 
     // 2. Comment out the "DoAutomaticChanges()" line (50).
     // 3. Start the app and let it open the example workbook.
     // 4. Select a couple of cells in the row beneath the table (example range to select D13:E13)
     // 5. Enter "test" and press CTRL + Enter
     // 6. Press CTRL + Z twice (the bug presents itself even if you undo once and try to edit a random table cell)
     // 7. Edit random cell in table and the SheetChange event handler will report 
     //    System.Runtime.InteropServices.COMException: 'Exception from HRESULT: 0x800A01A8' when trying to access the ListObject.
     static Worksheet sheet;
     static Application excel;
     static void Main(string[] args)
     {
         var tableName = "ExampleTableName";
         var filePath = @"C:\Users\...\ExampleBook.xlsx";
         excel = new Application
         {
             Visible = true
         };
    
         var wb = excel.Workbooks.Open(filePath);
         sheet = wb.Sheets[1] as Worksheet;
         var listObject = 
             sheet
             .ListObjects
             .OfType<ListObject>()
             .Single(lo => lo.Name == tableName);
    
         wb.SheetChange += (s,e) =>
         {
             var test = listObject.Range;
         };
    
         //DoAutomaticChanges();
         Console.ReadLine();
         wb.Close(false);
         excel.Quit();
     }
    
     private static void DoAutomaticChanges()
     {
         sheet.Range[sheet.Cells[13,4],sheet.Cells[13,5]].Select();
         Thread.Sleep(500);
         excel.SendKeys("test^~");
         Thread.Sleep(500);
         excel.SendKeys("^z");
         Thread.Sleep(500);
         excel.SendKeys("^z");
         Thread.Sleep(500);
    
         // this approach represents user interaction and makes the ListObject unavailable
         sheet.Range[sheet.Cells[6,5],sheet.Cells[6,5]].Value2 = "test";
    
         // this approach works from code without losing reference of ListObject,but does not represent actual user interaction
         //sheet.Range[sheet.Cells[6,5]].Select();
         //excel.SendKeys("test");
     }
    

这是预期的行为吗?

在抛出异常并发现存在 ListObject 后,我​​尝试从工作簿中获取所有表,因此我对问题的理解是在撤消自动扩展/调整大小时以某种方式创建了一个新表而不是旧表。关于这个问题有什么想法吗?

我当前的解决方法 -> 我存储 ListObject 的名称,当异常发生时,我再次从当前工作簿中获取具有相同名称的 ListObject。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)