簡體   English   中英

清除容器的Controls屬性並確保正確處置控件的最安全方法是什么?

[英]What is the safest way to clear a container's Controls property and make sure the controls are properly disposed?

在WinForms應用程序中,我有多個實例,在其中我將一個控件添加到容器中以響應用戶操作( panel.Controls.Add(new CustomControl(...)) ),然后稍后清除面板( panel.Controls.Clear() )並重新使用它。

在生產中,該應用偶爾會引發與GDI錯誤或無法加載ImageList有關的異常。 這通常發生在資源有限的計算機上,以及一天中大量使用該應用程序的用戶。 很明顯,我有一個GDI句柄泄漏,應該處理從容器中清除的控件,但是我發現的任何解釋都不清楚應在何時何處放置控件。

我應該在清理容器后立即處置兒童控件嗎? 就像是:

var controls = new List<Control>(_panel.Controls.Cast<Control>());
_panel.Controls.Clear();
foreach (var c in controls) c.Dispose();

還是應該在列表中跟蹤控件並在容器的Dispose()方法中調用dispose? 如:

List<Control> _controlsToDispose = new List<Control>();
void ClearControls()
{
    _controlsToDispose.AddRange(_panel.Controls.Cast<Control>());
    _panel.Controls.Clear();
}
void Dispose()
{
    ...
    foreach (var c in _controlsToDispose) c.Dispose();
}

選項2引入了另一個您需要清除的列表,這些列表將占用更多的內存。 我希望選項1帶有圍繞您提到的代碼的try catch。

在(以某種有效的方式)糾正了我的應用沒有處理清除的控件的所有情況后,我可以提出幾點:

  • 有時我會預先構建一個控件列表,例如,存儲在ListViewItemTreeViewItem的集合的Tag屬性中。 它們不應該被清除,但是整個列表應該被迭代,並在父級的Dispose()方法中調用((Control)item.Tag).Dispose()
  • 如果不再使用該控件(當我即時創建它時會發生這種情況),則應在從容器中清除該控件時將其丟棄。
  • 即時清除和添加控件時,您需要考慮控件的生命周期,以確定是否要立即處理它們,將其推遲到處理父對象之前還是不必擔心。
  • 我遇到的情況是,我刪除了一個控件以顯示“正在加載...”消息,然后響應於線程完成而將該控件放回原處。 刪除控件時,我添加了一個處置該控件的調用,這在嘗試再次添加它時導致錯誤。 由於存在線程問題,因此調試起來並不容易。 關鍵是生命周期可以依賴於UI線程以外的線程。 適當的情況是在顯示表單后大約20秒,因此至少控件仍然存在。 在弱事件發生的情況下,管理可能被線程仍希望引用的控件破壞的情況。

在管理控制生命周期和處置方面,我找不到任何最佳實踐或建議。 我猜規則是,如果一個控件沒有結束,那么它的生命就嵌套在一個被處置的控件上,無論何時不再使用它,都必須手動處置它,或者在父控件的Dispose()最晚的方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM