9

In my application I have class that is responsible for all database actions. It is called from main class and uses delegates to call methods after action is complete. Because it is asynchronous I must use invoke on my GUI, so I've created a simple extensions method:

 public static void InvokeIfRequired<T>(this T c, Action<T> action)
            where T: Control
        {
            if (c.InvokeRequired)
            {
                c.Invoke(new Action(() => action(c)));
            }
            else
            {
                action(c);
            }
        }

This works fine when I try to call it on textBox:

textBox1.InvokeIfRequired(c => { c.Text = "it works!"; });

but when I try to call it on ToolStripStatusLabel or ToolStripProgressBar I get an error:

The type 'System.Windows.Forms.ToolStripStatusLabel' cannot be used as type parameter 'T' in the generic type or method 'SimpleApp.Helpers.InvokeIfRequired(T, System.Action)'. There is no implicit reference conversion from 'System.Windows.Forms.ToolStripStatusLabel' to 'System.Windows.Forms.Control'.

I know that this is probably a simple fix, but I just can handle it :/

Misiu
  • 4,738
  • 21
  • 94
  • 198
  • Maybe this similar question will help you. http://stackoverflow.com/questions/1127973/how-do-i-make-cross-threaded-calls-to-a-toolstripstatuslabel – Rugbertl Jun 20 '16 at 09:15

3 Answers3

10

This is because ToolStripItem (base for those two causing an error) is a Component and not a Control. Try calling your extension method on the tool strip that owns them and adjust your delegate methods.

slawekwin
  • 6,270
  • 1
  • 44
  • 57
  • I fount just a second ago the same info on Google :) But how I should access ToolStripStatusLable from statusStrip? So I can pass statusStrip to my method? – Misiu Sep 14 '12 at 06:54
  • 2
    http://msdn.microsoft.com/en-us/library/system.windows.forms.toolstrip.items.aspx MSDN is your friend :) – slawekwin Sep 14 '12 at 06:56
  • You're fast :) but how to access Items? only by index or can I do it by name? For example if I name ToolStripStatusLabel 'status' how can I access it in my delegate? only like `statusStrip1.Items[0]`? I'm asking because I will be adding controls to statusStrip dynamically and I can mess up index of my control. – Misiu Sep 14 '12 at 06:59
  • 1
    http://msdn.microsoft.com/en-us/library/25b5ws77.aspx It was just 2 click away... please read documentation – slawekwin Sep 14 '12 at 07:04
  • Don't ya love this place? :) – Alan Aug 03 '23 at 13:44
3

I'd like to add up to the accepted solution. You can get the control from the component by using the GetCurrentParent method of the ToolStripStatusLabel.

Instead of doing toolStripStatusLabel1.InvokeIfRequired, do toolStripStatusLabel1.GetCurrentParent().InvokeIfRequired

Mathter
  • 747
  • 7
  • 14
  • 1
    Thanks for the answer. I have been working with Control, but after getting your answer, I just finished my work. – sebu Oct 10 '19 at 12:40
2

Extension method using GetCurrentParent().InvokeRequired

public static void ToolStripStatusInvokeAction<TControlType>(this TControlType control, Action<TControlType> del)
    where TControlType : ToolStripStatusLabel
    {
        if (control.GetCurrentParent().InvokeRequired)
            control.GetCurrentParent().Invoke(new Action(() => del(control)));
        else
            del(control);
    }

Calling the ToolStripStatusInvokeAction Extension:

toolStripAppStatus.ToolStripStatusInvokeAction(t =>
{ 
    t.Text= "it works!";
    t.ForeColor = Color.Red;
});
sebu
  • 2,824
  • 1
  • 30
  • 45