0

Is there any simply way to call my existing void method asynchronously, so that my form show up instantly without waiting for that method to end?

That method reads directory that contains almost 20000 files to array, and populates it to ListView. It takes almost ten seconds when running first time and Windows have not cached it yet.

darx
  • 1,417
  • 1
  • 11
  • 25

3 Answers3

3

You can run your code in a new thread so it doesn't block the UI thread, it's pretty trivial to do this using the TPL

Task.Run(() =>
{
    // enumerate files
    return files;
}).ContinueWith(t =>
{
     var files = t.Result;
     // update list view
}, TaskScheduler.FromCurrentSynchronizationContext());
James
  • 80,725
  • 18
  • 167
  • 237
  • 1
    Well that's simple! But sadly does not allow adding items to ListView, because it's created in other thread. – darx Jul 19 '14 at 10:56
  • 4
    @darx you just need to delegate access back to the UI thread when updating the list view, see my update – James Jul 19 '14 at 11:09
  • I have to read more about TPL, but even before I fully understand what is going on there, I get it working. That's exactly what I wanted, thanks! – darx Jul 20 '14 at 08:52
1

You can used Task but also return results and use async/await or use dispatcher to update UI.

try
{
   var result = await Task.Run(() => GetResult());
   // Update UI: success.
   // Use the result.

   listView.DataSource = result;
   listView.DataBind();
}
catch (Exception ex)
{
   // Update UI: fail.
   // Use the exception.
}

Look at this

Community
  • 1
  • 1
Jan Barta
  • 450
  • 2
  • 8
  • Its a windows form application. you cannot assign `DataSource` directly to `ListView` control. There is no such property like `DataSrouce` you have to fill all items manually by using `Items.Add()` method. Are you sure this method will not throw error like `Cross Thread Exception`? – Shell Jul 19 '14 at 11:38
  • Sorry, I'm used to this from ASP.NET. But it's just example that here you can bind items. Yes, because you get resources in task on separed thread and then return them to main UI thread and only render them. – Jan Barta Jul 19 '14 at 11:58
  • I asked you that because i haven't used that method before. So, i am completely unaware of that the method will allow to update UI from different thread. If it works fine than it's better than my given solution. – Shell Jul 19 '14 at 12:00
  • 1
    Well the trick is that it's not different thread. Since you get back from task using async await you will get UI thread again. – Jan Barta Jul 19 '14 at 12:04
0

Try following method

private delegate void AddItem(string item);
private AddItem addListItem;

private void form_load()
{
    new System.Threading.Thread(new ThreadStart(this.FillItems)).Start();
}

private void FillItems()
{
    addListItem = new AddItem(this.addItem);
    ///Fill your list here
    this.Invoke(addListItem, "ABC");
    this.Invoke(addListItem, "XYZ");
    this.Invoke(addListItem, "PQR");
}

private void addItem(string item)
{
   listView1.Items.Add(item);
}
Shell
  • 6,818
  • 11
  • 39
  • 70
  • You should avoid creating dedicated threads unless you *really* need to. The TPL is a much better option as it does a lot of the heavy lifting for you, plus it reuses existing threads from the ThreadPool. – James Jul 19 '14 at 12:17