在 Excel C# 范围内写入一个二维对象数组

Posted

技术标签:

【中文标题】在 Excel C# 范围内写入一个二维对象数组【英文标题】:Write a 2D array of objects in range Excel C# 【发布时间】:2018-04-12 15:35:00 【问题描述】:

我使用 c# 在 excel 中创建了一个新的用户定义函数,excelDna 加载项,我想要得到的是当用户打开一个 excel 文件时,单击一个单元格并写入 =myFunction() 按回车,数据应该是显示在 excel 文件中。这些数据是从 sql server 数据库中检索的,并存储在一个二维对象数组中,我的问题是当我尝试在 excel 范围内显示这个数组时,我得到了这个异常 HRESULT 异常:0x800A03EC 以下是我的代码:

public static void LoadViewData()
  
      var target = (ExcelReference)XlCall.Excel(XlCall.xlfCaller);
      var sheetName = (string)XlCall.Excel(XlCall.xlSheetNm, target);
      var application = (Microsoft.Office.Interop.Excel.Application)ExcelDnaUtil.Application;
      var sheet = application.Sheets[Regex.Replace(sheetName, @"\[[^]]*\]", string.Empty)];
      object[,] result = LoadFromDbData();
      var startCell =sheet.Cells[target.RowFirst + 1, target.ColumnFirst];
      var endCell =sheet.Cells[target.RowFirst+ result.GetUpperBound(0) - result.GetLowerBound(0) + 1,
          target.ColumnFirst+ result.GetUpperBound(1) - result.GetLowerBound(1) + 1];
      var writeRange = sheet.Range[startCell, endCell];

      writeRange.Value2 = result;

  

target 返回用户编写公式的单元格的正确值 (=myFunction()) sheetName 返回用户在其中编写公式的正确 activeSheet result 包含从 sql server 检索到的数据,它是一个 object[854,8] 数组 startcell 和 endcell 表示将显示单元格数据的范围 调试时,所有变量都包含正确的值,该指令出现异常:

writeRange.Value2 = result;

有人已经用过这个或者可以帮忙吗? 谢谢

【问题讨论】:

您似乎正试图从用户定义的函数修改 Excel 工作表,该函数是从工作表公式调用的。 Excel 不允许这样做(Range.Value = ... 在 UDF 函数中调用时总是会失败)。您需要从功能区按钮或其他东西运行代码。在这种情况下,您必须从使用“调用者”更改为让 ActiveCell 决定更新位置。 【参考方案1】:

我认为您的“LoadFromDbData()”正在返回输入的数据。尝试将每个值转换为字符串。这是一个示例(如果我不转换为字符串,我可以重新创建该错误代码):

void Main()

  var tbl = new System.Data.DataTable();
  new SqlDataAdapter(@"
  WITH  tally ( OrderNo, UniqueId, RandNumber )
        AS (
             SELECT TOP 50000
                    ROW_NUMBER() OVER ( ORDER BY t1.object_id ), 
                    NEWID(),
                    CAST(CAST(CAST(NEWID() AS VARBINARY(4)) AS INT) AS DECIMAL) / 1000
             FROM   master.sys.all_columns t1
             CROSS JOIN master.sys.all_columns t2
           )
  SELECT  OrderNo, 
    DATEADD(DAY, -OrderNo, GETDATE()) as OrnekDate, 
    UniqueId, RandNumber, 
    abs(RandNumber)%100 / 100 as pct
  FROM [tally];", @"server=.\SQLExpress;Database=master;Trusted_Connection=yes;").Fill(tbl);

  object[,] arr = new object[tbl.Rows.Count + 1, tbl.Columns.Count];
  for (int i = 0; i < tbl.Columns.Count; i++)
  
    arr[0, i] = tbl.Columns[i].Caption;
  
  for (int i = 0; i < tbl.Rows.Count; i++)
  
    for (int j = 0; j < tbl.Columns.Count; j++)
    
      arr[i + 1, j] = tbl.Rows[i][j].ToString(); // without .ToString() you should have the error
    
  

  // Excel dosya yarat ve arrayi koy
  Microsoft.Office.Interop.Excel.Application xl = new Microsoft.Office.Interop.Excel.Application();
  var workbook = xl.Workbooks.Add();
  xl.Visible = true;

 Worksheet sht = ((Worksheet)workbook.ActiveSheet);
 Range target = (Range)sht.Range[ (Range)sht.Cells[1,1], (Range)sht.Cells[arr.GetUpperBound(0)+1,arr.GetUpperBound(1)+1] ];
 target.Value2 = arr;


注意:作为旁注,为什么要将数据作为二维数组传输?这是其中一种方法,但要注意它是有限的(我不知道上限的好值 - 尝试像 200K 行这样的高数字)。 根据我的经验,最好通过 QueryTables.Add 或 CopyFromRecordSet 将数据输入 excel。根据您的需要,您也可以直接将 Excel 文件本身用作数据表并进行插入。 Nuget 上还有 EPPlus 库,但这会有点慢 + 可能不包含您需要的所有功能。

【讨论】:

以上是关于在 Excel C# 范围内写入一个二维对象数组的主要内容,如果未能解决你的问题,请参考以下文章

如何将值设置为二维 Excel 范围?

为啥在 C# 中的二维数组中按列写入速度很慢

从阵列写入单元格时是否需要指定范围?

为啥在 C# .NET 中写入 Excel 范围所需的时间比预期的要长得多?

Unity3d在屏幕范围内随机生成一个圆

如何在二维数组的范围内使用 flatMap() 和 reduce()