C# 在多线程中将面板保存为图像
C# Saving Panel as image at Multithread
我在使用 UI 线程将面板保存为图像时没有任何问题,但是当我将此面板保存在 UI 线程以外的另一个线程时,我只有一个黑色矩形:
using (Bitmap bmp = new Bitmap(panel1.Width, panel1.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb))
{
if (panel1.InvokeRequired)
{
panel1.BeginInvoke((MethodInvoker)delegate ()
{
panel1.DrawToBitmap(bmp, new System.Drawing.Rectangle(Point.Empty, bmp.Size));
});
Bitmap bb = bmp.Clone(new System.Drawing.Rectangle(0, 0, 1016, 648), PixelFormat.Format24bppRgb);
bb.Save(@"C:\sample.bmp", ImageFormat.Bmp);
}
else
{
panel1.DrawToBitmap(bmp, new System.Drawing.Rectangle(Point.Empty, bmp.Size));
Bitmap bb = bmp.Clone(new System.Drawing.Rectangle(0, 0, 1016, 648), PixelFormat.Format24bppRgb);
bb.Save(@"C:\sample.bmp", ImageFormat.Bmp);
}
}
这个问题与锁定机制有关?或者我该如何解决这个问题?
提前致谢。
通用答案(有解释):
BeginInvoke
是发送消息'this function should be executed in different thread'然后直接离开在当前线程继续执行的函数。
该函数稍后执行,当目标线程有 'free time' (处理之前发布的消息).
当你需要函数的结果时,使用Invoke
。 Invoke
函数是 'slower',或者更确切地说,它会阻塞当前线程,直到执行的函数完成。 (我最近真的在 C# 中测试过这个,但有可能 Invoke
函数被优先考虑;例如,当你调用 BeginInvoke
并在它之后直接调用 Invoke
到同一个线程,Invoke
中的函数可能会在 BeginInvoke
中的函数之前执行。)
如果您需要在处理下一条指令之前执行该函数,请使用此选项(当您需要调用函数的结果时)。
简单(tl;dr): 当你需要只需要设置一个值时(例如设置编辑框文本),使用BeginInvoke
,但是当你需要结果时(例如从编辑框获取文本)总是使用Invoke
。
在您的情况下,您需要结果 (要绘制的位图) 因此您需要等待函数结束。 (还有其他可能的选择,但在这种情况下,简单的方法是更好的方法。)
我在使用 UI 线程将面板保存为图像时没有任何问题,但是当我将此面板保存在 UI 线程以外的另一个线程时,我只有一个黑色矩形:
using (Bitmap bmp = new Bitmap(panel1.Width, panel1.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb))
{
if (panel1.InvokeRequired)
{
panel1.BeginInvoke((MethodInvoker)delegate ()
{
panel1.DrawToBitmap(bmp, new System.Drawing.Rectangle(Point.Empty, bmp.Size));
});
Bitmap bb = bmp.Clone(new System.Drawing.Rectangle(0, 0, 1016, 648), PixelFormat.Format24bppRgb);
bb.Save(@"C:\sample.bmp", ImageFormat.Bmp);
}
else
{
panel1.DrawToBitmap(bmp, new System.Drawing.Rectangle(Point.Empty, bmp.Size));
Bitmap bb = bmp.Clone(new System.Drawing.Rectangle(0, 0, 1016, 648), PixelFormat.Format24bppRgb);
bb.Save(@"C:\sample.bmp", ImageFormat.Bmp);
}
}
这个问题与锁定机制有关?或者我该如何解决这个问题?
提前致谢。
通用答案(有解释):
BeginInvoke
是发送消息'this function should be executed in different thread'然后直接离开在当前线程继续执行的函数。
该函数稍后执行,当目标线程有 'free time' (处理之前发布的消息).
当你需要函数的结果时,使用Invoke
。 Invoke
函数是 'slower',或者更确切地说,它会阻塞当前线程,直到执行的函数完成。 (我最近真的在 C# 中测试过这个,但有可能 Invoke
函数被优先考虑;例如,当你调用 BeginInvoke
并在它之后直接调用 Invoke
到同一个线程,Invoke
中的函数可能会在 BeginInvoke
中的函数之前执行。)
如果您需要在处理下一条指令之前执行该函数,请使用此选项(当您需要调用函数的结果时)。
简单(tl;dr): 当你需要只需要设置一个值时(例如设置编辑框文本),使用BeginInvoke
,但是当你需要结果时(例如从编辑框获取文本)总是使用Invoke
。
在您的情况下,您需要结果 (要绘制的位图) 因此您需要等待函数结束。 (还有其他可能的选择,但在这种情况下,简单的方法是更好的方法。)