Question

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);
Was it helpful?

Solution 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 :)

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top