且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

"跨线程操作无效"对内部控制异常

更新时间:2023-08-23 14:47:52

在哪里 pnlFoo 创建,并在其中线程?你知不知道正在创建的句柄时?如果它是在原来的(非UI)线程创建,这就是问题所在。



应创建并在同一个线程访问在同一个窗口中的所有控制手柄。在这一点上,你不需要的两个的为调用是否需要检查,因为 CTRL 面板应使用同一主题。



如果这没有帮助,请提供一个简短而完整的程序来演示该问题。


I've been struggling with this for quite a while: I have a function designed to add control to a panel with cross-thread handling, the problem is that though the panel and the control are in "InvokeRequired=false" - I get an exception telling me that one of the controls inner controls are accessed from a thread other than the thread it was created on, the snippet goes like this:

public delegate void AddControlToPanelDlgt(Panel panel, Control ctrl);
    public void AddControlToPanel(Panel panel, Control ctrl)
    {
        if (panel.InvokeRequired)
        {
            panel.Invoke(new AddControlToPanelDlgt(AddControlToPanel),panel,ctrl);
            return;
        }
        if (ctrl.InvokeRequired)
        {
            ctrl.Invoke(new AddControlToPanelDlgt(AddControlToPanel),panel,ctrl);
            return;
        }
        panel.Controls.Add(ctrl); //<-- here is where the exception is raised
    }

the exception message goes like this:

"Cross-thread operation not valid: Control 'pnlFoo' accessed from a thread other than the thread it was created on"

('pnlFoo' is under ctrl.Controls)

How can I add ctrl to panel?!


When the code reaches the "panel.Controls.Add(ctrl);" line - both panel and ctrl "InvokeRequired" property is set to false, the problem is the the controls inside ctrl has "InvokeRequired" set to true. To clarify things: "panel" is created on the base thread and "ctrl" on the new thread, therefore, "panel" has to be invoked (causing "ctrl" to need invoke again). Once both of the invokes are done, it reaches the panel.Controls.Add(ctrl) command (both "panel" and "ctrl" doesn't need invocation in this state)

Here is a small snippet of the full program:

public class ucFoo : UserControl
{
    private Panel pnlFoo = new Panel();

    public ucFoo()
    {
        this.Controls.Add(pnlFoo);
    }
}

public class ucFoo2 : UserControl
{
    private Panel pnlFooContainer = new Panel();

    public ucFoo2()
    {
         this.Controls.Add(pnlFooContainer);
         Thread t = new Thread(new ThreadStart(AddFooControlToFooConatiner());
         t.Start()
    }

    private AddFooControlToFooConatiner()
    {
         ucFoo foo = new ucFoo();
         this.pnlFooContainer.Controls.Add(ucFoo); //<-- this is where the exception is raised
    }
}

Where is pnlFoo being created, and in which thread? Do you know when its handle is being created? If it's being created in the original (non-UI) thread, that's the problem.

All control handles in the same window should be created and accessed on the same thread. At that point, you shouldn't need two checks for whether Invoke is required, because ctrl and panel should be using the same thread.

If this doesn't help, please provide a short but complete program to demonstrate the problem.