我正在为一个项目工作,其中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 ::
}
}
答案 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);
}
}
}
}