【问题标题】:correct access of a windows form inside backgroundworker thread在 backgroundworker 线程中正确访问 Windows 窗体
【发布时间】:2011-08-14 08:33:50
【问题描述】:

我有一个 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;
    }

我做错了吗? 提前谢谢你。

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

【问题讨论】:

    标签: winforms thread-safety backgroundworker invokerequired


    【解决方案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();
        }
    }
    

    【讨论】:

    • 我刚刚尝试过,但意识到 IntPtr 不是 Control 对象,因此没有 InvokeRequired 或 Invoke 等属性,因此我可以以线程安全的方式调用此静态方法。
    • 我刚刚意识到您的代码比我最初想象的更糟糕:您以不安全的方式调用 GetMainAppForm() 只是为了确定是否需要以线程安全的方式调用相同的方法,或者不是。这是没有意义的。无论如何,我已经更新了我的答案并包含了更多代码。
    • 感谢您的评论 - 您的意思是我的代码中没有意义的部分位于:GetMainAppForm().InvokeRequired 或 updaterObj = GetMainAppForm().Invoke(deleg) as Updater?
    • 两者。您最初的假设是 GetMainAppForm() 必须以线程安全的方式调用。然而,您在调用Invoke 之前以不安全的方式调用了它两次,这在核心是线程安全的方式。但是,在其他地方需要线程安全访问,即在使用 Handle 属性时。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-15
    • 1970-01-01
    相关资源
    最近更新 更多