上篇 [C#.NET][Winform] 製作不同顏色相間隔的 ListBox 在Winform裡已經實作了DrawItem事件,我們可以再進一步將這個功能打包成屬於自己的控制項
首先開啟Control Library專案
繼承ListBox
加入要重繪的屬性,並加入適當的 Attribute,在這裡主要是處理屬性的預設值
private Color _RowColor1 = Color.CornflowerBlue; /// <summary> /// 第一列的顏色 /// </summary> [DefaultValue(typeof(Color), "CornflowerBlue")] [Browsable(true), Category("重繪設定"), Description("第一列的顏色")] public Color RowColor1 { get { return _RowColor1; } set { _RowColor1 = value; } } private Color _RowColor2 = Color.PaleGreen; /// <summary> /// 第二列的顏色 /// </summary> [DefaultValue(typeof(Color), "PaleGreen")] [Browsable(true), Category("重繪設定"), Description("第二列的顏色")] public Color RowColor2 { get { return _RowColor2; } set { _RowColor2 = value; } } private Color _RowGradualColor1 = Color.Thistle; /// <summary> /// 第一列的漸層色 /// </summary> [DefaultValue(typeof(Color), "Thistle")] [Browsable(true), Category("重繪設定"), Description("第一列的漸層色")] public Color RowGradualColor1 { get { return _RowGradualColor1; } set { _RowGradualColor1 = value; } } private Color _RowGradualColor2 = Color.DarkKhaki; /// <summary> /// 第二列的漸層色 /// </summary> [DefaultValue(typeof(Color), "DarkKhaki")] [Browsable(true), Category("重繪設定"), Description("第二列的漸層色")] public Color RowGradualColor2 { get { return _RowGradualColor2; } set { _RowGradualColor2 = value; } } private Color _SelectRowColor = Color.White; [DefaultValue(typeof(Color), "White")] [Browsable(true), Category("重繪設定"), Description("選擇列的顏色")] public Color SelectRowColor { get { return _SelectRowColor; } set { _SelectRowColor = value; } } private bool _IsGradualColor = true; /// <summary> /// 是否使用漸層色 /// </summary> [Browsable(true), Category("重繪設定"), Description("是否使用漸層色")] [DefaultValue(true)] public bool IsGradualColor { get { return _IsGradualColor; } set { _IsGradualColor = value; this.Invalidate(); } } static string[] testData = new string[] { "1", "2", "gy", "余小章" }; private bool _IsUseDefauleData = false; [DefaultValue(false)] [Browsable(true), Category("重繪設定"), Description("是否使用預設資料")] public bool IsUseDefauleData { get { if (_IsUseDefauleData) this.DataSource = testData; else this.DataSource = null; return _IsUseDefauleData; } set { _IsUseDefauleData = value; if (value) this.DataSource = testData; else this.DataSource = null; } }
因為我在Library裡有使用DataSource、Items兩個屬性,所以會讓VS自動產生出程式碼,會導致一些錯誤發生
所以我用[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]重新定義這兩個屬性,不讓VS自動產生程式碼
[Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public new object DataSource { get { return base.DataSource; } set { base.DataSource = value; } } [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public new ListBox.ObjectCollection Items { get { return base.Items; } }
我想要變更預設值所以再重新定義
[Browsable(true)] [DefaultValue(typeof(DrawMode), "OwnerDrawFixed")] public new DrawMode DrawMode { get { return base.DrawMode; } set { base.DrawMode = value; } }
在建構子裡設定DrawMode 屬性以及註冊DrawItem事件
public ListBoxControl() { InitializeComponent(); this.DrawMode = DrawMode.OwnerDrawFixed; this.DrawItem += new DrawItemEventHandler(ListBoxControl_DrawItem); } void ListBoxControl_DrawItem(object sender, DrawItemEventArgs e) { ListBox list = (ListBox)sender; if (list.Items.Count <= 0) return; //定義框的大小 Rectangle rec = new Rectangle(0, 0, list.Width, list.Height); //定義一般筆刷 SolidBrush brushRow1 = new SolidBrush(this.RowColor1); SolidBrush brushRow2 = new SolidBrush(this.RowColor2); //定義漸層筆刷 LinearGradientBrush linBrushRow1 = new LinearGradientBrush(rec, this.RowColor1, this.RowGradualColor1, LinearGradientMode.BackwardDiagonal); LinearGradientBrush linBrushRow2 = new LinearGradientBrush(rec, this.RowColor2, this.RowGradualColor2, LinearGradientMode.BackwardDiagonal); //選筆刷 Brush brush; if (this.IsGradualColor) { if (e.Index % 2 == 0) brush = linBrushRow1; else brush = linBrushRow2; } else { if (e.Index % 2 == 0) brush = brushRow1; else brush = brushRow2; } //畫框 e.Graphics.FillRectangle(brush, e.Bounds); bool selected = ((e.State & DrawItemState.Selected) == DrawItemState.Selected) ? true : false; if (selected) { e.Graphics.FillRectangle(new SolidBrush(this.SelectRowColor), e.Bounds); } //畫字 e.Graphics.DrawString(list.Items[e.Index].ToString(), this.Font, Brushes.Black, e.Bounds); //畫焦點框 e.DrawFocusRectangle(); }
這樣一來我們所開發的控制項已經完成了,接下來就測試這控制項的效果,在原本方案裡再新增一個Winform的Demo專案,按下Shift+Ctrl+B建置方案
在Demo專案裡,便可以看到我們所開發的控制項,把它拖拉到Winform裡,便可以使用了
後記:DrawListBoxControl.zip
開發控制項要注意的觸發事件非常的多,跟我們寫一般的程式有差益,要注意控制項第一次匯製時VS所產生的程式碼,有沒有錯誤,這牽扯到控制項的生命週期,這必須要多做一些測試,可以先把會產生錯誤的部份隱藏起來。