【问题标题】:How to delete Excel.Name object?如何删除 Excel.Name 对象?
【发布时间】:2010-07-20 19:44:52
【问题描述】:

我在 Workbook.Names 集合下有一堆 Excel.Name 对象,其中包含无效引用。换句话说,当我评估 Excel.Name.RefersTo 属性时,我得到一个以“=#REF ...”开头的值。我尝试运行以下代码,但删除名称似乎没有效果:

var ranges = myWorkBook.Names;
for (int i = 1; i <= ranges.Count; i++)
{
    var currentName = ranges.Item(i, Type.Missing, Type.Missing);
    var refersTo = currentName.RefersTo.ToString();
    if (refersTo.Contains("REF!"))
    {
        currentName.Delete();
    }
}

谁能建议我在这里做错了什么?或者,也许我错过了一步?

【问题讨论】:

    标签: c# .net-3.5 vsto excel-2007 excel-2003


    【解决方案1】:

    使用名称删除:

    workbook.Names.Item(rangeName, Type.Missing, Type.Missing).Delete();
    

    (在 C# 中)。

    【讨论】:

      【解决方案2】:

      试试Workbook.Names[i].Delete()。您不能使用currentName.Delete。 (根据记忆,我会尝试找到我的代码来执行此操作。)

      【讨论】:

      • 谢谢,我会试一试,然后告诉你结果如何。
      • 最后是 Workbook.Names.Item(i, Type.Missing, Type.Missing) 成功了。感谢您为我指明正确的道路!
      • @code4life:啊,没错。必须调用Item,因为它是一个 COM 调用。
      【解决方案3】:

      我遇到的问题是,当您从活动工作簿中删除一堆名称时,名称集合的索引会立即更新。这可能会导致坏索引/索引超出范围异常。

      如果您想确保删除所有可用的名称,请使用以下代码:

      public void finalize()
          {
              Microsoft.Office.Interop.Excel.Workbook myWorkbook = Globals.ThisAddIn.Application.ActiveWorkbook;
      
      
              var ranges = myWorkbook.Names;
              int leftoveritems;
              leftoveritems = ranges.Count;
      
              while (leftoveritems > 0)
              {
                  int i = 1;
                  try
                  {
                      while (i <= leftoveritems)
                      {
                          myWorkbook.Names.Item(i).Delete();
                          //System.Windows.Forms.MessageBox.Show(i + " deleted.");
                          i++;
                      }
                  }
                  catch (Exception ex)
                  {
                      //System.Windows.Forms.MessageBox.Show(i + " failed " + ex.Message);
                  }
      
                  ranges = myWorkbook.Names;
                  leftoveritems = ranges.Count;
              }
          }
      

      【讨论】:

        【解决方案4】:

        AMissico 引导我朝着正确的方向前进。 currentName.Delete() 绝对不行。但是 VSTO 2005 SE 下不支持 Workbook.Names[i].Delete,所以我又挖了一些,发现 Workbook.Names.Item(i, Type.Missing, Type.Missing) 成功了。

        这是一个有效的代码示例:

        var ranges = myWorkBook.Names;
        
        int i = 1;
        while (i <= ranges.Count)
        {
            var currentName = ranges.Item(i, Type.Missing, Type.Missing);
            var refersTo = currentName.RefersTo.ToString();
            if (refersTo.Contains("REF!"))
            {
                ranges.Item(i, Type.Missing, Type.Missing).Delete();
            }
            else
            {
                i++;
            }
        }
        

        【讨论】:

        • 刚刚测试过这个。它可以工作,但请注意,如果您为工作簿和工作表命名的范围在其他方面相同,则在工作簿范围名称索引上调用 delete 将改为删除工作表范围名称。除了首先删除工作表范围范围之外,我还没有找到解决此问题的方法。
        【解决方案5】:

        我只是将它设置为 VBA 函数,然后从 C# 中调用它:

        VBA(如果您只想删除引用错误命名范围,可以取消注释一行):

        Sub DeleteNamedRanges()
           Dim nm As Object
           Dim mystr As String
        
           For Each nm In ThisWorkbook.Names
              On Error Resume Next
              'If InStr(1, nm.RefersTo, "#REF!") Then
              nm.Delete
              On Error GoTo 0
           Next
        End Sub
        

        C#:

        XlApp.Application.Run($"'{fileName}'!{yourWorksheet.CodeName}.DeleteNamedRanges");
        

        关于 C# 的注意事项,就我而言,我将该 VBA 放入特定工作表的代码中,因为我将该工作表复制到其他工作簿中,并且我希望它可以在这些工作簿中访问,因此我必须调用完全限定路径VBA 方法。如果您不需要类似的东西,只需将 VBA 代码放入 ThisWorkbook 或模块并更直接地调用它会简单得多。

        【讨论】:

        • 我必须将 VBA 注入目标工作簿,然后调用它...当然必须有更简单的方法来做到这一点。
        • 如果您纯粹从头开始创建工作簿(即仅在 C# 代码中,不使用 wb 模板或不从现有/打开的工作簿中复制任何内容),那么可以,不是最好的。但是,如果您已经有一个模板或您知道要复制的工作表,那么只需预先包含 VBA 代码就很容易,您就会知道它会在那里供您调用。
        猜你喜欢
        • 2013-10-28
        • 2019-11-25
        • 1970-01-01
        • 2011-05-09
        • 1970-01-01
        • 1970-01-01
        • 2011-01-12
        • 2013-03-21
        • 2023-03-16
        相关资源
        最近更新 更多