问题描述
我刚刚发布了一个关于如何让代表更新另一个表单上的文本框的问题.就在我认为我使用 Invoke 得到答案的时候……这发生了.这是我的代码:
I just posted a question about how to get a delegate to update a textbox on another form. Just when I thought I had the answer using Invoke...this happens. Here is my code:
主窗体代码:
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 是未处理 - Invoke 或 BeginInvoke不能在控件上调用,直到窗口句柄已创建.
我已经尝试在 Log 项上创建句柄...但是没有用.问题是我不知道自己在做什么,我在 Google 上广泛地进行了搜索,却只找到了模糊的答案.
I already tried to create a handle on the Log item...but that didn't work. The problem is I have NO CLUE what I am doing and I have searched Google extensively only to find vague answers.
请在我调用此委托之前告诉我如何创建句柄.当你在做的时候,给我一些方法可以让这个代码更简单.例如,我不想要两个 Add 函数……我必须这样做,因为我无法从 Logging 类中找到要调用的项目.有没有更好的方法来完成我需要做的事情?
Please tell me how to create the handle before I invoke this delegate. While you are at it, give me some ways I can make this code more simple. For example, I dont want two Add functions... I had to do that because there was no way for me to find an item to invoke from the Logging class. Is there a better way to accomplish what I need to do?
谢谢!!!
我的项目相当大,但这些是导致此特定问题的唯一项目.
My project is fairly large, but these are the only items causing this specific problem.
Log 是我的 RichTextBox1 (Log.Items.Add(message)) 我将其重命名为 Log,以便重新输入.
Log is my RichTextBox1 (Log.Items.Add(message)) I renamed it to Log so it is easier to retype.
我正在从不同的表单调用 updateLog(message)...让我在这里更新它(尽管我从它调用 updateLog(message) 并没有什么区别仍然给我这个错误)
I am calling updateLog(message) from a different form though...let me update that in here (although it makes no difference where I call updateLog(message) from it still gives me this error)
你们将不得不让我的事情变得更简单......并提供示例.我不明白你们在这里所说的一切......我不知道如何使用方法和句柄的调用.我也研究过它的废话......
You guys are going to have to make things more simpler for me...and provide examples. I don't understand HALF of everything you guys are saying here...I have no clue on how to work with Invoking of methods and Handles. I've researched the crap out of it too...
第二次
我相信我找到了问题所在,但不知道如何解决.
I believe I have located the problem, but do not know how to fix it.
在我的日志记录类中,我使用此代码创建 mainClass:
In my logging class I use this code to create mainClass:
静态 Main mainClass = new Main();
我正在为 Main() 创建一个全新的蓝图副本,包括 Log(我正在尝试更新的 Richtextbox)
I am creating a entirely new blueprint replica to Main(), including Log (the richtextbox I am trying to update)
当我调用 updateLog(message) 时,我相信我正在尝试更新 Main() 的第二个实体(也称为 mainClass)上的日志(richtextbox).当然,这样做会抛出这个异常,因为我什至没有看到我正在使用的当前 Main 的副本.
When I call updateLog(message) I believe I am trying to update the Log (richtextbox) on the second entity of Main() otherwise known as mainClass. Of course, doing so will throw me this exception because I haven't even seen that replica of the current Main I am using.
这就是我的目标,感谢其中一位给出答案的人:
This is what I am shooting for, thanks to one of the people that gave an answer:
Main mainClass = Application.OpenForms.OfType<Main>().First(); logAddDelegate = mainClass.logAdd; logAddDelegate(message);
我不需要使用 new() 运算符创建 mainClass,因为我不想创建表单的新蓝图,我希望能够编辑当前表单.
I need to create mainClass not with the new() operator because I dont want to create a new blueprint of the form I want to be able to edit the current form.
上面的代码不起作用,我什至找不到 Application.这甚至是 C# 语法吗?
The above code doesn't work though, I can't even find Application. Is that even C# syntax?
如果我能让上面的代码工作,我想我可以解决我的问题,并在寻求答案几个小时后最终解决这个问题.
If I can get the above code to work, I think I can resolve my issue and finally lay this problem to rest after a couple of HOURS of seeking for answers.
最终
感谢以下一位用户,我想通了.这是我更新的代码:
I figured it out thanks to one of the users below. Here is my updated code:
主窗体代码:
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 上运行并封装了许多本机的 Win32 概念,例如窗口、列表视图、编辑框(标准文本框的 Win32 名称).这意味着您可以拥有 TextBox 或 Form 的有效 .NET 实例,但还没有该项目的基础 Windows 版本(EditBox 或 Window).当 HandleCreated 为 true 时,将创建项目的 Windows 版本.
In order to understand what is happening, you need to understand how .NET and Windows relate to one another. .NET runs on Windows and wraps many of the native, Win32 concepts like a window, a listview, an editbox (the Win32 name for a standard textbox). This means that you can have a valid .NET instance of a TextBox or a Form, but not have the underlying Windows version of that item (EditBox, or Window) yet. When HandleCreated is true, the Windows version of the item is created.
出现您的问题是因为在创建窗体的窗口之前调用 logAdd 方法.这意味着在 Form 实例被实例化之后但在 Window 句柄创建之前的启动过程中的某个地方,正在尝试调用 logAdd.如果您向 logAdd 添加断点,您应该能够看到该调用在做什么.您会发现调用是在您在 logger 类中创建的 Main 实例上进行的,而不是在实际运行的 Main 实例上进行的.由于记录器实例从未显示,因此未创建窗口句柄,因此您会收到错误.
Your issue is occurring because something is leading to the logAdd method being called before the Form's Window has been created. This means somewhere during your startup after the Form instance has been instantiated but before the Window handle has been created, something is trying to call logAdd. If you add a breakpoint to logAdd, you should be able to see what is doing that call. What you will find is that the call is being made on the Main instance you create in your logger class and NOT the Main instance that is actually running. As the logger instance never gets shown, the window handle is not created, and so you get your error.
应用程序运行的一般方式是在您的启动方法中调用 Application.Run(new Main()),该方法通常在 Program 类中,称为 Main.您需要您的记录器指向此 main 实例.
The general way an application runs is to call Application.Run(new Main()) in your startup method, which is usually in the Program class and called Main. You need your logger to point to this instance of main.
有几种方法可以获取表单的实例,每种方法都有自己的注意事项,但为简单起见,您可以将实例暴露在 Main 类本身之外.例如:
There are several ways to get the instance of the form, each with its own caveats, but for simplicity you could expose the instance off the Main class itself. For example:
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 或 BeginInvoke."的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!