2016-09-16 47 views
0

我試圖在輔助線程上添加自定義控件,但是當我在線程仍在運行時關閉窗口時,出現此異常:C# - 創建新控件的線程仍在運行時的閉合表單

直到已創建窗口 句柄,才能在控件上調用Invoke或BeginInvoke。

我不知道,如果獲得此異常的原因是因爲missused線程或becuse我關閉窗口,而線程仍在運行。

這是我得到的異常的代碼:

panelWall.Invoke(new Action(() => 
      { 
       postControl = new FBPostUserControl(m_LoggedInUser.Name, m_LoggedInUser.ImageNormal, post.CreatedTime); 
       postControl.PostBody = post.Message; 
       postControl.Image = postImage; 
       postControl.Dock = DockStyle.Top; 
       postControl.BringToFront(); 
      })); 

這是我的自定義控制代碼:

public partial class FBPostUserControl : UserControl 
{ 
    private readonly string m_UserName = string.Empty; 
    private readonly Image m_UserProfileImage = null; 
    private readonly DateTime? m_DatePosted = null; 
    private Image m_Image = null; 
    private string m_PostBody = string.Empty; 

    public string UserName 
    { 
     get { return m_UserName; } 
    } 

    public DateTime? DatePosted 
    { 
     get { return m_DatePosted; } 
    } 

    public Image Image 
    { 
     get { return m_Image; } 
     set 
     { 
      if (value == null) 
      { 
       pictureBoxImage.Visible = false; 
      } 
      else 
      { 
       pictureBoxImage.Visible = true; 
       pictureBoxImage.Image = value; 
       updateImageSize(); 
      } 
     } 
    } 

    private void updateImageSize() 
    { 
     if (pictureBoxImage.Image != null) 
     { 
      double ratio = pictureBoxImage.Image.Width/pictureBoxImage.Image.Height; 
      pictureBoxImage.Height = (int)(pictureBoxImage.Width/ratio); 
      pictureBoxImage.SizeMode = PictureBoxSizeMode.Zoom; 
     } 
    } 

    public string PostBody 
    { 
     get { return m_PostBody; } 
     set 
     { 
      if (string.IsNullOrWhiteSpace(value) == false) 
      { 
       labelPostBody.Visible = true; 
       labelPostBody.Text = value; 
      } 
      else 
      { 
       labelPostBody.Visible = false; 
      } 
     } 
    } 

    public Image UserProfileImage 
    { 
     get { return m_UserProfileImage; } 
    } 

    public FBPostUserControl(string i_Name, Image i_ProfileImage, DateTime? i_PostDate) 
    { 
     InitializeComponent(); 
     m_UserName = i_Name; 
     m_UserProfileImage = i_ProfileImage; 
     m_DatePosted = i_PostDate; 

     refreshHeader(); 
    } 

    private void refreshHeader() 
    { 
     pictureBoxUserImage.Image = m_UserProfileImage; 
     labelName.Text = m_UserName; 

     if (labelDate != null) 
     { 
      labelDate.Text = m_DatePosted.ToString(); 
     } 
     else 
     { 
      labelDate.Visible = false; 
     } 
    } 
} 
+1

90%肯定是因爲「我正在關閉窗口,而線程仍在運行。」 –

+0

嘗試關閉具有活動線程的窗口時,我收到了該錯誤。我結束了使用外行人的測試(if(this.FormClosing)return;但是我確定有更多優雅的解決方案在那裏。 –

+2

你的線程繼續使用控件,即使它不再存在。在你允許窗口關閉之前,確保線程停止工作取決於你。http://stackoverflow.com/a/1732361/17034 –

回答

1

首先,我沒有看到你推出在新線程中的操作,因爲Invoke方法只是將操作發送到UI線程中的分派器隊列。

因此,在代碼中沒有真正的多線程,但是在執行操作時,用戶有機會在調度程序隊列中發佈Windows消息來關閉表單,並且可以在下一個Invoke之前處理它。因此,爲避免出現異常,請檢查表單在下一個Invoke之前是否已關閉。順便說一下,我相信在啓動一個新線程來更新圖形元素方面沒有真正的優勢,因爲最後,它們必須在UI線程中更新,而且你只是花時間和資源往返。

如果你有一個很長的圖形操作,並且你的目標是NET Framework 4.5或更高版本,那麼標準的做法是等待一個用於長圖形操作的異步方法,並且在內部等待Task.Yield()用戶有機會取消,關閉窗口等。

基本上,Task.Yield()將方法延續發佈到UI調度器,並且當它返回時,您可以檢查表單並取消長操作,如果表單已關閉:

async Task LongJustGraphicsOperation() 
    { 
     while (true) 
     { 
      //do some work and give a pause 
      await Task.Yield(); 
      if (formIsClosed) break; 
     } 
    } 

Task.Yield()是舊的VB doevents的任務版本。

注意。檢查一個winform是否關閉有點棘手Detect when a form has been closed