0

I have a main form with a ListView control that contains a list of remote machines within my domain (Active Directory). By right-clicking on any item, a second form with WMI Objects' details of that machine opens. Retrieving those data takes some time, so I wanted a third form to open, just showing a "please wait"-kinda message. This is the code within my main form:

private async void cmShowDetails_Click(object sender, EventArgs e)
{
    nomeComputer = lvElencoMacchine.SelectedItems[0].Text;

    HamsterWheel hw = new HamsterWheel(); // create an instance of the waiting form

    await Task.Run(()=> {
        WorkstationDetails wdForm = new WorkstationDetails(nomeComputer, FUNZIONEFORM.VISUALIZZAZIONE);
        hw.Close();
        if (!wdForm.IsDisposed) wdForm.ShowDialog();
        });

    hw.ShowDialog();
}

I see that once calling the construction method of the form in which I have to show the machine details, the focus remains on that thread. What am I missing?ù

Thanks. Davide.

Carcigenicate
  • 43,494
  • 9
  • 68
  • 117
Davide Vitali
  • 1,017
  • 8
  • 24
  • Remove the await/async and let the task run. – Nkosi Jun 08 '18 at 15:54
  • @Nkosi uhm... it works until trying to call hw.close(), which get me an invalid cross-thread operation. – Davide Vitali Jun 08 '18 at 15:56
  • right pass the wait form as a state object to the Run task and extract acess from there. I overlooked the cross thread. – Nkosi Jun 08 '18 at 15:59
  • Is there any reason you decided against [BackgroundWorker](https://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker(v=vs.110).aspx#Examples) for this? – Mr Moose Jun 08 '18 at 16:02
  • @MrMoose just lack of skills I guess... I’m new to asynchronous operations. – Davide Vitali Jun 08 '18 at 16:04
  • You should only have one UI thread, and you should only ever be interacting with UI objects on that UI thread. Don't create and show a form on another thread, it's just going to cause you a world of problems. – Servy Jun 08 '18 at 16:09
  • @MrMoose Why do you think that using a BGW would be preferable to using the TPL? Unless you're just so much more used to BGW, there really isn't anything in particular it's better at. – Servy Jun 08 '18 at 16:10
  • @Servy, for Winforms and performing operations on some thread other than the UI thread, it offers a really reasonable option. I would suggest it is a much simpler abstraction than trying to understand async/await for someone that is "new to asynchronous operations" as the OP suggests. – Mr Moose Jun 08 '18 at 16:21
  • 2
    @MrMoose You think that creating an object, adding event handlers, setting various properties on the BGW, is simpler than just awaiting a call to `Task.Run`, and having the code after the `await` run in the UI thread when the background work is done? Honestly I find it much harder to explain event-based asynchronous models to people than `await`. (Having explained both to lots of different people.) – Servy Jun 08 '18 at 16:23
  • @Servy, I'll admit to not having used async/await in Winforms apps primarily because that is what I've always worked with. For all UI elements, you'll need to create event handlers etc anyway. It is _still_ how MS seems to advocate doing things related to long running tasks in their documentation. See [here](https://learn.microsoft.com/en-us/dotnet/framework/winforms/controls/how-to-implement-a-form-that-uses-a-background-operation) and [here](https://learn.microsoft.com/en-us/dotnet/framework/winforms/controls/walkthrough-implementing-a-form-that-uses-a-background-operation) – Mr Moose Jun 08 '18 at 16:30
  • @MrMoose You will still need to use events some, yes, but you won't need to perform complex asynchronous workflows that involve passing between different events in a single logical operation (at least nearly as much) if you use `await`. BGW particularly is a more complex inherent workflow that's not nearly as easy to pick up as, say, adding a button click handler that fires when a button is clicked. – Servy Jun 08 '18 at 16:31
  • Try ```hw.Invoke``` – Michael Puckett II Jun 08 '18 at 17:49
  • @Servy, To be clear I'm not really advocating one over another, just what I've used in the past and that I don't think it is particularly arduous. It has piqued my interest though and there are [posts](https://stackoverflow.com/questions/12414601/async-await-vs-backgroundworker) on SO that discuss this. The referenced post has some comments from Stephen Cleary (who I hold in high regard with all things async/await). That led me to his blog post on the [comparison](http://blog.stephencleary.com/2013/05/taskrun-vs-backgroundworker-intro.html) which I'd recommend the OP read. MS - update examples – Mr Moose Jun 08 '18 at 18:51

1 Answers1

0

You can use SynchronizationContext.Current to run async code that will end up updating the UI.

    SyncronizationContext.Current.Post(d => {
        'YOUR CODE HERE'
    }, null);

This Allows you to run async code on the UI thread which may be where your cross thread issue is coming from.