2017-03-07 126 views
-2

我知道有多個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))); 

任何幫助將不勝感激!

+1

http://stackoverflow.com/questions/218732/how-do-i-execute-code-after-a-form-has-loaded 。使用給定的Event'Shown'來等待表單完成 – Nico

+0

此事件在表單上的所有控件都完成呈現時觸發嗎? – user1035217

+0

當窗體第一次顯示時調用'Shown'(https://msdn.microsoft.com/en-us/library/system.windows.forms.form.shown(v=vs.110).aspx)渲染是/應該完成的。最小化和重新開放不會引發這個事件作爲旁註。 – Nico

回答

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 
     } 
    } 
}