使用Thread.Sleep和pictureBox时,Winform会冻结

时间:2013-09-10 15:23:07

标签: c# multithreading winforms image picturebox

我正在为一个项目工作,其中pictureBox用于逐个显示目录中的图像。

首先,我点击开始按钮。它调用backgroundWorker,它一直运行直到我按下停止按钮。然后在backgroundWorker里面我用500ms的时间间隔调用了一个计时器。它调用了一个eventhandler方法。

在evenhandler方法中首先我从数字目录中取出文件名并在名为“PicBox”的pictureBox中显示并递增然后显示下一个图像。我使用了一个运行整个过程的while循环,直到我点击停止按钮。

问题是它在500ms(定时器间隔)后启动并以高速显示所有图像。我想在流程中显示它们,以便用户无法意识到所有图像都是多个图像的组合,但速度不是这样。

我使用了Thread.Sleep(),但它冻结了winform,我甚至无法点击停止按钮。

PictureBox 代码在这里:

if (_performReceiving)
{
    try
    {
        while (_performReceiving)
        {
            switch (firstNum)
            {
                case 0:
                case 1:
                case 2:
                case 3:
                case 4:
                case 5:
                case 6:
                case 7:
                case 8:
                case 9:
                    PicBox.Image = Image.FromFile(path + "0" + firstNum + ".png");
                    this.PicBox.SizeMode = PictureBoxSizeMode.Zoom;
                    PicBox.Refresh();
                    firstNum++;
                    break;
                default:
                    PicBox.Image = Image.FromFile(path + firstNum + ".png");
                    this.PicBox.SizeMode = PictureBoxSizeMode.Zoom;
                    PicBox.Refresh();
                    firstNum++;
                    break;
            } 
        }
    }
    catch (FileNotFoundException)
    {
        MoveTimer.Stop();
    }
}

有什么建议吗?

编辑:(代码视图)

Form class
{
start_button clicked()
{
   //call backgroundWorker1
}

backgroundWorker1_DoWork()
{
   //create Timer1_handler
   //Timer1.Start()
}

Timer1_handler()
{
   //Process to get firstNames numeric value which passes to switch parameter

   :: This code posted on the main question ::
}
}

1 个答案:

答案 0 :(得分:4)

没有。 No. No. No.。

这都错了。线程和WinForm,你必须弄清楚这些事情。 WinForm在所谓的UI线程上运行。这是你必须创建控件的线程,以及唯一可以访问控件的线程(否则你可能会遇到死锁......或者这些天会出现例外情况)。

其次,后台工作者在doWork中使用后台线程。这不是UI线程,可以用来做很多可爱的处理。当您使用后台工作程序进行更新时(我忘记了确切的API),它将自动编组到UI线程中。我们好吗?

OKAY。现在这是你的问题:System.Windows.Forms.Timer在UI THREAD上运行。这是一个简单的系统,可以按特定的时间间隔在UI线程的队列中插入项目。

因此,在您的示例中,您似乎正在调用后台线程,然后尝试将其工作基于位于UI线程中的计时器。这很疯狂。

使用System.Threading.Timer或者完全丢弃BackgroundWorker,只使用一个线程(UI线程)执行此操作。由于您只需要一次加载1张图像,只要图像是本地图像,您就可以使用它而不会使UI过于无响应。

Form1_Load(object sender, EventArgs e) {
    Timer t = new System.Windows.Forms.Timer();
    t.Interval = 5000;
    t.Tick += SomeEventHandlerThatLoadsAndDisplaysTheNextImage;
    t.Start();
}

或者只是正确使用BackgroundWorker。如果你这样做,你可以添加.sleeps。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        // this is the UI thread
        public Form1()
        {
            InitializeComponent();
            Load += new EventHandler(Form1_Load);
        }

        private BackgroundWorker worker;

        // this is the UI thread
        void Form1_Load(object sender, EventArgs e)
        {
            worker = new BackgroundWorker();
            worker.DoWork += new DoWorkEventHandler(worker_DoWork);
            worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
            worker.RunWorkerAsync();
        }
        // this is the UI thread, the BackgroundWorker did the marshalling for you (Control.Invoke or Control.BeginInvoke)    
        void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            pictureBox1.Image = (Image) e.UserState;
        }
        // this is a background thread, don't touch the controls on this thread we use .ReportProgress (offered by the backgroundWorker) to marshal back to the UI thread.
        void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            while (iNeedToKeepRotatingImages)
            {
                Thread.Sleep(5000);
                var image = LoadAnImage(myState);
                worker.ReportProgress(0, image);
            }
        }
    }
    }