Search code examples
c#multithreadinginvoke

Add a control to Controls property from another thread in C#


I need to add a new control to a control from a background worker in c#. I tried to use Type.InvokeMember(), but I alway get an error. That´s my code:

private delegate void AddControlThreadSafeDelegate(Control newControl, Control parent);

public static void AddControlThreadSafe(Control newControl, Control parent)
{
    if (newControl == null) return;
    if (parent == null) return;

    if (parent.InvokeRequired)
    {
        parent.Invoke(new AddControlThreadSafeDelegate(AddControlThreadSafe),
            new object[] { newControl, parent });
    }
    else
    {
        parent.GetType().InvokeMember("Controls.Add", BindingFlags.InvokeMethod, null, parent, new object[] { newControl });
    }
}

The error is

The method "System.Windows.Forms.FlowLayoutPanel.Controls.Add" could not be found

I don´t get an error if I instead invoke "Hide". It seems like it doesn´t work, because the method doesn´t belong directly to the parent but to one of it´s propertys. Does anyone know how to fix this or another way to do it?


Solution

  • You do not need to do the Cermony with creating a delegate etc. You could just use a lambda:

    parent.Invoke(() => parent.Controls.Add(newControl));
    

    In older versions of .net you may need an explicit cast:

    parent.Invoke((Action)(() => parent.Controls.Add(newControl)));
    

    Also, if you are already on the UI thread you do not have to mess around with InvokeMember, just call:

    parent.Controls.Add(newControl);
    

    Note that background worker is mostly superseded by Task and async/await, so modern code should look something like this:

    // gather parameters from the UI
    var result = await Task.Run(() => MyBackgroundMethod(myParameter));
    // Update UI with the results