我正在尝试使用轨迹条在图像上应用亮度/对比度,因为应用图像需要很长时间。当滚动轨迹栏时,它不平滑,它在我的表格上落后。这是我的代码,这是用于从UI分离工作线程的正确方法(虽然用户体验没有改善)?
private void bright_tbr_ValueChanged(object sender, EventArgs e)
{
brightness = bright_tbr.Value;
contrast = contrast_tbr.Value;
toolTip1.SetToolTip(bright_tbr, brightness.ToString());
Thread thread = new Thread(new ThreadStart(applyBandC));
thread.IsBackground = true;
thread.Start();
}
private void applyBandC()
{
this.Invoke((MethodInvoker)delegate()
{
lock (this)
{
create_pixmap(brightness, contrast, 0, 0, 255, 255);
Bitmap bmp1 = new Bitmap(bmp);
BitmapData data1 = bmp1.LockBits(new Rectangle(0, 0, bmp1.Width, bmp1.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
MapLUT(bmp1.Height, bmp1.Width, data1.Scan0);
bmp1.UnlockBits(data1);
pictureBox2.Image = bmp1;
}
}
);
}
答案 0 :(得分:2)
您的解决方案无法改善用户体验,因为您的整个"多线程"代码包含在this.Invoke
中! Invoke
的目的是在UI线程上执行委托 。将pictureBox2.Image = bmp1;
部分除了传递给this.Invoke
的委托之外的所有处理代码移动,它应该正常工作。
答案 1 :(得分:1)
正如minitech所说,在调用块中工作时,您仍然在阻止UI。您必须在后台准备位图并将其分配给前台。您还必须确保只有一个准备任务同时运行,并且您不希望在等待另一个updateTask时批量更新请求。 TPL可以帮助您,请参阅以下示例代码:
private Task _runningTask;
// only call this method from the UI!
private void UpdateBitmap()
{
int brightness = bright_tbr.Value;
int contrast = contrast_tbr.Value;
// only when not yet running
if (_runningTask == null)
{
var ui = TaskScheduler.FromCurrentSynchronizationContext();
_runningTask = Task.Factory.StartNew<Bitmap>(() =>
{
// prepare
create_pixmap(brightness, contrast, 0, 0, 255, 255);
Bitmap bmp1 = new Bitmap(bmp);
BitmapData data1 = bmp1.LockBits(new Rectangle(0, 0, bmp1.Width, bmp1.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
MapLUT(bmp1.Height, bmp1.Width, data1.Scan0);
bmp1.UnlockBits(data1);
return bmp1;
}).ContinueWith(x =>
{
// assign
pictureBox2.Image = x.Result;
int newBrightness = bright_tbr.Value;
int newContrast = contrast_tbr.Value;
// If the value has changed in the meantime, update again
if (newBrightness != brightness || newContrast != contrast)
{
UpdateBitmap();
}
else
{
_runningTask = null;
}
}, CancellationToken.None, TaskContinuationOptions.None, ui);
}
}
答案 2 :(得分:0)
这是一个Web应用程序或Windows应用程序(更具体地说是WPF)。如果它是基于WPF的应用程序,那么您可以使用Dispatcher类来执行非基于UI的任务,这些任务将在单独的线程上执行,一旦处理结束,结果将被推回到主UI线程。有关Dispatcher的更多信息:http://weblogs.asp.net/pawanmishra/archive/2010/06/06/understanding-dispatcher-in-wpf.aspx