【问题标题】:(C# - Excel) How do I write a formula to a newly created column for each existing row?(C# - Excel)如何为每个现有行将公式写入新创建的列?
【发布时间】:2017-04-13 03:42:52
【问题描述】:

假设你有一个包含一堆数字和行的 excel 文件,大约 100 行。

我想以编程方式编写一个带有公式的列,该公式将每个现有行的一组字段的值相加。

首先,当然,我会为 Excel 文件创建 Openfiledialog,找到路径,通过 OleDb 打开它。把这个记下来了。现在说我有下表:

[朋友 |钱 |金钱损失 |几天过去了|解决方案]

Bilbo , 50 , 50 , 7 , *公式在这里

Bilso , 80 , 50 , 7 , *公式在这里

等等……

问题是,我没有确切的行数,所以我必须枚举 OleDb 连接找到的任何内容。 该公式类似于 =(B2-C2)*D2 但 2 也是错误的,它必须与它所在的任何行相关,即:第 3 行将是 =(B3-C3)*D3。我不知道该怎么做。

我发现直接写入单元格也不会使公式直接处理数字。

=====

编辑:

    private Excel.Application Xls;
    private Excel.Workbooks WBs;
    private Excel.Workbook WB;
    private Excel.Worksheet WS;
    private Excel.Sheets SS;
    Excel.Range cellsRange = null;
    Excel.Range columnRange = null;
    Excel.Range rowRange = null;
    int numberOfColumns = 0;
    int numberOfRows = 0;
    private void btnColumn_Click(object sender, EventArgs e)
    {
        if (btnColumn.FlatStyle == FlatStyle.Flat)
            btnColumn.FlatStyle = FlatStyle.Standard;
        else
        {
            btnColumn.FlatStyle = FlatStyle.Flat;
        }

        OpenFileDialog openFileDialog = new OpenFileDialog();
        openFileDialog.Filter = "Excel Files|*.xls;*.xlsx";
        openFileDialog.ShowDialog();
        string pather = openFileDialog.FileName;

        if (pather == "" || pather == " " || pather == null)
        {
            return;
        }

        if (!string.IsNullOrEmpty(openFileDialog.FileName))
        {
            try
            {
                Xls = new Excel.Application();
                WBs = Xls.Workbooks;
                WB = WBs.Open(pather, 0, false, 5, "", "", true,
                    XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
                SS = WB.Worksheets;
                WS = SS.get_Item(1);                    
                cellsRange = WS.Cells;
                columnRange = cellsRange.Columns;
                rowRange = cellsRange.Rows;
                numberOfColumns = columnRange.Count;
                numberOfRows = rowRange.Count;
                int LastCell = numberOfColumns+1;
                WS.Cells[1, LastCell] = "Tax Formula";
                for (int i = 2; i < numberOfRows; i++)
                {
                    //string niceFormula = "=SUM(L" + i + ",M" + i + ")*N"+ i ;
                    //WS.Cells[i, LastCell].Formula = niceFormula;
                    WS.Cells[i, LastCell].Value = (WS.Cells[i, 12] + WS.Cells[i, 13]) * WS.Cells[i, 14];
                }
                //==========================
                WB.Save();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Write Excel: " + ex.Message);
            }
            finally
            {
                GC.Collect();
                GC.WaitForPendingFinalizers();
                WB.Close();
                Xls.Quit();

                releaseObject(cellsRange);
                releaseObject(columnRange);
                releaseObject(rowRange);
                releaseObject(SS);
                releaseObject(WS);
                releaseObject(WBs);
                releaseObject(WB);
                releaseObject(Xls);
            }
        MessageBox.Show("Finished Updating File", "Task complete");
    }
}

有人知道为什么这段代码在尝试写入时会抛出以下错误吗?

HRESULT: 0x800A03EC

为了您的方便,重贴了整个代码。它仍在吐出 HRESULT 错误。

目标项目是 4 行深,1 行标题和大约 16 列宽。

【问题讨论】:

  • 逐个处理每个单元格值会很慢。我建议您将 Excel 中的整个数据放入数据表中并进行计算(使用 LINQ 或常规循环)并将计算值添加到同一数据表中的新列中。最后将数据表以所需格式导出到 Excel 表中。
  • 你没有告诉我们,你是怎么写到日期的。 VBA?还是具有 Excel 互操作性的 Winform 应用程序?还是带有 EPPlus 的 WinForm 应用程序?请详细说明。
  • @nabuchodonossor,我最初将其保持打开状态,因为有时有人会准备好 VBA 答案,但会被 C# 标签关闭。在某些情况下,我可以自己将逻辑转换为适合 C# 的逻辑,这样会有更多的总答案,但是是的,这是带有 Excel 互操作的 Winform。
  • @SouvikGhosh 好的,我想我现在如何将数据添加到数据表中,尽管我不确定如何做相反的事情(数据表到 excel)。但后来我不知道该怎么做。根本不是 LinQ 方面的专家,但我知道自己的编辑方法。
  • 有大量的文章和答案将数据表导出到 excel。这是一个-stackoverflow.com/questions/8207869/…。我想你现在可以忽略 LINQ。只需在常规循环中进行计算并相应地更新数据表。

标签: c# winforms excel oledb vba


【解决方案1】:

编辑:

你可能想试试这个:

numberOfColumns = WS.UsedRange.Columns.CountLarge;
numberOfRows = WS.UsedRange.Rows.CountLarge;

呃,如果你使用CountLarge而不是Count,也将它们更改为long而不是int

好的 - 我终于搞定了 - 不知道为什么会遇到这么多问题。

对我来说,我显然必须让应用程序可见,否则它不起作用。

可能还有另一种解决方法 - 我从这里提取了它:https://stackoverflow.com/a/17061714/1274820

这段代码终于为我工作了:

请注意,这是一个控制台应用程序(我想我会排除它),但您应该能够添加魔术线。

Application excelApp = new Application();
excelApp.SheetsInNewWorkbook = 1;
////////////////////////////////////////////
//Add these lines to make it work???
////////////////////////////////////////////
try {
    excelApp.Visible = true;
}
catch {} 
////////////////////////////////////////////
Workbook excelWB = excelApp.Workbooks.Open(@"C:\test.xls", Type.Missing, false);
_Worksheet excelWS = excelWB.Sheets[1];
Range cellsRange = excelWS.UsedRange;
long LastCell = cellsRange.Columns.CountLarge + 1;
long numberOfRows = cellsRange.Rows.CountLarge;
excelWS.Cells[1, LastCell] = "Tax Formula";
for (int i = 2; i <= numberOfRows; i++)
{
    string niceFormula = "=SUM(L" + i + ",M" + i + ")*N" + i;
    excelWS.Cells[i, LastCell].Formula = niceFormula;
}
excelWB.Close(true);
excelApp.Quit();

之前:

之后:

如何用 Excel 电子表格填充 DataTable:

//////////////////////////////////////////////////////////////////////////////////
//This function is absolute magic >.> - Fill DataTable with excel spreadsheet
//HDR=YES means "Spreadsheet has headers" Change to NO if not.
//name = "Log"; - This is the Sheet name to pull the data from
//////////////////////////////////////////////////////////////////////////////////
//oconn takes an SQL like command (Select Everything from name sheet) using con
//HDR=YES means that our data has headers :)
//////////////////////////////////////////////////////////////////////////////////
String constr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + copyToPath + ";Extended Properties='Excel 12.0 XML;HDR=YES;';";
OleDbConnection con = new OleDbConnection(constr);
OleDbCommand oconn = new OleDbCommand("Select * From [Log$]", con);
con.Open();
OleDbDataAdapter sda = new OleDbDataAdapter(oconn);
DataTable data = new DataTable();
sda.Fill(data);
con.Close();
//////////////////////////////////////////////////////////////////////////////////

【讨论】:

  • 嗯,这比我周围的要整洁得多,尽管我没有将它植入数据表,而是将其植入 DataGridView。使用它,您将如何访问 data 中的数据?就像你想要一个数组一样?诠释foo = data[1,1]?我使用数据表的唯一一次是填充一个 DataGridView(我然后接口),但它确实有效。哦,顺便说一句,正如我上面评论的那样,我尝试了你的代码,但我得到了和以前一样的错误。也许我没有注意到我的范围声明有问题?
  • 我在你的 atm 上向后工作 - 你在代码中声明了两次 XlsWbs,所以显然存在问题。在打开文件之前,您还将获得工作簿对象。这可能不是一个好主意。
  • 我发布了我的整个代码,没有公式位,类似的代码在另一个函数中工作,它只是向单元格添加值,所以代码的基本结构应该可以工作。但由于某种原因,我仍然收到 HRESULT 错误。
  • try { Xls.Visible = true; } catch {} 在声明 Xls 后添加
  • 我收回来-您的整个问题可能与我的不同-您只是在计算范围内的单元格。使用numberOfColumns = WS.UsedRange.Columns.CountLarge;numberOfRows = WS.UsedRange.Rows.CountLarge;
【解决方案2】:

为什么不使用 R1C1 参考风格?这样,您的公式就不需要与列相关。

供参考: https://excelmate.wordpress.com/2013/04/22/excel-r1c1-reference-style-vs-a1/

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多