通过标题名称而不是列索引引用 VSTO Excel ListObject 的列
Posted
技术标签:
【中文标题】通过标题名称而不是列索引引用 VSTO Excel ListObject 的列【英文标题】:Reference VSTO Excel ListObject's columns by header name instead of column index 【发布时间】:2011-12-22 13:30:12 【问题描述】:实际上,我可以使用以下代码轻松读取 VSTO 中 ListObject 的内容。
在此示例中,我正在读取给定工作表中的所有产品。使用 Excel 表编辑数据,该表转换为 VSTO 内的 ListObject。我将 VS2010 与 .NET 4.0 以及 Excel 2010 一起使用。
private IEnumerable<Produto> ReadFromWorksheet()
var produtosLidos = new List<Produto>();
try
foreach (Excel.ListRow row in Globals.Sheet1.tblProdutos.ListRows)
var id = RangeUtils.ToInt(row.Range[1, 1]) ?? -1;
var codigo = RangeUtils.ToString(row.Range[1, 2]);
var nome = RangeUtils.ToString(row.Range[1, 3]);
var qtdDisp = RangeUtils.ToDecimal(row.Range[1, 4]);
var unidMed = RangeUtils.ToString(row.Range[1, 5]);
var valor = RangeUtils.ToDecimal(row.Range[1, 6]);
if (string.IsNullOrEmpty(codigo) ||nome == null || qtdDisp == null || unidMed == null || valor == null)
throw new ApplicationException("Os campos Nome, Qtd. Disponível, Unid. de Medida e Valor são obrigatórios.");
var p = new Produto();
p.Id = id;
p.CodigoProduto = codigo;
p.Nome = nome;
p.QtdDisponivel = qtdDisp;
p.UnidadeMedida = unidMed;
p.Valor = valor;
p.DataUltimaAlteracao = DateTime.Now;
p.Acao = RangeUtils.ToString(row.Range[1, 8]);
p.Ativo = true;
produtosLidos.Add(p);
catch (Exception ex)
MessageBox.Show(ex.Message);
return null;
return produtosLidos;
但有时用户想要添加另一行,甚至更改表格的列顺序。所以我想知道是否有更好的方法来通过列名而不是列索引来引用每一行。
一个可接受的解决方案是这样的:
var myValue = row.Range[1, "My Value"];
提前感谢您对此的任何建议。
【问题讨论】:
【参考方案1】:我刚刚遇到了类似的问题。这是我为获取标题名称所做的工作:
private void listSPRData_BeforeDoubleClick(Range Target, ref bool Cancel)
foreach (Range c in Target.ListObject.HeaderRowRange.Cells)
// Do something...
// "c.Value" contains the name of your header.
// When you find your column, you can break to avoid unnecessary looping.
希望这会有所帮助!
【讨论】:
我不得不开发一个定制的解决方案来克服这种情况。基本上,在加载 VSTO 的地方,诀窍是将所有列及其索引映射到字典中,并将此映射存储在类字段中。 public void ReadColumnPositions() cols = new DictionarySheet1.ListObjects("dataTable").DataBodyRange(2, "b").Value
假设您的表名为 dataTable,它有 3 列(a、b、c)和 2 行。
注意:我正在使用 VBA。我认为您在使用 DataBodyRange
时应该可以工作。
var myValue = Sheet1.ListObjects("dataTable").DataBodyRange[1, "myColumnHeader"];
【讨论】:
您好@shahkalpesh,我尝试了这种技术,但没有成功。 VSTO 似乎不接受这种访问列的方式。例外是:类型不匹配。 (来自 HRESULT 的异常:0x80020005 (DISP_E_TYPEMISMATCH))。我尝试使用以下代码: for (int i = 1; i @MárioMeyrelles:你能试试看上面的 VBA 代码是否适用于你的情况,根据你的设置修改表名、工作表名、列名? 再次嗨@shahkalpesh,我在VBA中尝试了这种方法,但没有奏效。 Sub Button1_Click() '工作正常 Debug.Print Sheet6.ListObjects("tblSaidas").DataBodyRange(1, 1).Value '不起作用 Debug.Print Sheet6.ListObjects("tblSaidas").DataBodyRange(1, "Valor Previsto ").Value 结束子 似乎引用 ListObject 列的唯一可能方法是使用它的索引。另一种方法是使用 Range 语法,例如“tblSaida[Valor Previsto]”。无论如何提前谢谢。【参考方案3】:Sheet1.ListObjects("dataTable").ListColumns["ColumnName"].Range[rowOfInterest] 怎么样?
【讨论】:
编译器错误:“不可调用的成员'sheet1.ListObjects'不能像方法一样使用。【参考方案4】:由于 ListObject 不提供该功能,您也可以使用 Range.Find..
Range cellFind = Sheet1.Cells.Find(What: "Column your looking for", After: Type.Missing, LookIn: Excel.XlFindLookIn.xlValues, LookAt: Excel.XlLookAt.xlWhole, SearchOrder: Excel.XlSearchOrder.xlByColumns, SearchDirection: Excel.XlSearchDirection.xlNext, MatchCase: false, SearchFormat: false);
if (cellFind != null)
int columnIndex = cellFind.Column;
...
【讨论】:
【参考方案5】:您可以通过列名直接访问 ListObject 列。 @shahkalpesh 和 @gap 很接近,但 ListObjects 上的索引器习语(VBA,而不是 c#)不匹配。下面的示例构建了一个简单的表,通过名称“ColName2”引用第二列,并修改了第二列中的第一个数据单元格;
object[,] Data = new object[,] "ColName1", "ColName2", 11, 12 , 21, 22 ;
Excel.Range tblRange = Globals.SParameters.Range["B20:C22"];
tblRange.Value = Data;
Globals.SParameters.Controls.AddListObject(tblRange, "tblProdutos");
Globals.SParameters.ListObjects["tblProdutos"].ListColumns["ColName2"].DataBodyRange[1] = 55;
请注意,您可以使用“DataBodyRange”或“Range”; 'DataBodyRange' 不包括列标题,这通常是合适的。
【讨论】:
以上是关于通过标题名称而不是列索引引用 VSTO Excel ListObject 的列的主要内容,如果未能解决你的问题,请参考以下文章
将 A 转换为 1 B 转换为 2 ... Z 转换为 26,然后将 AA 转换为 27 AB 转换为 28(Excel 中列引用的列索引)