Is that any way to make excel only calculate partial worksheets?

40 Views Asked by At

I make a UDF in C# (by using Excel-DNA nuget package, version:1.7.0-rc9) to get some data from my service api and re-write the data to another worksheet, To ensure that the data is up to date and easy to trigger new queries, my UDF is marked as volatile,in some unknow case that make my UDF will calculation in loop and re-write to target worksheet that will cause excel process No Response, so i set the Application. Calculation to XLCalculation.xlCalculationManual mode but i don't think that is the best solution because the volatile UDF on other worksheet won't auto recalculation after some cell changed, Is there any way to set the calculation property to workbook or worksheet but not application? I hope can make excel application on XlCalculation.xlCalculationAutomatic and only calculation worksheets which don't contains xlMyGet

Let's assume the UDF call at [Workbook1]Sheet1!$A$1 and data re-write at [Worbook1]Sheet2!$A$5

The response data like: object[,] data = new object[2,4]

The UDF definition like follow:

// UDF Summary
[ExcelFunction(IsVolatile=true)]

public static object xlMyGet(string url,object[] argumentKeys,object[] argumentValues,string cellAddress)
{
    if(ExcelDnaUtil.IsInFunctionWizard())
        return ExcelError.ExcelErrorRef;
    Application app = (Application)ExcelDnaUtil.Application;
    Range targetCell = app.Range[cellAddress];
    Dictionary<string,object> argDic = Enumerable.Range(0,argumentKeys.Length)
      .ToDictionary(key=>argumentKeys.ElementAt(key)?.ToString(),value=>argumentValues.ElementAtOrDefault(value));
    if(targetCell != null)
    {
        new MyApi().getData(argDic,targetCell.Column,targetCell.Row,targetCell.Worksheet);
    }
    return "OK here!";
}

The MyApi.cs like follow:

public class MyApi
{
    public void getData(Dictionary<string,object> argDic,int beginColumn,int beginRow,Worksheet worksheet)
    {
        // assume the data is ready and has 2 rows, 4 columns
        object[,] data = new object[2,4];
        // notify the refresh datetime of data
        ExcelAsyncUtil.QueueAsMacro(()=>
        {
            DateTime refreshTime = DateTime.Now.ToLocalTime();
            Range refreshTitleRange = worksheet.Cells[beginRow,beginColumn+1];
            refreshTitleRange.Value = "Refresh time:";
            refreshTitleRange = refreshTitleRange.Offset[ColumnOffset:1];
            refreshTitleRange.NumberFormat = "@";
            refreshTitleRange.Value = refreshTime.ToString("yyyy-MM-dd HH:mm:ss");
            refreshTitleRange.EntireColumn.AutoFit();
        })
        int rowCount = data.GetLength(0);
        int colCount = data.GetLength(1);
        // write data to target worksheet
        Range dataRange = worksheet.Range[worksheet.Application.ConvertFormula($"R{beginRow+1}C{beginColumn}:R{((beginRow+1)+Math.Max(0,rowCount-1))}C{beginColumn+colCount-1}",XlReferenceStyle.xlR1C1,XlReferenceStyle.xlA1)];
        dataRange.Value = data;
    }
}

Any suggestion and insights would be very useful to me!

I had try to set volatile state to true by using c-api and try to handle the AfterCalculate and the SheetCalculate event but it don't support to cancel special sheet's calculation

0

There are 0 best solutions below