首页 > 解决方案 > 如何知道何时创建了 Windows 窗体上的所有控件句柄?

问题描述

启动时,我的 Windows 窗体中有竞争条件。我想我已经确定了问题,但不确定解决问题的最佳/最简单方法。

Invoke或者BeginInvoke在创建控件之前不能在窗口句柄上调用。

我已经解决了试图操作在主线程上创建的 Windows 控件(通过使用.InvokeRequiredand .Invoke)的工作线程带来的 CrossThreadException 问题。我已经得出结论,在启动时这里存在竞争条件,该工作线程启动并开始接收来自其他服务的消息,有时在创建表单上所有控件的句柄之前,它会尝试操作一个(启用按钮, 例如)。如果尚未创建该按钮句柄,则会出现异常。

我尝试或考虑尝试的事情:

  1. 在其他 SO 问题中,我从 MSDN被定向到此页面。我曾希望在Form.Shown事件处理程序中启动我的工作线程可以解决问题。但是,中断此事件处理程序并检查环境表明.IsHandleCreated相关按钮是false,因此问题仍然存在。
  2. 在工作线程中打开网络套接字之前,我可以旋转等待,遍历表单中的所有控件并检查它们的.IsHandleCreated属性,但看到唯一返回的东西Form.Controls是表单的直接子级,所以我需要某种递归来检查一切。
  3. 我可以为所有检查 的函数添加一个额外.IsHandleCreated的检查.IsInvokeRequired,但是其中有很多,并且希望有更简单的东西。
  4. 与 1 类似,我可以创建一个可以由网络消息操作的所有 Controls 的列表,并让工作线程自旋等待,直到创建了所有 Handles,然后再在网络上侦听。同样,这看起来很笨重且维护成本很高。

所以我的问题是,是否有一种简单/简单的方法可以知道表单上的所有控件何时创建了它们的句柄,之后我将创建这个工作线程来开始监听网络流量?也许是一个事件?或者这是一个 XY 问题,我应该考虑一种完全不同的方法? 这个问题是相关的,但接受的答案(上面的1)并不能解决我的问题。

基本设置是这样的:

// Program.cs
static void Main()
{
  ....
  MyForm form = new MyForm();
  Application.Run(form);
}

// MyForm.cs
public MyForm()
{
  InitializeComponent();
  ...
  UDP_ReceiveInterface recvInterface = new UDP_ReceiveInterface(...);
}

private void MyForm_Shown(object sender, EventArgs e)
{
  recvInterface.Activate();
}

// UDP_ReceiveInterface.cs
...
public void Activate()
{
  listenThread_ = new Thread(new ThreadStart(ListenForPackets));
}

private void ListenForPackets()
{
  // opens up a socket with network info from a config file
}

我已经尝试将UDP_ReceiveInterface.Activate()函数移动到不同的地方......在 MyForm 构造函数中,在 Program.csform中创建之后,如上所示,在MyForm_Shown事件处理程序中。整个 GUI 由 TabControl 控制,因此所有控件都位于六个 TabPage 之一上。

标签: c#.netmultithreadingwinforms

解决方案


推荐阅读