WIndows窗体线程 - 等待窗体完成渲染
问题描述:
我知道有多个Windows窗体线程问题。我浏览过很多,但似乎无法找到我要找的内容。WIndows窗体线程 - 等待窗体完成渲染
我有一个主窗体。从这个表单代码被执行来创建一系列新的表单,这些表单将被用于拍摄图像快照,然后将其添加到PDF文档中。
我在这个阶段的问题是新的表单没有足够的时间来完成PDF文档创建之前的渲染。因此,我需要在不同的线程上执行表单,等待它们完成呈现(最重要的是等待几秒钟),然后继续生成PDF文档。
这是很多代码,所以我将尝试解释我正在尝试使用新的(简化)代码做什么。
public static void CreatePDFDocument()
{
List<Form> formsList = CreateForms(collectionIDs);
CreatePDF(formsList);
}
public static List<Form> CreateForms(List<string> collectionIDs)
{
List<Form> formsList = new List<Form>();
foreach (string id in collectionIDs)
{
Form chartForm;
chartForm = new Form();
chartForm.TopMost = false;
chartForm.Height = 1024;
chartForm.Width = 1400;
chartForm.StartPosition = FormStartPosition.CenterScreen;
chartForm.AutoScroll = true;
//CODE TO ADD CHART CONTROLS TO FORM
//...
//...
//...
formsList.Add(chartForm);
}
return (formsList);
}
public static void CreatePDF(List<Form> formsList)
{
foreach (var form in formsList)
{
foreach (var control in form.Controls)
{
//CODE TO CREATE BITMAP AND ADD IT TO PDF DOCUMENT
//ACCESSING THE CONTROL HERE NEED TO BE THREAD SAFE
}
}
}
上面的代码在渲染完成之前生成PDF文档。因此我在PDF文档中得到黑色图像。我需要在一个单独的线程上运行它们,等待一切完成,然后继续创建新的PDF文档(以线程安全的方式访问表单)。
我已经尝试了很多不同的线程代码,但是当窗体本身使用ShowDialog()函数或窗体关闭完成后,窗体要么停留在线程中,然后我无法再访问它们。
要访问一个线程安全的方式形式,我使用的扩展方法:
public static void SynchronizedInvoke(this ISynchronizeInvoke sync, Action action)
{
// If the invoke is not required, then invoke here and get out.
if (!sync.InvokeRequired)
{
// Execute action.
action();
// Get out.
return;
}
// Marshal to the required context.
sync.Invoke(action, new object[] { });
}
这是我如何我生成与扩展方法的位图:
Bitmap image = new Bitmap(newPBWidth, newPBHeight);
form.SynchronizedInvoke(() => form.DrawToBitmap(image, new Rectangle(new Point(0, 0), image.Size)));
任何帮助将不胜感激!
答
下面的工作就像一颗炸弹。根据我的经验和Nico给出的建议构建它
public static List<Thread> formsThreadList = new List<Thread>();
public static List<string> formsFinishedLoading = new List<string>();
public static List<Form> formsList = new List<Form>();
public static void CreatePDFDocument()
{
formsList = CreateForms(collectionIDs);
Thread thread = new Thread(CreatePDFThreadFunction)
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
public static void CreatePDFThreadFunction()
{
while (formsFinishedLoading.Count() != formsThreadList.Count()) { Thread.Sleep(100); }
CreatePDF(formsList, collectionList, path, "");
}
public static void form_shown(object sender, EventArgs e)
{
Form frm = (Form)sender;
frm.Refresh();
formsFinishedLoading.Add(frm.Name);
}
public static List<Form> CreateForms(List<string> collectionIDs)
{
List<Form> formsList = new List<Form>();
foreach (string id in collectionIDs)
{
Form chartForm;
chartForm = new Form();
chartForm.TopMost = false;
chartForm.Height = 1024;
chartForm.Width = 1400;
chartForm.StartPosition = FormStartPosition.CenterScreen;
chartForm.AutoScroll = true;
chartForm.Shown += new EventHandler(form_shown);
//CODE TO ADD CHART CONTROLS TO FORM
//...
//...
//...
formsList.Add(chartForm);
}
return (formsList);
}
public static void CreatePDF(List<Form> formsList)
{
foreach (var form in formsList)
{
foreach (var control in form.Controls)
{
//CODE TO CREATE BITMAP AND ADD IT TO PDF DOCUMENT
//ACCESSING THE CONTROL HERE NEED TO BE THREAD SAFE
}
}
}
http://*.com/questions/218732/how-do-i-execute-code-after-a-form-has-loaded 。使用给定的Event'Shown'来等待表单完成 – Nico
此事件在表单上的所有控件都完成呈现时触发吗? – user1035217
当窗体第一次显示时调用'Shown'(https://msdn.microsoft.com/en-us/library/system.windows.forms.form.shown(v=vs.110).aspx)渲染是/应该完成的。最小化和重新开放不会引发这个事件作为旁注。 – Nico