将包含Excel公式的数据对象数组插入到给定范围

时间:2017-07-20 12:10:11

标签: c# excel winforms excel-interop

我有一个dataobject数组对象[,]来自通过SqlDataAdapter加载的SQL数据库表,它包含Excel公式。

我想将对象粘贴到已打开的Excel文件中的某个范围内。

我应该补充一点,当数据表中包含“这是一个测试”之类的字符串而不是像“= SUM(A1:A5)”这样的Excel公式时,一切正常

但我一直在遇到对我毫无意义的异常。请指教!

这就是我所拥有的。我在俯瞰什么?

    private void InsertBridgeCalcBlock()
    {
        Excel.Application xlApp = (Excel.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application");

        try
        {
            xlActiveCell = xlApp.ActiveCell;
            DataTable dt = new DataTable();

            try
            {
                using (SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM " + sDBBridgeCalcTable, conn))
                {
                    da.Fill(dt);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error Message:" + Environment.NewLine + ex);
            }

            object[,] BridgeCalcTable = new object[dt.Rows.Count + 1,dt.Columns.Count];
            for (var i = 0; i < dt.Rows.Count; i++)
                for (var j = 1; j < dt.Columns.Count; j++)
                {
                    BridgeCalcTable[i, j-1] = dt.Rows[i][j];
                }

            Excel.Range insertBridgeCalcTableRange = xlApp.Range[xlApp.ActiveSheet.Cells[xlActiveCell.Row-2, 11], xlApp.ActiveSheet.Cells[xlActiveCell.Row-2 + dt.Rows.Count - 1, 11 + dt.Columns.Count]]; // set insertrange
            xlApp.ActiveSheet.EnableCalculation = true;
            insertBridgeCalcTableRange.Value = BridgeCalcTable; // fill range with data

        }
        catch (Exception ex)
        {
            MessageBox.Show("Error Message:" + Environment.NewLine + ex);
        }
    }

例外情况为:

    System.Runtime.InteropServices.COMException (0x800A03EC): 
    Exception from HRESULT: 0x800A03EC at System.RuntimeType.ForwardCallToInvokeMember(String memberName, BindingFlags flags, Object target, Int32[] aWarpperTypes, MessageData& msgData)
    at Microsoft.Office.Interop.Excel.Rage.ser_Value(obejct value) at LookApp2016.Form1.InsertBridgeCalcBlock() in ~~myfilelocation~~ line 2886

1 个答案:

答案 0 :(得分:0)

虽然我仍然想知道为什么Interop在数据表中使用Excel公式时会抛出异常,

我通过输入Excel.Range.CopyFromRecordSet找到了可能的答案。像这样:

        ADODB.Recordset BridgeCalcRecordset = ConvertToRecordset(dt);
        insertBridgeCalcTableRange.CopyFromRecordset(BridgeCalcRecordset);

但是,现在我的公式不会自动识别为公式。我必须在计算开始之前编辑并退出每个单元格,公式将更改为结果...

我使用以下方法解决了这个问题:

     insertBridgeCalcTableRange.Formula = insertBridgeCalcTableRange.Value;

我的代码是一样的,但我正在使用此代码将我的DataSet转换为ADODB RecordSet(他们说它也更快): 在http://www.nullskull.com/q/10057748/hi-all.aspx

获得Web Star奖励
    static public ADODB.Recordset ConvertToRecordset(DataTable inTable)
    {
        ADODB.Recordset result = new ADODB.Recordset();
        result.CursorLocation = ADODB.CursorLocationEnum.adUseClient;

        ADODB.Fields resultFields = result.Fields;
        System.Data.DataColumnCollection inColumns = inTable.Columns;

        foreach (DataColumn inColumn in inColumns)
        {
            resultFields.Append(inColumn.ColumnName
                , TranslateType(inColumn.DataType)
                , inColumn.MaxLength
                , inColumn.AllowDBNull ? ADODB.FieldAttributeEnum.adFldIsNullable :
                                         ADODB.FieldAttributeEnum.adFldUnspecified
                , null);
        }

        result.Open(System.Reflection.Missing.Value
                , System.Reflection.Missing.Value
                , ADODB.CursorTypeEnum.adOpenStatic
                , ADODB.LockTypeEnum.adLockOptimistic, 0);

        foreach (DataRow dr in inTable.Rows)
        {
            result.AddNew(System.Reflection.Missing.Value,
                          System.Reflection.Missing.Value);

            for (int columnIndex = 0; columnIndex < inColumns.Count; columnIndex++)
            {
                resultFields[columnIndex].Value = dr[columnIndex];
            }
        }

        return result;
    }

    static ADODB.DataTypeEnum TranslateType(Type columnType)
    {
        switch (columnType.UnderlyingSystemType.ToString())
        {
            case "System.Boolean":
                return ADODB.DataTypeEnum.adBoolean;

            case "System.Byte":
                return ADODB.DataTypeEnum.adUnsignedTinyInt;

            case "System.Char":
                return ADODB.DataTypeEnum.adChar;

            case "System.DateTime":
                return ADODB.DataTypeEnum.adDate;

            case "System.Decimal":
                return ADODB.DataTypeEnum.adCurrency;

            case "System.Double":
                return ADODB.DataTypeEnum.adDouble;

            case "System.Int16":
                return ADODB.DataTypeEnum.adSmallInt;

            case "System.Int32":
                return ADODB.DataTypeEnum.adInteger;

            case "System.Int64":
                return ADODB.DataTypeEnum.adBigInt;

            case "System.SByte":
                return ADODB.DataTypeEnum.adTinyInt;

            case "System.Single":
                return ADODB.DataTypeEnum.adSingle;

            case "System.UInt16":
                return ADODB.DataTypeEnum.adUnsignedSmallInt;

            case "System.UInt32":
                return ADODB.DataTypeEnum.adUnsignedInt;

            case "System.UInt64":
                return ADODB.DataTypeEnum.adUnsignedBigInt;

            case "System.String":
            default:
                return ADODB.DataTypeEnum.adVarChar;
        }
    }