0

I've searched through a lot of examples for asynchronously updating UI controls in WinForms, and most of the examples have tons of code. Is there a way to make this easier? I just feel like they're too much work at this time.

I've seen people do this:

await Task.Run(() =>
{
    doSomething();
});

But I've heard that's bad and doesn't work right, and I don't like peppering my UI code with a multiple instances of await Task.Run(()=> {});. And I've seen tons of examples on background workers.

Is there a better way to do this that won't require too much boilerplate code?

Kevin
  • 11
  • 2
  • 1
    A better way to do _what_? There's nothing wrong with the code snippet you posted per se, but there's so little context that really nothing useful can be said about it. `Task.Run()` is IMHO today the best way to handle long-running operations that are otherwise not already asynchronous, and `await` is the best way to synchronize the UI code with such long-running operations. – Peter Duniho Nov 15 '15 at 08:06
  • 1
    But there's nothing in your question that provides any sort of real problem statement. Fact is, done correctly there **won't** be a lot of extra code using worker tasks and updating the UI; if you have a lot of extra code, you did it wrong. But there's no way to help you know how to fix code where you did it wrong, unless you provide [a good, _minimal_, _complete_ code example](http://stackoverflow.com/help/mcve) that shows clearly what you're talking about. – Peter Duniho Nov 15 '15 at 08:06
  • I just want to update code in without calling the illegal cross thread error – Kevin Nov 15 '15 at 08:08
  • 1
    There's nothing in your question that actually asks that. And if that is in fact all you want to know, there are already lots of questions and answers on Stack Overflow addressing that. All you have to do is search for the exception message text. – Peter Duniho Nov 15 '15 at 08:10
  • 1
    If the proposed answer does in fact answer the question you _meant_ to ask, then your question is a duplicate. There are already several answers identical to the one posted here, including this one (and is in fact superior to the one posted here): http://stackoverflow.com/a/3874177 – Peter Duniho Nov 15 '15 at 08:13
  • Peter the answer you linked doesn't work for me, sorry – Kevin Nov 15 '15 at 08:20
  • Don't be ridiculous. It can't not work. It is fundamentally identical to the answer you accepted. – Peter Duniho Nov 15 '15 at 08:22
  • @PeterDuniho, Nice suggestion. That looks a bit better than mine. I think I'll be going with that in the future. :) – Mark Buffalo Nov 15 '15 at 08:23
  • @Kevin The one Peter linked is superior to mine. If it doesn't work for you, perhaps you've forgotten to implement `using System.ComponentModel`? – Mark Buffalo Nov 15 '15 at 08:42

1 Answers1

0

There's one method I like to use:

  1. Create a control extension that invokes an action:

    public static void Update(this Control ctrl, Action a)
    {
        if (ctrl.InvokeRequired) 
        { 
            ctrl.BeginInvoke(new MethodInvoker(a), null); 
        }
        else 
        { 
            a.Invoke(); 
        }
    }
    
  2. And then call it like this: control.Update(()=> { /* code to update control */ });

For example:

listView1.Update(() =>
{
    ListViewItem lvi = new ListViewItem("something");
    lvi.SubItems.Add("something else");
    listView1.Items.Add(lvi);
});
Mark Buffalo
  • 766
  • 1
  • 10
  • 25
  • (1) This is nothing more than a cut down (thus limited) version of `Control.Invoke`. (2) Contains redundancy - 'new MethodInvoker(a)` instead of just `a`. (3) Does different things (`BeginInvoke` vs `Invoke`) – Ivan Stoev Nov 15 '15 at 08:32
  • @IvanStoev Thanks! I appreciate the feedback. Just noticed the redundancy. Out of curiosity, how is this limited? Why would you use BeginInvoke vs. Invoke? – Mark Buffalo Nov 15 '15 at 08:35
  • 1
    `Control.Invoke` is synchronous (blocks the calling non UI thread until the call is processed by the UI thread), while `BeginInvoke` is similar, but does not block the calling thread. There are usages for both. Your method is limiting, well, because it does not provide that flexibility. And since you are forcing usage of a delegate, the equivalent of the code above is `listView1.BeginInvoke(new Action(() => ....))` just to use concrete `Delegate` (`Action` in this case). Note that once you put the code into a delegate, there is no need to check `InvokeRequired`. – Ivan Stoev Nov 15 '15 at 09:24