5

Alternate question: Why is VS10 so keen to complain about Invoke?

In my continuing quest to make my app work become the worlds best C# programmer, I have decided that threads are a Good Thing™.

MSDN has a helpful article on making thread-safe calls to controls, but it (and seemingly every other article on the subject) obliquely references a method called Invoke. Sometimes even BeginInvoke, which I've read is to be preferred.

All this would be great, if I could get visual studio to recognise Invoke. MSDN says that it is contained in the System.Windows.Forms assembly, but I'm already 'using' that. To be sure, I've also tried using System.Threading, but to no avail.

What hoops do I need to jump through to get invoke working?

Tom Wright
  • 11,278
  • 15
  • 74
  • 148
  • What do you mean by "Visual Studio recognize Invoke"? Intellisense? – Stefan Steinegger Jun 24 '10 at 11:58
  • Are you talking about invoking a method on a control that was created on a different thread then the currently executing thread? – Ryan Conrad Jun 24 '10 at 11:58
  • 5
    When you become the worlds best C# programmer you will probably realize that threads are A Very Bad Thing. Or, at least, explicit management of threads is a bad thing. – Eric Lippert Jun 24 '10 at 12:45
  • @Eric You prompted another question: http://stackoverflow.com/questions/3110154/why-is-the-explicit-management-of-threads-a-bad-thing – Tom Wright Jun 24 '10 at 13:05

6 Answers6

4

Invoke is within Control. I.e. Control.Invoke();

There's no way to call Invoke directly as there's no such method in System.Windows.Forms. The Invoke method is a Control Member.

Here's an example I made earlier:

public delegate void AddListViewItemCallBack(ListView control, ListViewItem item);
public static void AddListViewItem(ListView control, ListViewItem item)
{
    if (control.InvokeRequired)
    {
        AddListViewItemCallBack d = new AddListViewItemCallBack(AddListViewItem);
        control.Invoke(d, new object[] { control, item });
    }
    else
    {
        control.Items.Add(item);
    }
}
Community
  • 1
  • 1
djdd87
  • 67,346
  • 27
  • 156
  • 195
3

You need to call Invoke on an instance of something which contains it - if you're using Windows Forms, that would be a control:

control.Invoke(someDelegate);

or for code within a form, you can use the implicit this reference:

Invoke(someDelegate);

You shouldn't need to go through any particular hoops. If Visual Studio is complaining, please specify the compiler error and the code it's complaining about. There's nothing special about Invoke here.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
2

The winform Invoke is an instance method of Control - you just need an instance of a control (which can be this in many cases). For example:

txtBox.Invoke(...);

It can also be accessed via an interface, or sync-context if you want abstraction - but the easiest approach is to handle it at the UI via an event, in which case controls are conveniently available.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
1

If you really want to become the worlds best c# programmer you have to learn that threads are not a good thing unless used correctly.

Updating the UI across threads is usually a sign that you are abusing threads.

Anyways, it's not enough to use using System.Windows.Forms, you have to add it to the references. Make a right-click on References in your project explorer, then Add References and select System.Windows.Forms

  • Gee thanks! You went and done gone made me confused. (Here's another question you might like to answer: http://stackoverflow.com/questions/3110154/why-is-the-explicit-management-of-threads-a-bad-thing) – Tom Wright Jun 24 '10 at 13:06
  • "Updating the UI across threads is usually a sign that you are abusing threads." Wow, that's a new one to me. So if I put a long analysis operation in a BG thread to keep the UI responsive, but the user would like to see the incremental results quickly, so my BG thread periodically posts results back to the UI thread, this is abuse? And you're now going to reveal the better solution? – Conrad Albrecht Jun 24 '10 at 13:38
  • 2
    Yes, it's quite simple: Use events. The BG Thread provides an event to which the UI can subscribe, i.e. "FileCopied", "NumberCalculated", etc. The UI can subscribe to it and the background worker would still work without modifications if you switch your code from winforms to WPF, implement multi-language UI, change a boring dialog to a fancy dialog, etc. –  Jun 24 '10 at 13:46
  • 2
    @Conrad: dbemerlin has an excellent point. Another way to think about it is that *the analysis operation's business is the analysis, not the UI*. There shouldn't be *any* logic to update the UI directy in an analysis function; that's not its concern. If an analysis function offers as a service a callback to describe its current state, great, that *is* its concern. What the effect on the UI of that callback is can be handled by the UI code. – Eric Lippert Jun 24 '10 at 14:59
  • 1
    OK, just a misunderstanding of meaning. Actually my BG thread *does* use an event exactly as you guys advocate; still sounds like "updating UI across threads" to me. In fact my event fires on the BG thread (because that's the only thread the firing method knows about). But the event triggers a UI method (which is also therefore running on the BG thread) which must then Invoke another UI method "across threads". – Conrad Albrecht Jun 25 '10 at 04:59
0

Invoke is a method on objects, usually found on the Controls in the Forms library and some async classes. You of course need specific objects to be able to call Invoke on that control/class.

Femaref
  • 60,705
  • 7
  • 138
  • 176
0

You're presumably trying to call Invoke from within a class (i.e. not from within a Form or a Control). Move your code out of the class and into a form or control, and you will see that Invoke compiles and works correctly (strictly speaking, your code should reference this.Invoke, which makes the source of the method clear, but Invoke will work as well since it assumes the this).

MusiGenesis
  • 74,184
  • 40
  • 190
  • 334