我刚刚发布了一个关于如何让委托(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/