0

I need to show a form and at the same time upload some data. I'm looking at how to do it with async and await, but I'm still blocking the UI.

Here's my code:

using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Async
{
    public partial class Form2 : Form
    {
        public Form2()
        {
            InitializeComponent();
        }

        public async void Init()
        {
            Text = "Setting Form Caption";
            label1.Text = "Setting label1 text";
            label2.Text = "Setting label2 text";

            var res = await GetData();
            res.ForEach(r => listBox1.Items.Add(r));
        }

        async Task<List<int>> GetData()
        {
            await Task.Delay(200);
            List<int> lTmp = new List<int>();

            await Task.Run(() =>
            {
                foreach (var t in Enumerable.Range(1, 10000))
                    lTmp.Add(t);

            });
            return lTmp;
        }
    }
}

This code is called at Button click inside another form with this code:

private void button1_Click(object sender, EventArgs e)
{
    Form2 frm = new Form2();
    frm.Init();
    frm.Show();
}

Executing this, I have 2 questions:

  1. If I remove Task.Delay(200) from the GetData() method, I can't see the text of the labels until the data has finished loading.
  2. I can't move the Form2 until the GetData() is finished

Could someone tell me what I am doing wrong?
Or should I take some other approach?

Peter Csala
  • 17,736
  • 16
  • 35
  • 75
Miquel
  • 1
  • 1
  • 1
    Async all the way. The button1_Click handler must be async, and await the call to Init. – CodeCaster Jul 03 '20 at 12:05
  • `async void` [:(](https://stackoverflow.com/q/45447955/9363973) – MindSwipe Jul 03 '20 at 12:07
  • 1
    Well async void is not bad ... It is just fire and forget... His problem here is that assigning values to controls means it has to run on the UI thread. – Legacy Code Jul 03 '20 at 12:10
  • do what @CodeCaster said call the init function with await and add async to the event handler also return a Task from init not void. void and async are fine with event handlers only – HMZ Jul 03 '20 at 12:11
  • @LegacyCode you cant await a function that doesn't return a Task – HMZ Jul 03 '20 at 12:13
  • Yes ... That’s why it is called fire and forget. – Legacy Code Jul 03 '20 at 12:19
  • Async void is *always* bad. Because you cannot await a function that doesn't return a task. Meaning exceptions can (and will) be lost. I highly recommend watching Brandon Minnick's [talk about async/ await](https://www.youtube.com/watch?v=J0mcYVxJEl0). Instead of async void, use `async Task`. The only exception should be `EventHandlers`, as documented by MS themselves [here](https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming) – MindSwipe Jul 03 '20 at 12:20
  • 1
    `async void` was created for the use cases when it needs to be used for event handling where the signature must be `void` and can't be `Task` – Pac0 Jul 03 '20 at 12:25
  • Move `Init()` call to `Form.Load` Event handler, don't call it externally. Make `Form2_Load` `async`, change `Init()` to `async Task` and call `await Init()` then. – aepot Jul 03 '20 at 23:54

0 Answers0