-1

I was able resolve the issue with the input form Stephen Cleary. Please see update 3.

I have a Windows Forms application that has a method with the async modifier. If the method is called inside a button's click event it does not block the UI thread. However, when I call it inside a timer as a callback it freezes the UI. I could not figure out what I am doing wrong here. Please see below my code. This is just a sample project for demonstration purposes.

public Form1()
{
    InitializeComponent();            
}

private async void formCloseAsync()
{
    shutdown stf = new shutdown();
    stf.StartPosition = FormStartPosition.CenterScreen;
    stf.Show();
    var task = Task.Factory.StartNew(processClose);
    await task;
}

private void processClose()
{
    Thread.Sleep(5000);
    Environment.Exit(1);
}

private void simpleButtonAsync_Click(object sender, EventArgs e)
{
    formCloseAsync();
}        

private void _simpleButtonTimer_Click(object sender, EventArgs e)
{
    Timer _shutdownTimer = new Timer(delegate
    {
       formCloseAsync();
    }, null, 5000, Timeout.Infinite);
}

Update 1: Thanks All for your valuable input. Please see the updated code below

public Form1()
    {
        InitializeComponent();

    }

    private Timer _shutdownTimer;
    private void formCloseAsync()
    {
        shutdown stf = new shutdown();
        stf.StartPosition = FormStartPosition.CenterScreen;
        stf.Show();

        Task.Run(async ()=>
            { 
                await Task.Delay(5000);
                Environment.Exit(1);
            }
        );
    }

    private void simpleButtonAsync_Click(object sender, EventArgs e)
    {
        formCloseAsync();
    }

    private void _simpleButtonTimer_Click(object sender, EventArgs e)
    {
        _shutdownTimer = new Timer(async delegate
        {
            formCloseAsync();
        }, null, 0, Timeout.Infinite);
    }

However I still have the same issue. shutdown stf is blocked when called inside timer callback. Main UI is okay. No issue with that. I just want the shutdown(stf) GUI to be responsive when created from timer call back. Shutdown GUI has a progress bar.

Update 3:

Here is the final code

public partial class Form1 : Form
{
    readonly shutdown _stf = new shutdown();
    public Form1()
    {
        InitializeComponent();

    }

    private Timer _shutdownTimer;
    private async Task formCloseAsync()
    {

        try
        {
            BeginInvoke(new MethodInvoker(delegate
            {

                _stf.StartPosition = FormStartPosition.CenterScreen;
                _stf.Show();
            }));
            await Task.Run( async () =>
                            {
                                await Task.Delay(5000);
                            });

        }
        catch (Exception ex)
        {

            MessageBox.Show(ex.ToString());

        }
        finally
        {
            Environment.Exit(1);
        }

    }

    private  void simpleButtonAsync_Click(object sender, EventArgs e)
    {
        formCloseAsync();
    }

    private void _simpleButtonTimer_Click(object sender, EventArgs e)
    {
        _shutdownTimer = new Timer(async delegate
        {
            formCloseAsync();
        }, null, 0, Timeout.Infinite);
    }

    private async void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        e.Cancel = true;
         await formCloseAsync();
    }
IamaC
  • 357
  • 1
  • 10
  • 23

2 Answers2

5

Use Task.Delay instead:

await Task.Delay(5000);

Since Thread.Sleep actually blocks the current thread and should not be used within an async method.

You can find out more about this here: When to use Task.Delay, when to use Thread.Sleep?

Community
  • 1
  • 1
ThePerplexedOne
  • 2,920
  • 15
  • 30
  • 3
    The sleep is being called from a background thread, so that's not his problem. He should change it, but it wouldn't cause the problems he's claiming he's having. – Servy Sep 13 '16 at 15:20
1

However, when I call it inside a timer as a callback it freezes the UI.

You can't access UI elements from background threads (I'm guessing stf.Show(); is showing a dialog). The easiest fix is probably to replace System.Threading.Timer with Windows.Forms.Timer.

Other notes:

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • Hi @stephen thanks so much for your input. I have updated my original post. Please see above. I may have not said it correctly which UI is being frozen. Its the shut down UI that is not responsive when called form timer.. – IamaC Sep 14 '16 at 05:42
  • @IamaC: The same answer applies: don't run UI code from a background thread. – Stephen Cleary Sep 14 '16 at 12:32
  • Thanks @stephen. i was able to resolve the issue with your input. Please see update 3 – IamaC Sep 15 '16 at 18:54