C#编译错误:"在创建窗口句柄之前,无法在控件上调用Invoke或BeginInvoke."

One*_*hot 8 c# delegates runtime-error handle invoke

我刚刚发布了一个关于如何让代理人在另一个表单上更新文本框的问题.就在我以为我有使用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();
    }

}
Run Code Online (Sandbox Code Playgroud)

记录类代码:

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)
  • 编译错误:

    InvalidOperationException未处理 - 在创建窗口句柄之前,无法在控件上调用Invoke或BeginInvoke.

我已经尝试在Log项目上创建一个句柄......但是这不起作用.问题是我没有CLUE我正在做什么,我已经广泛搜索谷歌只是为了找到模糊的答案.

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

谢谢!!!

编辑:

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

Log是我的RichTextBox1(Log.Items.Add(message))我将它重命名为Log,因此更容易重新输入.

我从一个不同的形式调用updateLog(消息)...让我在这里更新(虽然它没有区别我从它调用updateLog(消息)仍然给我这个错误)

你们不得不让事情变得更简单......并举例说明.我不明白你们在这里说的所有内容的HALF ......我不知道如何使用方法和句柄的调用.我也研究了它的废话......

第二次编辑:

我相信我找到了问题,但不知道如何解决它.

在我的日志类中,我使用此代码来创建mainClass:

static Main mainClass = new Main();

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

当我调用updateLog(消息)时,我相信我正在尝试更新Main()的第二个实体(也称为mainClass)上的Log(richtextbox).当然,这样做会让我这个例外,因为我甚至没有看到我正在使用的当前Main的复制品.

这是我拍摄的内容,感谢其中一位给出答案的人:

Main mainClass = Application.OpenForms.OfType<Main>().First();
logAddDelegate = mainClass.logAdd; 
logAddDelegate(message);
Run Code Online (Sandbox Code Playgroud)

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

上面的代码不起作用,我甚至找不到Application.这甚至是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();
    }

}
Run Code Online (Sandbox Code Playgroud)

记录类代码:

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Mic*_*ows 12

我过去使用以下方法解决了这个问题:

private void invokeOnFormThread(MethodInvoker method)
{
    if (IsHandleCreated)
         Invoke(new EventHandler(delegate { method(); }));
    else
        method();
}
Run Code Online (Sandbox Code Playgroud)

调用invokeOnFormThread而不是调用.如果已经创建了句柄,它将只使用表单的线程,否则它将使用调用者的线程.


Jef*_*tes 12

对,我要重新开始.

为了理解正在发生的事情,您需要了解.NET和Windows如何相互关联..NET在Windows上运行并包含许多本机Win32概念,如窗口,列表视图,编辑框(标准文本框的Win32名称).这意味着您可以拥有TextBox或Form的有效.NET实例,但还没有该项目的基础Windows版本(EditBox或Window).当HandleCreated为true时,将创建项目的Windows版本.

您的问题正在发生,因为有些东西导致在创建表单窗口之前调用logAdd方法.这意味着在启动Form实例之后的某个地方,但在创建Window句柄之前,有些东西试图调用logAdd.如果向logAdd添加断点,您应该能够看到正在进行该调用的内容.你会发现,调用是在你在logger类中创建的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);
    }
}
Run Code Online (Sandbox Code Playgroud)