C#编译错误: "Invoke or BeginInvoke cannot be called on a control until the window handle has been created."

标签 c# delegates invoke handle runtime-error

我刚刚发布了一个关于如何让委托(delegate)更新另一个表单上的文本框的问题。就在我认为我可以使用 Invoke 找到答案时......发生了这种情况。这是我的代码:

主窗体代码:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;
using System.Data.OleDb;
using System.Collections.Specialized;
using System.Text;
using System.Threading;

delegate void logAdd(string message);

namespace LCR_ShepherdStaffupdater_1._0
{
    public partial class Main : Form
    {
        public Main()
        {
            InitializeComponent();
        }

        public void add(string message)
        {
            this.Log.Items.Add(message);
        }
        public void logAdd(string message)
        {   /////////////////////////// COMPILER ERROR BELOW ///////////
            this.Invoke(new logAdd(add), new object[] { message }); // Compile error occurs here     
        }////////////////////////////// COMPILER ERROR ABOVE ///////////

        private void exitProgramToolStripMenuItem_Click(object sender, EventArgs e) 
        {
            Application.Exit(); 
        }
        private void aboutToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            Form aboutBox = new AboutBox1(); 
            aboutBox.ShowDialog(); 
        }

        private void settingsToolStripMenuItem_Click(object sender, EventArgs e)
        {
        }

        private void settingsToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            settingsForm.settings.ShowDialog();
        }

        private void synchronize_Click(object sender, EventArgs e)
        {
            string message = "Here my message is"; // changed this
            ErrorLogging.updateLog(message);  // changed this
        }

    }

    public class settingsForm 
    {
        public static Form settings = new Settings();
    }

}

记录类代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LCR_ShepherdStaffupdater_1._0
{
    public class Logging
    {
        static Main mainClass = new Main();
        static logAdd logAddDelegate;

        public static void updateLog(string message)
        {
            logAddDelegate = mainClass.logAdd;
            logAddDelegate(message);
        }
    }
}
  • 编译错误:

    InvalidOperationException 是 未处理 - 调用或 BeginInvoke 不能在控件上调用,直到 窗口句柄已创建。

我已经尝试在日志项上创建一个句柄...但是没有用。问题是我完全不知道自己在做什么,而且我在 Google 上广泛地进行了搜索,却只找到了模糊的答案。

请告诉我在调用此委托(delegate)之前如何创建句柄。当你在做的时候,给我一些方法可以让这段代码更简单。例如,我不想要两个 Add 函数......我不得不这样做,因为我无法找到要从 Logging 类调用的项目。有没有更好的方法来完成我需要做的事情?

谢谢!!!

编辑:

我的项目相当大,但这些是导致此特定问题的唯一项目。

Log 是我的 RichTextBox1 (Log.Items.Add(message)) 我将它重命名为 Log 以便重新键入。

虽然我从不同的形式调用 updateLog(message)...让我在这里更新它(尽管我从哪里调用 updateLog(message) 没有区别,它仍然给我这个错误)

你们将不得不为我简化事情...并提供示例。我不明白你们在这里说的一半......我不知道如何使用调用方法和句柄。我也研究过它的废话......

第二次编辑:

我相信我已经找到问题所在,但不知道如何解决。

在我的日志记录类中,我使用这段代码来创建 mainClass:

static Main mainClass = new Main();

我正在为 Main() 创建一个全新的蓝图副本,包括 Log(我正在尝试更新的 richtextbox)

当我调用 updateLog(message) 时,我相信我正在尝试更新 Main() 的第二个实体(也称为 mainClass)上的日志(richtextbox)。当然,这样做会抛出这个异常,因为我什至还没有看到我正在使用的当前 Main 的副本。

这就是我的目标,感谢其中一位给出答案的人:

Main mainClass = Application.OpenForms.OfType<Main>().First();
logAddDelegate = mainClass.logAdd; 
logAddDelegate(message);

我需要创建 mainClass 而不是使用 new() 运算符,因为我不想创建新的表单蓝图我希望能够编辑当前表单。

虽然上面的代码不起作用,我什至找不到应用程序。这甚至是 C# 语法吗?

如果我能让上面的代码工作,我想我可以解决我的问题,并在几个小时的寻求答案后最终解决这个问题。

最终编辑:

感谢下面的一位用户,我弄明白了。这是我更新的代码:

主窗体代码:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;
using System.Data.OleDb;
using System.Collections.Specialized;
using System.Text;
using System.Threading;

delegate void logAdd(string message);

namespace LCR_ShepherdStaffupdater_1._0
{
    public partial class Main : Form
    {
        private static Main mainFormForLogging;
        public static Main MainFormForLogging
        {
            get
            {
                return mainFormForLogging;
            }
        }

        public Main()
        {
            InitializeComponent();
            if (mainFormForLogging == null)
            {
                mainFormForLogging = this;
            }
        }

        public void add(string message)
        {
            this.Log.Items.Add(message);
        }
        public void logAdd(string message)
        {
            this.Log.BeginInvoke(new logAdd(add), new object[] { message });
        }

        private void exitProgramToolStripMenuItem_Click(object sender, EventArgs e) 
        {
            Application.Exit(); 
        }
        private void aboutToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            Form aboutBox = new AboutBox1(); 
            aboutBox.ShowDialog(); 
        }

        private void settingsToolStripMenuItem_Click(object sender, EventArgs e)
        {
        }

        private void settingsToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            settingsForm.settings.ShowDialog();
        }

        private void synchronize_Click(object sender, EventArgs e)
        {
            add("test");
            Logging.updateLog("testthisone");
            //DatabaseHandling.createDataSet();
        }

    }

    public class settingsForm 
    {
        public static Form settings = new Settings();
    }

}

记录类代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LCR_ShepherdStaffupdater_1._0
{
    public class Logging
    {

        static Main mainClass = Main.MainFormForLogging;
        static logAdd logAddDelegate;

        public static void updateLog(string message)
        {
            logAddDelegate = mainClass.logAdd;
            logAddDelegate(message);
        }
    }
}

最佳答案

好吧,我要重新开始了。

为了了解正在发生的事情,您需要了解 .NET 和 Windows 之间的关系。 .NET 在 Windows 上运行并包装了许多 native 的 Win32 概念,如窗口、 ListView 、编辑框(标准文本框的 Win32 名称)。这意味着您可以拥有 TextBox 或 Form 的有效 .NET 实例,但还没有该项目(EditBox 或 Window)的基础 Windows 版本。当 HandleCreated 为真时,将创建项目的 Windows 版本。

您的问题的发生是因为某些原因导致在创建窗体的窗口之前调用 logAdd 方法。这意味着在实例化 Form 实例之后但在创建 Window 句柄之前,在启动过程中的某处,某些东西正在尝试调用 logAdd。如果您向 logAdd 添加一个断点,您应该能够看到那个调用在做什么。您会发现调用是在您在记录器类中创建的 Main 实例上进行的,而不是实际运行的 Main 实例。由于记录器实例永远不会显示,因此不会创建窗口句柄,因此您会收到错误消息。

应用程序运行的一般方式是在您的启动方法中调用Application.Run(new Main()),该方法通常在Program 类中并称为Main。您需要您的记录器指向这个 main 实例。

有多种获取表单实例的方法,每种方法都有自己的注意事项,但为简单起见,您可以将实例公开到 Main 类本身之外。例如:

public partial class Main : Form
{
    private static Main mainFormForLogging;
    public static Main MainFormForLogging
    {
        get
        {
            return mainFormForLogging;
        }
    }

    public Main()
    {
        InitializeComponent();

        if (mainFormForLogging == null)
        {
            mainFormForLogging = this;
        }
    }

    protected void Dispose(bool disposing)
    {
         if (disposing)
         {
             if (this == mainFormForLogging)
             {
                mainFormForLogging = null;
             }
         }

         base.Dispose(disposing);
    }
}

关于C#编译错误: "Invoke or BeginInvoke cannot be called on a control until the window handle has been created.",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/513131/

相关文章:

model-view-controller - 从另一个 Controller 调用操作方法的最佳方法是什么?

assembly - 尝试退出程序时调用错误

c# - System.Runtime.Caching.MemoryCache 是否在同一服务器中跨进程共享

c# - xUnit 中的 Assert.DoesNotThrowAsync() 发生了什么?

c# - 在 C# 中将 Windows 键用于其他目的

c++ - 将 Visual C++ 委托(delegate)传递给 native C++ 类

c# - 身份验证和登录页面 - 我如何进行身份验证?

c# - 如何从字节数组中删除空值?

iphone - iOS:通过委托(delegate)方法从推送的 ViewController 返回?

winforms - 在不存在控制对象的情况下在 UI 线程上运行代码