問題通常我們在設置子控制項的一些與外觀、佈局有關的屬性時,比如Size、Location、Anchor或Dock等,會激發子控制項的 Layout事件,並可能會引起視窗重繪。當子控制項較多時,如果頻繁設置上述屬性(例如在窗體的初始化代碼中),多個子控制項的Layout事件會引起視窗重繪效率問題,比如閃爍。特 ...
問題
通常我們在設置子控制項的一些與外觀、佈局有關的屬性時,比如Size、Location、Anchor或Dock等,會激發子控制項的 Layout事件,並可能會引起視窗重繪。當子控制項較多時,如果頻繁設置上述屬性(例如在窗體的初始化代碼中),多個子控制項的Layout事件會引起視窗重繪效率問題,比如閃爍。特別地,通過動態載入插件生成的UI對象特別多時,閃爍的情況就特別嚴重。那麼怎麼解決這個問題呢?
解決
這時,通過使用控制項的SuspendLayout方法,可以將控制項的佈局暫時掛起,其後的代碼中將會把子控制項的Layout事件暫時掛起,只是把相應屬性的值設置為新值,並不激發Layout事件,待調用ResumeLayout方法後,再一起使子控制項的Layout事件生效。當需要立即執行佈局事件時,可以直接調用PerformLayout方法。
Q&A
1.什麼時候會觸發Control.Layout事件?
(1)當控制項本身的大小(Size)改變時會觸發本控制項的Layout事件
(2)當其子控制項的位置(Location)改變時會觸發它的Layout事件。
(3)添加或刪除子控制項也會引起它的Layout事件。
(4)發生其他可影響控制項佈局的變化時會引起它的Layout事件。
2.SuspendLayout方法作何用?
在添加或移除子控制項,控制項的邊界改變,以及在發生其他可影響控制項佈局的變化時,會發生 Layout 事件。可以使用SuspendLayout掛起佈局,可以在控制項上執行多個操作,而無需為每次更改執行一次佈局操作。也就是說,有了這個語句之後,緊接著下麵的添加刪除子控制項,或者改變子控制項的大小、位置及改變它自身的位置的這些操作,都不在引發Layout事件了。
3. ResumeLayout方法作何用?
通過ResumeLayout方法可以取消掛起的佈局。以後佈局改變的時候就會引發Layout事件了。
4. PerformLayout方法作何用?
ResumeLayout方法可以取消掛起的佈局,使以後的佈局均有效,但是並不能保證佈局的立即執行。如果要使佈局立即執行(即立即觸發Layout事件),可以調用PerformLayout方法強制佈局,強制控制項將佈局邏輯應用於自身及其子控制項。
C#窗體設計器生成的代碼
/// <summary>
/// 設計器支持所需的方法 - 不要
/// 使用代碼編輯器修改此方法的內容。
/// </summary>
private void InitializeComponent()
{
this.panel1.SuspendLayout();
this.SuspendLayout();
......//這裡設置控制項屬性
......//這裡設置控制項屬性
this.panel1.ResumeLayout(false);
this.ResumeLayout(false);
}
從代碼中可以看出,窗體設計器自動生成代碼時也是在大規模改變控制項屬性(這些屬性會決定控制項佈局)的時候使用到了控制項的PerformLayout與ResumeLayout方法來提高重繪效率,減少閃爍。