跨线程操作不是有效的控件

本文关键字:有效 控件 线程 操作 | 更新日期: 2023-09-27 18:00:34

我知道关于我的问题有很多topcis,但我找不到解决我的问题的方法。。。

我有一个面板,我在运行时在上面添加控件,我尝试了这个代码,但它对我没有帮助,错误显示:

跨线程操作无效从线程访问的控件"panel1"除了在上创建的线程

这是我的代码:

public void AddControlToPanel(Panel panel, Control ctrl)
{
    if (panel.InvokeRequired)
    {
        panel.Invoke((MethodInvoker)delegate { AddControlToPanel(panel, ctrl); });
        return;
    }
    else
        panel.Controls.Add(ctrl);
}

我这样称呼它:

AddControlToPanel(panel1, ctrl);

跨线程操作不是有效的控件

您可以在项目的命名空间中创建一个控件扩展,如下所示:

public static class ControlExtensions
{
    public static void UIThread(this Control @this, Action code)
    {
        if (null != @this && (!@this.Disposing || !@this.IsDisposed))
        {
            if (@this.InvokeRequired)
            {
                @this.BeginInvoke(code);
            }
            else
            {
                code.Invoke();
            }
        }
    }
}

并在您的代码中使用它,如下所示:

this.UIThread(() =>
{
    panel1.Controls.Add(ctrl);
});

在这种情况下,您还应该检查"IsHandleCreated"

来自MSDN:…如果不需要Invoke(调用发生在同一线程上),或者控件是在不同线程上创建的,但控件的句柄尚未创建,则InvokeRequired可能返回false。

当InvokeRequired在后台线程上返回false时,还可以通过检查IsHandleCreated的值来防止这种情况。如果尚未创建控件句柄,则必须等到创建控件句柄后才能调用Invoke或BeginInvoke。通常,只有在显示窗体或调用application.Run之前,在应用程序的主窗体的构造函数中创建了后台线程(如application.Run(new MainForm())),才会发生这种情况。

最终我解决了我的问题,我的代码是正确的,只是使用这个漂亮的函数隐藏旧控件以显示新控件:

private void SetControlPropertyValue(Control oControl, string propName, object propValue)
        {
            if (oControl.InvokeRequired)
            {
                SetControlValueCallback d = new SetControlValueCallback(SetControlPropertyValue);
                oControl.Invoke(d, new object[] { oControl, propName, propValue });
            }
            else
            {
                Type t = oControl.GetType();
                PropertyInfo[] props = t.GetProperties();
                foreach (PropertyInfo p in props)
                {
                    if (p.Name.ToUpper() == propName.ToUpper())
                    {
                        p.SetValue(oControl, propValue, null);
                    }
                }
            }
        }

像这样:

foreach (Control item in panel1.Controls.OfType<Type>())
                {
                    SetControlPropertyValue(item, "Visible", false);                 
                }

然后,我可以像这样重新创建我的控件:

AddControlToPanel(panel1, ctrl);

感谢所有人的帮助:)