Show Loading animation during loading data in other thread
Asked Answered
S

1

4

I have an application running with the database. When I load a tables in the datagridview, my form freezes. How to ensure the smooth load animation during loading tables?

I run two threads for animation and load data into the tables, but the animation still does not always work.

 private volatile bool threadRun;

 private void UpdateTab()
 {      
     // Create panel for animation
     Panel loadingPanel = new Panel();              
     // Label, where the text will change
     Label loadingLabel = new Label();
     loadingLabel.Text = "Loading";        

     loadingPanel.Controls.Add(loadingLabel);
     this.Controls.Add(loadingPanel);

     // thread loading animation
     threadRun = true;         

     Task.Factory.StartNew(() =>
     {
         int i = 0;
         string labelText;
         while (threadRun)
         {
             Thread.Sleep(500);
             switch (i)
             {
                 case 0:
                     labelText = "Loading.";
                     i = 1;
                     break;
                 case 1:
                     labelText = "Loading..";
                     i = 2;
                     break;
                 default:
                     labelText = "Loading...";
                     i = 0;
                     break;
            }
            loadingLabel.BeginInvoke(new Action(() => loadingLabel.Text = labelText));
         }
     });

     // thread update DataGridView   
     Thread update = new Thread(ThreadUpdateTab);
     update.Start();
 }

 private void ThreadUpdateTab()
 {
     // SQL Query...
     myDataGridView1.Invoke(new Action(() => myDataGridView1.DataSource = myDataSet1.Tables[0]));
     // ...
     myDataGridView10.Invoke(new Action(() => myDataGridView10.DataSource = myDataSet10.Tables[0]));

     threadRun = false;
 }
Scleroma answered 25/8, 2016 at 8:38 Comment(9)
Why the mix of threads and tasks? Choose one, not both. Choose TPL, IMHO.Tael
Take a look at Load data asynchronously into my DataTable in Windows Forms.Hansen
Also if you may be interested in Showing Transparent Loading Spinner above other ControlsHansen
Reza Aghaei, this is what I need, thank you!Scleroma
@Scleroma If you use the loading spinner without making your load data asynchronous, probably you will see the spinner doesn't spin or is frozen. So you need to make your load data asynchronous.Hansen
@Reza-Aghaei I'll try, but do not want to lose speed in loading data. Thanks for the advice.Scleroma
@Scleroma It's just and example to create delay. You need to use asynchronos way to load data. Show the loading before LoadData and hid it after LoadData. Read my previous comments.Hansen
Take a look at the answer which clarifies what I said in comments.Hansen
The most important thing that you should consider, is When the form is frozen, it means the UI thread is too busy and so even of you try to show a loading animation, it will not animate. You should load data asynchronously.Hansen
H
10

When the form is frozen, it means the UI thread is too busy and so even if you try to show a loading animation, it will not animate. You should load data asynchronously.

You can have an async method which returns Task<DataTable> like the GetDataAsync method which you can see in this post. Then call it in an async event handler. In the event handler, first show the loading image, then load data asynchronously and then hide the loading image.

You can simply use a normal PictureBox showing a gif animation as loading control. Also you may want to take a look at this post to show a transparent loading image.

enter image description here

public async Task<DataTable> GetDataAsync(string command, string connection)
{
    var dt = new DataTable();
    using (var da = new SqlDataAdapter(command, connection))
        await Task.Run(() => { da.Fill(dt); });
    return dt;
}

private async void LoadDataButton_Click(object sender, EventArgs e)
{
    loadingPictureBox.Show();
    loadingPictureBox.Update();
    try
    {
        var command = @"SELECT * FROM Category";
        var connection = @"Your Connection String";
        var data = await GetDataAsync(command, connection);
        dataGridView1.DataSource = data;
    }
    catch (Exception ex)
    {
        // Handle Exception
    }
    loadingPictureBox.Hide();
}
Hansen answered 25/8, 2016 at 10:15 Comment(7)
I found that in my example and in your, animation freezes on dataGridView1.DataSource = data; I can await SQL-queries, but as soon as there is a reference to the form, it animation is froze. Maybe create a new transparent form and show animation on her?Scleroma
That display of data takes timeScleroma
I used 100,000 records and the delay was 250-400 milliseconds. If you want to load more records, it's better to rethink about the way you want to show data. You need to use a paging mechanism or using data grid view in virtual mode and show data page by page.Hansen
For example, I showed 100 records of 100,000 records which I loaded in each page and data-binding took about 10 milliseconds to show data of each page.Hansen
I load 10 DataGridView and during each display data - animation delay. In the case of one large table, your example is ideal.Scleroma
I believe for the current post, it's useful answer. Since the problem now is the delay when performing data-binding and not delay when loading data, I recommend you to ask a new question inspired by this answer.Hansen
I can guess the answer for that question would be something like Since you should perform data-binding in UI thread, if the data-binding itself is time-consuming you should use a mechanism like paging.Hansen

© 2022 - 2024 — McMap. All rights reserved.