Excel formula lost after reassigning the cell value
Here is the sample code
XL.Worksheet worksheet = Globals.ThisAddIn.Application.ActiveSheet;
XL.Range range = worksheet.UsedRange;
arrValue = (object[,])range.get_Value(XL.XlRangeValueDataType.xlRangeValueDefault);
for (int iRow = 1; iRow <= arrValue.GetLength(0); iRow++)
{
for (int iCol = 1; iCol <= arrValue.GetLength(1); iCol++)
{
if (range.Cells[iRow, iCol].Formul开发者_如何学运维a != null)
range.Cells[iRow, iCol].Formula = "=" + kvp.Value.ToString(); // assign underlying formula (kvp is keyValuePair of dictionary) to the cell
range.Cells[iRow, iCol].Value = evalResults[count].ToString(); // assign value to the cell
count++;
}
}
I wonder if Cells.Value and Cells.Formula would overwrite each other. If I want to assign both of them at the same time, what is the best way to do it?
Thanks.
It is not possible to assign bot the value and the formula to an excel cell (you can't do that even using excel in the normal interactive way), since the result would be undefined, i.e. if the result of the formula is different from the value what would you show in the cell?
Since you want to preserve your formulas for reuse in the future you could have a Recalculate method which applies the formulas, saves them to a dictionary (and you already have something like that, don't you?), and then set the value of the cells with the current value (calculated from the formula).
Maybe this is what you are already doing here, but it's not so clear, since I don't understand what evalResults is. Anyway, I mean something like this:
private Dictionary<int,Dictionary<int,string>> formulas = new Dictionary<int,Dictionary<int,string>>(); // this has to be initialized according to your formulas
public void Recalculate()
{
XL.Worksheet worksheet = Globals.ThisAddIn.Application.ActiveSheet;
XL.Range range = worksheet.UsedRange;
for (int iRow = 1; iRow <= arrValue.GetLength(0); iRow++)
{
for (int iCol = 1; iCol <= arrValue.GetLength(1); iCol++)
{
range.Cells[iRow, iCol].Formula = "=" + formulas[iRow][iCol];
range.Cells[iRow, iCol].Value = range.Cells[iRow, iCol].Value;
}
}
}
If you want to keep the formulas in the excel workbook and not in memory (in the dictionary), a solution could be to have a hidden worksheet where you store the formulas as strings (i.e. without the '=') in order to avoid their evaluation and the performance issues. So you would have a SetFormulas and a Recalculate method very similar to your code:
public void SetFormulas()
{
XL.Worksheet worksheet = Globals.ThisAddIn.Application.ActiveSheet;
XL.Worksheet formulasWorksheet = Globals.ThisAddIn.Application.ActiveWorkbook.Worksheets["formulas"];
XL.Range range = worksheet.UsedRange;
arrValue = (object[,])range.get_Value(XL.XlRangeValueDataType.xlRangeValueDefault);
for (int iRow = 1; iRow <= arrValue.GetLength(0); iRow++)
{
for (int iCol = 1; iCol <= arrValue.GetLength(1); iCol++)
{
if (range.Cells[iRow, iCol].Formula != null)
{
range.Cells[iRow, iCol].Formula = "=" + kvp.Value.ToString(); // assign underlying formula (kvp is keyValuePair of dictionary) to the cell
formulasWorksheet.Cells[iRow, iCol].Value = kvp.Value.ToString(); // storing the formula here
}
range.Cells[iRow, iCol].Value = evalResults[count].ToString(); // assign value to the cell
count++;
}
}
}
public void Recalculate()
{
XL.Worksheet worksheet = Globals.ThisAddIn.Application.ActiveSheet;
XL.Worksheet formulasWorksheet = Globals.ThisAddIn.Application.ActiveWorkbook.Worksheets["formulas"];
XL.Range range = worksheet.UsedRange;
arrValue = (object[,])range.get_Value(XL.XlRangeValueDataType.xlRangeValueDefault);
for (int iRow = 1; iRow <= arrValue.GetLength(0); iRow++)
{
for (int iCol = 1; iCol <= arrValue.GetLength(1); iCol++)
{
if (!string.IsNullOrEmpty(formulasWorksheet.Cells[iRow, iCol].Text))
{
range.Cells[iRow, iCol].Formula = "=" + formulasWorksheet.Cells[iRow, iCol].Text; // restoring the formula
range.Cells[iRow, iCol].Value = range.Cells[iRow, iCol].Value // replacing the formula with the value
}
}
}
}
In your comment, you state your real concern, which is that performance will suffer if cell formulas are recalculated automatically. The solution is then to prevent automatic recalculation, i.e. make it manual:
Application.Calculation = xlCalculationManual
where xlCalculationManual
is a built-in constant equal to -4135. You can set it back to xlCalculationAutomatic
or -4105 later.
Just leave you formulas there, don't edit the values, let Excel figure out the result.
While in manual mode, the user can force a recalculation using F9, or you can do it programmatically with Application.Calculate
.
All this is also available in the Excel user interface: Tools > Options > Calculation.
精彩评论