简体   繁体   中英

UI slightly freezes when update from background thread

I have a Winform with 4 PictureBox controls, each control will contain a diferent image. The process is:

An event x is raised, the eventargs from this event, contain the filenames of each image (4), an so on (file exists etc..). Then, I have to update the UI.

Commonly I use Invoke:

Invoke((ThreadStart)delegate()
{
    picBig.Image = new Bitmap(strImageBig);
    picLittle1.Image = new Bitmap(saLittle[0]);
    picLittle2.Image = new Bitmap(saLittle[1]);
    picLittle3.Image = new Bitmap(saLittle[2]);
});

// saLittle[] is a string array, contains, filenames: "image1.jpg"

But when this executes, the form freezes for a little time, about 500ms, I know it's a small interval but it's noticeable, then the app continues normally.

I was trying to find out the reason of that 'UI freeze', then, after research, I found BeginInvoke. Now my code looks like this:

BeginInvoke((MethodInvoker)delegate
{
    picBig.Image = new Bitmap(strImageBig);
    picLittle1.Image = new Bitmap(saLittle[0]);
    picLittle2.Image = new Bitmap(saLittle[1]);
    picLittle3.Image = new Bitmap(saLittle[2]);
});

This is a little faster. But the UI is still freezing for 200~300ms.

In the articles I've read, they say that BeginInvoke is a better way than Invoke.

The code is working OK, there is no problem with logic or anything else. I just want to know why this happens. I don't want to leave this doubt unclear. The project is already finished. Hope this be useful for someone else.

Maybe this is not the correct approach. I know there are many ways to update the UI from a background thread, but is there another way to make an update faster ?

Or, do you think, the image loading is the reason? Is there another way to do a faster loading of images?

Thanks in advance.

This is because you're actually loading your images from disk on the UI thread along with setting the contents of the control. Calling the Bitmap constructor with a file path will go to the hard drive and load the image into memory.

Invoke and BeginInvoke will run the delegate that you provide on the thread that the control was created on, which is most likely going to be the UI thread.

...but is there another way to make an update faster?

Load the images on your background thread and, when they're actually loaded, invoke and set the images into the controls.

                    var big = new Bitmap(strImageBig);
                    var little1 = new Bitmap(saLittle[0]);
                    var little2 = new Bitmap(saLittle[1]);
                    var little3 = new Bitmap(saLittle[2]);

                    Invoke((ThreadStart)delegate()
                    {
                        picBig.Image = big;
                        picLittle1.Image = little1;
                        picLittle2.Image = little2;
                        picLittle3.Image = little3;
                    });                    

But when this executes, the form freezes for a little time, about 500ms, I know it's a small interval but it's noticeable, then the app continues normally.

Eventually, the UI thread needs to actually update the images. When the images are generated and updated on the UI thread, this will cause a (short) delay.

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