正确访问backgroundworker线程中的窗体

时间:2011-08-14 08:33:50

标签: winforms thread-safety backgroundworker invokerequired

我有一个winforms应用程序,我需要在Backgroundworker线程中访问主窗体的Handle属性。

我已经创建了一个使用InvokeRequired调用主窗体的线程安全方法。我的问题是 - 为什么我仍然得到“InvalidOperationException跨线程操作无效”错误,即使调用这样的线程安全方法:

ProcessStartInfo psi = new ProcessStartInfo(file);
psi.ErrorDialogParentHandle = Utils.GetMainAppFormThreadSafe().Handle;

以下是线程安全方法的代码(我的主应用程序表单称为Updater):

    /// <summary>
    /// delegate used to retrieve the main app form
    /// </summary>
    /// <returns></returns>
    private delegate Updater delegateGetMainForm();

    /// <summary>
    /// gets the mainform thread safe, to avoid cross-thread exception
    /// </summary>
    /// <returns></returns>
    public static Updater GetMainAppFormThreadSafe()
    {
        Updater updaterObj = null;
        if (GetMainAppForm().InvokeRequired)
        {
            delegateGetMainForm deleg = new delegateGetMainForm(GetMainAppForm);
            updaterObj = GetMainAppForm().Invoke(deleg) as Updater;
        }
        else
        {
            updaterObj = GetMainAppForm();
        }
        return updaterObj;
    }

    /// <summary>
    /// retrieves the main form of the application
    /// </summary>
    /// <returns></returns>
    public static Updater GetMainAppForm()
    {
        Updater mainForm = System.Windows.Forms.Application.OpenForms[Utils.AppName] as Updater;
        return mainForm;
    }

我做错了吗? 提前谢谢。

稍后编辑:我将首先发布我需要手柄的原因,也许还有另一种解决方案/方法。在My Backgroundworker线程中,我需要在循环中安装多个程序,并为每个安装程序启动一个进程。但是我需要提升,以便此操作也适用于标准用户,而不仅仅是管理员。简而言之,我正在尝试按照教程here

1 个答案:

答案 0 :(得分:1)

您没有以线程安全的方式获取句柄。相反,您以线程安全的方式获取Form实例,然后以不安全的方式访问Handle属性。

您应该添加一个方法GetMainAppFormHandle(),它直接返回句柄并以线程安全的方式调用该句柄:

public static IntPtr GetMainAppFormHandle()
{
    return System.Windows.Forms.Application.OpenForms[Utils.AppName].Handle;
}

<强>更新

此外,您需要GetMainAppFormHandleThreadSafe()而不是GetMainAppFormThreadSafe()

public static IntPtr GetMainAppFormHandleThreadSafe()
{
    Form form = GetMainAppForm();
    if (form.InvokeRequired)
    {
        return (IntPtr)form.Invoke(new Func<IntPtr>(GetMainAppFormHandle));
    }
    else
    {
        return GetMainAppFormHandle();
    }
}