简体   繁体   中英

How to manage loading animation thread? - C#

I am trying to do a loading form. So that I've put an animated gif to do the loading effect.

What happens is that when I use the loading.Visible = true property this is not visible until the click event ends.

Here is the code.

Private void btnLogin_Click (object sender, EventArgs e)
{
     loading.Visible = true;
     if (ConnectDataBase())
     {
         OpenForm2();
         This.Close();
     }
     else MessageBox.Show ("User or password, incorrect");
     loading.Visible = false;
}

The Data Base takes 3 to 6 seconds to respond in the ConnectDataBase() function, but the gif does not become visible until the event ends.

Someone could tell me, how could I do this?

In order for this to work you need to invoke ConnectDataBase() on a different thread. One way to do this is:

private void btnLogin_Click(object sender, EventArgs e)
{
    loading.Visible = true;
    Task.Run<bool>(() =>
        {
            return ConnectDataBase();
        })
        .ContinueWith(t =>
        {
            if (t.Result)
            {
                OpenForm2();
                this.Close();
            }
            else MessageBox.Show("User or password, incorrect");
        }, TaskScheduler.FromCurrentSynchronizationContext());
}

You will need to run the database connection in the background. There are many ways of doing this but with the advent of async/await , this would be the easiest way:

private async void btnLogin_Click (object sender, EventArgs e)
{
     loading.Visible = true;
     if (await Task.Run(() => ConnectDataBase()))
     {
         OpenForm2();
         This.Close();
     }
     else MessageBox.Show ("User or password, incorrect");
     loading.Visible = false;
}

Note the following changes:

  • I made the method async void to signal to the compiler that we want to use async/await
  • I created a task to run the database connection:

     await Task.Run(() => ConnectDataBase()) 

    This will return a bool , the result of ConnectDataBase() and will essentially do the same thing as the other answer here, just with less manual clutter and handling of tasks.

Observe : With background execution like this it is possible for the user to click on the Login button again, while the first click is still executing (and trying to connect to the database). You should take steps to ensure this is not possible, like disabling the login button (and other fields, such as username, password, etc.) while this is executing, something like:

private async void btnLogin_Click (object sender, EventArgs e)
{
     btnLogin.Enabled = eUsername.Enabled = ePassword.Enabled = false;
     loading.Visible = true;
     ... rest of method
     loading.Visible = false;
     btnLogin.Enabled = eUsername.Enabled = ePassword.Enabled = true;
}

Note It would also be better, if possible, to rewrite the ConnectDataBase method to be async in nature as most .NET database connection services nowadays have methods to do this. Without knowing more about what this method does I can only make a general comment.

Here's an example of how to write a SQL Server connection attempt:

public static async Task<bool> ConnectDataBase()
{
    var connection = new SqlConnection("connection string");
    try
    {
        await connection.OpenAsync();
        // store "connection" somewhere I assume?
        return true;
    }
    catch (SqlException)
    {
        connection.Dispose();
        return false;
    }
}

With this change you would change your if -statement in your original method to this:

     if (await ConnectDataBase())

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM