有没有办法找到控件的所有者线程?

Fla*_*ack 6 c# multithreading

我正在处理一个大型应用程序的线程问题(获得跨线程异常).有没有办法找到创建特定控件的线程名称/ ID?

当我尝试将新控件添加到控件的控件集合时,会发生错误.我不能真正创建一个小的,可重复的样本,所以我会尽可能地描述它.

我有一个位于表单上的主控件,称之为_mainControl.在它的构造函数中,我实例化了另一个控件的实例,例如

ChildControl _childControl = new ChildControl();
Run Code Online (Sandbox Code Playgroud)

现在_childControl存在但我还没有将它添加到_mainControls集合中.

最终,_mainControl会收到一个我应该添加控件的事件通知.在事件处理程序中,我检查是否.InvokeRequired,如果是,我调用处理程序,如下所示:

AddControlEventHander(...)
{
    if(InvokeRequired)
    {
        BeginInvoke(new MethodInvoker(AddControlEventHander);
        return;
    }
    Controls.Add(_childControl);
}
Run Code Online (Sandbox Code Playgroud)

Controls.Add总是抛出异常("跨线程操作无效:从创建它的线程以外的线程访问控件'_item').

现在,我不明白这是怎么回事.我在创建_mainControl的同一个线程上创建了_childControl.当我在调试时查看线程窗口时,当我调用Control.Add时,当添加_childControl时,当前线程名称/ id是相同的.但是,让我最困惑的是来自_mainControl的以下调用:

InvokeReuqired == false;
_childControl.InvokeRequired == false;
_childControl._item.InvokeRequired == true; //I made _item public just to try this and it returns true!
Run Code Online (Sandbox Code Playgroud)

怎么可能?_childControl是否有可能在一个线程上创建,而其子项以某种方式在另一个线程上创建?所有_childControl的子节点都是在初始化期间创建的,正如通常所做的那样.

如果有人对可能发生的事情有任何提示/建议,请告诉我.

谢谢.

编辑:

如果有人有兴趣,我会发现发生了什么.我很好奇如何在一个线程上创建一个控件,并且它是在另一个线程上创建的子节点,即使InitializeComponent都是在同一个线程上完成的.所以,我发现了使用类似于Charles建议的代码创建孩子的线程.一旦我知道了,我至少知道要关注哪个主题.然后我打破了子控件的OnHandleCreated事件并找到了问题.

我不知道的一件事是控件的句柄是在控件首次可见时创建的,而不是在创建控件时创建的.因此,没有控件的线程试图将其可见性设置为true.所以我添加了一个检查以查看InvokeRequired并认为这样做会有所帮助.但是,我真的没想到的是调用InvokeRequired会创建控件的句柄(如果它还没有创建)!这实际上导致在错误的线程上创建控件,并且始终为InvokeRequired返回false.我通过触摸控件的Handle属性来解决这个问题,以便在调用InvokeRequired之前创建它.

谢谢你的帮助:)

Cha*_*ana 5

要获取控件的所有者线程,请尝试以下操作:

private Thread GetControlOwnerThread(Control ctrl)
{
    if (ctrl.InvokeRequired)
        ctrl.BeginInvoke(
            new Action<Control>(GetControlOwnerThread),
            new object[] {ctrl});
    else
        return System.Threading.Thread.CurrentThread;
}
Run Code Online (Sandbox Code Playgroud)

子控件可以与父控件(容器控件)位于不同的线程上吗?是的,这完全取决于构造控件时正在运行的线程(新建)

您始终必须检查 InvokeRequired...因为您永远不知道哪个线程可能会调用您正在编码的方法...是否需要为每个子控件单独检查 InvokeRequired,取决于您对所有控件都已执行的确定程度是否在同一线程上创建。如果所有控件都是在创建表单时在同一个初始化例程中创建的,那么您可以安全地假设它们都是在同一个线程上创建的

  • 因为 Action 没有返回值,所以 `Action&lt;Control&gt;` 不应该是 `Func&lt;Control, Thread&gt;` 吗?另外,“BeginInvoke”不应该是“Invoke”吗,因为 BeginInvoke 没有返回值?另外,它不应该像“return (Thread)ctrl.Invoke...”一样开头吗? (6认同)