简体   繁体   中英

open xml sdk excel formula recalculate after cell removal

I have a formula cell C4 that needs to recalculate after I enter a value in another cell C2. but the C4 keeps getting cached and keeps returning old cached value.

I have asked this question multiple times on SO but I am not getting any help. I am trying every thing that I can. Here is what I found on msdn site.

With the methods from the previous code listing in place, generating the report is now a process of getting the portfolio data and repeatedly calling UpdateValue to create the report. Indeed, if you add the necessary code to do this, things seem to work fine except for one problem - any cell that contains a formula that refers to a cell whose value was changed via Open XML manipulation does not show the correct result. This is because Excel caches the result of a formula within the cell. Because Excel thinks it has the correct value cached, it does not recalculate the cell. Even if you have auto calculation turned on or if you press F9 to force a manual recalculation, Excel does not recalculate the cell. The solution to this is to remove the cached value from these cells so that Excel recalculates the value as soon as the file is opened in Excel. Add the RemoveCellValue method shown in the following example to the PortfolioReport class to provide this functionality.

Based on above MSDN explanation. I have tried putting the removing the code before I update the cell. After I update the cell. Before I read the formula cell, after I read the formula cell but I keep getting the following error after I read the formula cell.

System.NullReferenceException: Object reference not set to an instance of an object.

Here is my code...

    string filename = Server.MapPath("/") + "MyExcelData.xlsx";



    using (SpreadsheetDocument document = SpreadsheetDocument.Open(filename, true))
    {


        Sheet sheet = document.WorkbookPart.Workbook.Descendants<Sheet>().SingleOrDefault(s => s.Name == "myRange1");
        if (sheet == null)
        {
            throw new ArgumentException(
                String.Format("No sheet named {0} found in spreadsheet {1}", "myRange1", filename), "sheetName");
        }
        WorksheetPart worksheetPart = (WorksheetPart)document.WorkbookPart.GetPartById(sheet.Id);
        Worksheet ws = worksheetPart.Worksheet; // ((WorksheetPart)(worksheetPart.GetPartById(sheet.Id))).Worksheet;
        Cell cell = InsertCellInWorksheet(ws, "C4");

        // If there is a cell value, remove it to force a recalculation
        // on this cell.
        if (cell.CellValue != null)
        {
            cell.CellValue.Remove();
        }

        // Save the worksheet.
        ws.Save();
        document.Close();
    }



    // getting 2 numbers in excel sheet, saving, and closing it.

    using (SpreadsheetDocument document = SpreadsheetDocument.Open(filename, true))
    {


        Sheet sheet = document.WorkbookPart.Workbook.Descendants<Sheet>().SingleOrDefault(s => s.Name == "myRange1");
        if (sheet == null)
        {
            throw new ArgumentException(
                String.Format("No sheet named {0} found in spreadsheet {1}", "myRange1", filename), "sheetName");
        }
        WorksheetPart worksheetPart = (WorksheetPart)document.WorkbookPart.GetPartById(sheet.Id);


        int rowIndex = int.Parse("C3".Substring(1));

        Row row = worksheetPart.Worksheet.GetFirstChild<SheetData>().
                Elements<Row>().FirstOrDefault(r => r.RowIndex == rowIndex);

        Cell cell3 = row.Elements<Cell>().FirstOrDefault(c => "C3".Equals(c.CellReference.Value));
        if (cell3 != null) 
        {
            cell3.CellValue = new CellValue("16");
            cell3.DataType = new DocumentFormat.OpenXml.EnumValue<CellValues>(CellValues.Number); 
        }

        worksheetPart.Worksheet.Save();
        document.Close();

    }

    // getting the result out of excel.
    using (SpreadsheetDocument document = SpreadsheetDocument.Open(filename, false))
    {
        document.WorkbookPart.Workbook.CalculationProperties.ForceFullCalculation = true;
        document.WorkbookPart.Workbook.CalculationProperties.FullCalculationOnLoad = true;

        Sheet sheet = document.WorkbookPart.Workbook.Descendants<Sheet>().SingleOrDefault(s => s.Name == "myRange1");
        if (sheet == null)
        {
            throw new ArgumentException(
                String.Format("No sheet named {0} found in spreadsheet {1}", "myRange1", filename), "sheetName");
        }



        WorksheetPart worksheetPart = (WorksheetPart)document.WorkbookPart.GetPartById(sheet.Id);

        int rowIndex = int.Parse("C4".Substring(1));

        Row row = worksheetPart.Worksheet.GetFirstChild<SheetData>().
                Elements<Row>().FirstOrDefault(r => r.RowIndex == rowIndex);

        Cell cell = row.Elements<Cell>().FirstOrDefault(c => "C4".Equals(c.CellReference.Value));

        d.Average = Convert.ToDouble(cell.CellValue.InnerText);

    }

The problem seems to be that you are directly modifying an Excel data file without Excel being open. Since Excel can only track formula dependencies when its open it does not know that it needs to recalculate when you change data without Excel knowing that you have done so.

3 possible solutions are:
1) remove the calculation chain part from the file (not tested)
2) after making the changes to the file use interop/automation to open Excel and request a full calculation (or full calculation with dependency rebuild if you are also altering/creating formulas)
3) set the fullcalculationonload property to true : this should cause Excel to do a full calculation when it opens the file

我认为您已经删除了C4的cellValue,首先您必须创建cellValue,然后才能对其执行任何操作。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM