WIndows表单线程 - 等待表单完成渲染

时间:2017-03-07 10:20:12

标签: c# multithreading winforms

我知道有多个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[] { });
}

以下是我使用extensions方法生成位图的方法:

Bitmap image = new Bitmap(newPBWidth, newPBHeight);
form.SynchronizedInvoke(() => form.DrawToBitmap(image, new Rectangle(new Point(0, 0), image.Size)));

任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:2)

以下就像炸弹一样。根据我的经验和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
        }
    }
}