如何在输入值时停止计算Excel-DNA功能

时间:2014-01-23 09:44:26

标签: c# performance excel excel-dna

我在c#中实现了一些复杂且计算量很大的函数。要在Excel中使用它,我已经通过Excel-DNA创建了Excel-AddIn。

现在,当我在Excel中调用该函数并开始输入值时,它甚至在我完成所有输入之前就开始计算。更重要的是,当我单击进入单元格并更改某些输入时,该功能也会重新计算。通常我不介意。但由于性能缓慢,它变成了一场考验。

有没有办法抑制这种行为? (将计算设置为手动似乎不起作用)基本上我希望Excel-DNA公式仅在按下F9时(重新)计算。

如果有人有其他语言的解决方案,我很乐意将其作为灵感,并将其移植到c#。

2 个答案:

答案 0 :(得分:11)

根据Govert(XL DNA的作者),您可以这样做:

您可以调用ExceDnaUtil.IsInFunctionWizard()进行检查。

所以你的功能可能会去:

public static object SlowFunction()
{
    if (ExcelDnaUtil.IsInFunctionWizard()) return "!!! In Function
Wizard";

    // do the real work....
} 

值得一看的是关于XLDANA相关问题和答案的Excel DNA Google小组 https://groups.google.com/forum/#!forum/exceldna

答案 1 :(得分:2)

您遇到的问题是Excel函数向导会在您输入参数值时反复调用该函数。

为了避免这种情况,您的功能需要检测功能向导的存在并继续进行。

我有一些C ++代码可以在生产中强有力地实现这一点。希望你能把它移植到C#。它使用Windows API。您需要注意函数向导与特定的Excel会话相关;特别注意Excel2013。

typedef struct _EnumStruct
{
    bool wizard;
    DWORD pid;
} EnumStruct, FAR* LPEnumStruct;

BOOL CALLBACK EnumProc(HWND hwnd, LPEnumStruct pEnum)
{
    static const char szFunctionWizardClass[] = "bosa_sdm_XL";
    static const char szFunctionWizardCaption[] = "Function Arguments";

    char szClass[sizeof(szFunctionWizardClass)];
    char szCaption[sizeof(szFunctionWizardCaption)];

    if (GetClassName(hwnd, (LPSTR)szClass, sizeof(szFunctionWizardClass))){
        if (CompareString(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT), NORM_IGNORECASE, (LPSTR)szClass, (lstrlen((LPSTR)szClass) > lstrlen(szFunctionWizardClass)) ? lstrlen(szFunctionWizardClass) : -1, szFunctionWizardClass, -1) == CSTR_EQUAL){
            // Do the process IDs match? (The former way of checking parent windows doesn't work in Excel2013).
            DWORD pid = NULL;
            GetWindowThreadProcessId(hwnd, &pid);
            if (pid == pEnum->pid){
                // Check the window caption
                if (::GetWindowText(hwnd, szCaption, sizeof(szFunctionWizardCaption))){
                    if (CompareString(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT), NORM_IGNORECASE, (LPSTR)szCaption, (lstrlen((LPSTR)szCaption) > lstrlen(szFunctionWizardCaption)) ? lstrlen(szFunctionWizardCaption) : -1, szFunctionWizardCaption, -1) == CSTR_EQUAL){
                        pEnum->wizard = TRUE;
                        return FALSE;
                    }
                }
            }
        }
    }
    // Continue the enumeration
    return TRUE;
}

bool Excel12::calledFromFunctionWizard()
{
    EnumStruct enm;
    enm.wizard = FALSE;
    enm.pid = GetProcessId(GetCurrentProcess());
    EnumWindows((WNDENUMPROC)EnumProc, (LPARAM)((LPEnumStruct)&enm));
    return enm.wizard;
}