開發複雜 WinForms 控件(如 OpenGLControl)時,某些屬性(BitDepth、FrameRate、RenderContextType)必須在 Size 之前設定,否則底層資源建立失敗。但設計器產生的 InitializeComponent 代碼順序不可控:
this.openGLControl1.BitDepth = 32;
this.openGLControl1.DrawRenderTime = true;
this.openGLControl1.FrameRate = 29.41176F;
this.openGLControl1.Location = new Point(12, 12);
this.openGLControl1.Name = "openGLControl1";
this.openGLControl1.RenderContextType = RenderContextType.NativeWindow;
this.openGLControl1.Size = new Size(768, 379); // 最後才設定 Size
this.openGLControl1.TabIndex = 0;
當控件實作 System.ComponentModel.ISupportInitialize,設計器會自動在 InitializeComponent 中包裹 BeginInit()/EndInit():
private void InitializeComponent() {
// ...
this.openGLControl1 = new SharpGL.OpenGLControl();
((ISupportInitialize)(this.openGLControl1)).BeginInit();
this.SuspendLayout();
// ... 所有屬性設定代碼 ...
((ISupportInitialize)(this.openGLControl1)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
public class OpenGLControl : Control, ISupportInitialize {
private bool _initializing = false;
public int BitDepth { get; set; }
public float FrameRate { get; set; }
public RenderContextType RenderContextType { get; set; }
// ... 其他相依屬性
public void BeginInit() {
_initializing = true;
}
public void EndInit() {
_initializing = false;
// 此處所有屬性已設定完成,安全建立底層資源
RecreateRenderContext(); // 依賴 BitDepth、Size 等
}
protected override void OnSizeChanged(EventArgs e) {
if (!_initializing) RecreateRenderContext();
base.OnSizeChanged(e);
}
}
BeginInit:標記進入批次初始化階段,暫停副作用邏輯(如資源建立、事件觸發)。EndInit:標記初始化結束,統一執行依賴多個屬性的初始化邏輯,這是最早可安全執行的時機。ISupportInitialize,即自動生成包裹代碼,無需額外設定。DataSource 都觸發查詢)。