跨线程操作无效控制

时间:2014-04-28 11:16:41

标签: c# thread-safety invoke

我知道有很多关于我的问题的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);

3 个答案:

答案 0 :(得分:2)

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

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);
});

答案 1 :(得分:0)

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

来自MSDN

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

...

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

答案 2 :(得分:0)

最终我解决了我的问题,我的代码是正确的,只是隐藏旧的控件来显示新的,使用这个很好的功能:

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);

感谢大家的帮助:)