在 Windows Forms 開發中,若需在屬性視窗編輯集合型別屬性(如過濾條件清單),預設的 CollectionEditor 雖能基本運作,但常面臨「僅產生區域變數、無法對應全域變數」、「繼承 Control 導致刪除控制項時變數不隨之移除」等痛點。本文以 TypedFilter 為例,示範如何實作可設計時序列化、支援自訂編輯器的集合屬性,並探討常見坑點與改進方向。
關鍵在於三個屬性標記:
[Category("BusinessObjectControl")]:分類顯示;[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]:告知設計器序列化集合內容而非參考;[Editor(typeof(FilterCollectionEditor), typeof(UITypeEditor))]:指定自訂集合編輯器。class 動態 : Label
{
private List<TypedFilter> _filters = new List<TypedFilter>();
[Category("BusinessObjectControl")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
[Editor(typeof(FilterCollectionEditor), typeof(UITypeEditor))]
public List<TypedFilter> Filters
{
get { return _filters; }
set { _filters = value; }
}
}
public class TypedFilter
{
private string _dataPropertyName = "Name";
public string DataPropertyName { get { return _dataPropertyName; } set { _dataPropertyName = value; } }
private int _value = 0;
public int Value { get { return _value; } set { _value = value; } }
public override string ToString() => _dataPropertyName + " = " + _value.ToString();
}
class FilterCollectionEditor : CollectionEditor
{
public FilterCollectionEditor(Type type) : base(type) { }
}
預設 CollectionEditor 建立項目時呼叫 CreateInstance,若型別無無參建構子或未正確初始化,設計器將只在編輯器內建立暫時物件,不會寫入表單程式碼。解決方式:
TypedFilter)有 public 無參建構子;FilterCollectionEditor 覆寫 CreateInstance,回傳正確初始化的實例;Load 事件手動同步,或實作 IComponent 讓設計器管理生命週期。若 TypedFilter : Control,設計器會將其視為元件並加入容器,刪除時僅移除視覺樹,不會清除集合參考。建議:
Component 並搭配 IComponent、ISite 管理。ICustomTypeDescriptor 或 TypeConverter 自訂屬性網格顯示;CollectionEditor 的 GetItems、SetItems 掌控集合同步邏輯;PropertyTab 提供專屬設計時介面。完善的設計時體驗需從「序列化機制」、「元件生命週期」、「編輯器擴充」三面著手,以上代碼為起點,實務中常需依專案需求深度客製化。