I know there are many topcis about my question but I can't find a solution for my case...

I have a panel which I add controls on it at runtime, I tried this code but it doesn't help me, and an error says :

cross-thread operation not valid control 'panel1' accessed from a thread other than the thread it was created on

Here my code :

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

and I call this like this :

AddControlToPanel(panel1, ctrl);
有帮助吗?

解决方案 3

Finaly I solved my problem, my code was correct, just Hide old controls to show new ones, using this nice function :

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

like this :

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

and then, I can recreate my controls like this:

AddControlToPanel(panel1, ctrl);

Thanks all for help :)

其他提示

You can create a control extension within your project's namespace like this:

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

and use it within your code like this:

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

In this case you should also be checking for "IsHandleCreated"

from MSDN: ...InvokeRequired can return false if Invoke is not required (the call occurs on the same thread), or if the control was created on a different thread but the control's handle has not yet been created.

...

You can protect against this case by also checking the value of IsHandleCreated when InvokeRequired returns false on a background thread. If the control handle has not yet been created, you must wait until it has been created before calling Invoke or BeginInvoke. Typically, this happens only if a background thread is created in the constructor of the primary form for the application (as in Application.Run(new MainForm()), before the form has been shown or Application.Run has been called.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top