如何使用Excel Dna设置单元格的值?

6

我在我的Excel DNA插件中有以下代码:

在我的AutoOpen方法中,我放置了以下代码:

ExcelIntegration.RegisterUnhandledExceptionHandler(ex => ex.ToString());

我有以下函数,它会从我的Excel表格中调用。
[ExcelFunction(Category = "Foo", Description = "Sets value of cell")]
public static Foo(String idx)
{
        Excel.Application app = (Excel.Application)ExcelDnaUtil.Application;
        Excel.Workbook wb = app.Workbooks[1];
        Excel.Worksheet ws = GetSheet("Main");

        // This gives us the row
        Excel.Name idxRange = wb.Names.Item("COL_Main_Index");
        var row = (int)app.WorksheetFunction.Match(idx, idxRange.RefersToRange, 0);

        // Get the Column
        Excel.Name buyOrderRange = wb.Names.Item("COL_Main_BuyOrder");
        var col = (int)buyOrderRange.RefersToRange.Cells.Column;

        // create the range and update it
        Excel.Range r = (Excel.Range)ws.Cells[row, col];
        r.Value ="Foo"; 
}

问题是我无法实际设置任何单元格的值。当我调用该方法时,会导致最后一行出现错误。
我的错误处理程序给出了以下错误:
{System.Runtime.InteropServices.COMException (0x800A03EC)

我也尝试这样设置单元格的值:

        r = (Excel.Range)ws.Cells[12, 22];
        const int nCells = 1;
        Object[] args1 = new Object[1];
        args1[0] = nCells;
        r.GetType().InvokeMember("Value2", BindingFlags.SetProperty, null, r, args1);

有相同的结果。

有人能指出我在这里可能做错了什么吗?

3个回答

11

实际上,如果您将其作为宏的异步作业执行,可以在任何单元格中编写。

简单示例:

using ExcelDna.Integration;
using Excel = Microsoft.Office.Interop.Excel;

[ExcelFunction(Category = "Foo", Description = "Sets value of cell")]
public static Foo(String idx)
{
    Excel.Application app = (Excel.Application)ExcelDnaUtil.Application;
    Excel.Range range = app.ActiveCell;

    object[2,2] dummyData = new object[2, 2] {
        { "foo", "bar" },
        { 2500, 7500 }
    };

    var reference = new ExcelReference(
        range.Row, range.Row + 2 - 1, // from-to-Row
        range.Column - 1, range.Column + 2 - 1); // from-to-Column

    // Cells are written via this async task
    ExcelAsyncUtil.QueueAsMacro(() => { reference.SetValue(dummyData); });

    // Value displayed in the current cell. 
    // It still is a UDF and can be executed multiple times via F2, Return.
    return "=Foo()";
}

写入单个单元格:

int row = 5;
int column = 6;
var reference = new ExcelReference(row - 1, column - 1);

ExcelAsyncUtil.QueueAsMacro(() => { reference.SetValue("Foobar"); });

// 编辑: 顺便提一下,您也可以使用:

private void WriteArray(object[,] data)
{
    Excel.Application app = (Excel.Application)ExcelDnaUtil.Application;
    Excel.Worksheet worksheet= (Excel.Worksheet)app.ActiveWorkbook.ActiveSheet;

    Excel.Range startCell = app.ActiveCell;
    Excel.Range endCell = (Excel.Range)worksheet.Cells[startCell.Row + data.GetLength(0) - 1, startCell.Column + data.GetLength(1) - 1];

    var writeRange = worksheet.Range[startCell, endCell];
    writeRange.Value2 = data;
}

然后:

object[,] data = ...;    
ExcelAsyncUtil.QueueAsMacro(() =>
{
    WriteArray();
});

这对于第一次调用很有效,但对于所有后续调用都会出现问题。 - neonScarecrow
嗯?我们在Excel Addin(https://github.com/PATRONAS/opuxl)中大量使用这种方法,没有任何问题。对于你的后续调用,它是如何出错的? - ASN
抱歉造成困惑。我的问题与此无关。这最终非常有帮助。ArrayResizer很棒,但我实际上并不想要一个数组。我只是想将内容写入多个单元格,而这个方法做到了。 - neonScarecrow

5

Excel不允许在用户定义的工作表函数中设置其他工作表单元格。这是为了保留Excel用于管理重新计算的依赖树。不管你是使用VBA,C API还是Excel-DNA,都是如此。

最好的方法是添加一个功能按钮、上下文菜单或快捷键来通过宏实现更改。

虽然有一些丑陋的解决方案,但我不建议使用。


其中一个解决方法可以在这里找到: http://excel-dna.net/2011/01/30/resizing-excel-udf-result-arrays/ - Andrew Camilleri 'Kukks'

0

以下是使用 .NET VB 的答案

 Dim row As Integer = 7
        Dim column As Integer = 7
        Dim reference = New ExcelReference(row, column)

        ExcelAsyncUtil.QueueAsMacro(Sub()
                                        reference.SetValue("Test")
                                    End Sub)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接