使用C#Interop.Excel删除NamesManager中的重复名称

我正在面临一些问题,从C#代码中删除名称NAmesManager。 根据我的要求,我需要从名称pipe理器中删除所有的无效名称。 我正在检查名称的值,并删除它,如果值是“#REF!”。 这是我正在使用的代码

foreach (Name RangeName in namesManager2) { if(RangeName.Value.Contains("#REF!")) { RangeName.Delete(); } } 

代码工作正常,但有一些奇怪的情况下,有两个名称相同的名称,但范围是不同的。 考虑将单元格1命名为“TESTNAME”,范围为“Workbook”,单元格2也命名为“TESTNAME”,范围为“Sheet1”。 引用Cell2的名称具有有效值。

所以当我循环如果名称与“#REF!” 以上代码遇到的值是删除这两个名字。 我想保留名称的有效值,但只删除无效的名称。

有人可以build议如何做到这一点?

有重复的本地/全局名称的错误。
在活动工作表具有本地名称相同的名称的同时,访问全局名称将更改本地名称的属性,而不是全局名称,即使名称是使用工作簿名称完全限定的。

所以要绕过这个,你必须:
– 检测名称是否重复
– 如果是这样,切换到不是本地名称的父级的工作表(当然,可能有多个本地名称,每个表上一个,所以唯一真正安全的方法是添加另一个临时工作表并切换到该表)
– 然后在“工作簿名称”集合或工作表名称集合中访问所需的任何名称。

这是由JK Pieterse和我自己开发的免费的名称pipe理器Addin使用的技术:
姓名pipe理下载
它比内置的Name Manager有更多的function

我build议你使用名称范围的唯一名称来避免这种问题。

 var activeBook = (Workbook)currentInstance.ActiveWorkbook; Range rnArea = activeSheet.Range["A1:A1"]; activeBook.Names.Add("TESTNAME", rnArea); rnArea = activeSheet.Range["B1:B1"]; activeSheet.Names.Add("TESTNAME", rnArea); List<Name> existingNamedRangeList1 = XlHelper.GetNamedRanges(currentInstance.ActiveWorkbook); foreach (Name RangeName in existingNamedRangeList1) { if (RangeName.Value.Contains("#REF!")) { RangeName.Delete(); } } 

不幸的是,它看起来像假设名称将是唯一的,因此所做的任何删除将不会有预期的行为。 解决这个问题的一个方法是在遍历所有RangeNames时生成一个唯一的名称,然后在完成删除操作后将它们重置为原始名称。

 var rangeNameHolder = new Dictionary<string, string>(); var rangeNames = activeBook.Names; int counter = 0; foreach (Name rangeName in rangeNames) { var oldName = rangeName.Name; /* * This hack here is done because when you grab the name, it includes the prepended scope. * However, when you set the name, it prepends the scope yet again! * So when you grab it the first time you need to remove the scope so that it doesnt get * prepended twice */ oldName =oldName.Substring(oldName.LastIndexOf('!')+1); var newName = string.Format("{0}{1}", oldName, counter++); rangeName.Name = newName; if (rangeName.Value.Contains("#REF!")) { rangeName.Delete(); continue; } rangeNameHolder.Add(rangeName.Name,oldName); } //Reset names back to original foreach (Name rangeName in rangeNames) { if (rangeNameHolder.ContainsKey(rangeName.Name)) rangeName.Name = rangeNameHolder[rangeName.Name]; }