1. 程式人生 > >繫結資料來源時組合框ComboBox.DrawItem的事件處理方法

繫結資料來源時組合框ComboBox.DrawItem的事件處理方法

在一些窗體應用程式中,常常需要重寫組合框控制元件ComboBox的DrawItem事件處理方法,例如:顏色選擇組合框、帶圖示的組合框、調整項間距的組合框,等等。基本步驟如下:

  1. 設定ComboBox.DrawMode為OwnerDrawFixed或OwnerDrawVariable;
  2. 計算新的下拉框高度值ComboBox.DropDownHeight,或許還要計算寬度ComBoBox.DropDownWidth;
  3. 重寫ComboBox.DrawItem和ComboBox.MeasureItem等事件處理方法。

下面是兩個主要事件的程式碼舉例:

private void comboBox1_DrawItem(object sender, DrawItemEventArgs e)
{
    if (e.Index == -1) { return; } // 未下拉的當前框文字, 不需要重繪製

    ComboBox thisComboBox = sender as ComboBox;  // 當前組合框
    string itemText = Convert.ToString(thisComboBox.Items[e.Index]);  // 由DrawString()處理null情況

    e.DrawBackground();  // 繪製背景
    using (SolidBrush brush = new SolidBrush(e.ForeColor))
    {
        e.Graphics.DrawString(itemText, e.Font, brush, e.Bounds, StringFormat.GenericDefault);  // 繪製文字
    }
    e.DrawFocusRectangle();  // 繪製聚焦框
}

private void comboBox1_MeasureItem(object sender, MeasureItemEventArgs e)
{
    if (e.Index % 2 == 0)
    {
        e.ItemHeight = 15;  // 偶數項的項高
    }
    else
    {
        e.ItemHeight = 25;  // 奇數項的項高
    }
}

需要指出如下幾點:

  • 如果設定了ComboBox.ItemHeight的值,且每個項高度相同,則可以省略事件方法ComboBox.MeasureItem;
  • ComboBox.DrawMode為OwnerDrawFixed時,ComboBox.MeasureItem事件失效,此時取ComboBox.ItemHeight的值;
  • ComboBox.DrawMode為OwnerDrawVariable時,可以在ComboBox.MeasureItem改變指定項的高度;
  • 如果項高固定為height,則下拉框高 ComboBox.DropDownHeight = ComboBox.MaxDropDownItems * height。

當ComboBox繫結到資料來源,且該資料來源實現了IBindingList與IBindingListView介面時(例如:DataTable、BindingSource),ComboBox.Items即是當前的資料來源,通過ComboBox.Items[e.Index]獲取的則是當前資料來源的行物件DataRowView。此時,將根據DataRowView和ComboBox.DisplayMember屬性確定具體的列屬性值,獲取到待繪製的文字。參考如下程式碼:

private void comboBox1_DrawItem(object sender, DrawItemEventArgs e)
{
    if (e.Index == -1) { return; }  // 未下拉的當前框文字, 不需要重繪製

    ComboBox thisComboBox = sender as ComboBox;
    DataRowView row = thisComboBox.Items[e.Index] as DataRowView;  // 取序號為e.Index的行物件
    string itemText = Convert.ToString(row[thisComboBox.DisplayMember]);  // 由DrawString()方法處理null
    
    e.DrawBackground();  // 繪製背景
    using (SolidBrush brush = new SolidBrush(e.ForeColor))
    {
        e.Graphics.DrawString(value, e.Font, brush, e.Bounds, StringFormat.GenericDefault);  // 繪製文字
    }
    e.DrawFocusRectangle();  // 繪製聚焦框
} 

實際應用時注意如下幾點:

  • BindingSource與DataTable.DefaultView屬性均實現了IBindingList與IBindingListView介面;
  • 特別地,ComboBox繫結到DataTable,實質上是繫結到DataTable物件的DefaultView屬性;
  • 獲取的待繪製文字可以是DataRowView的兩列或多列的屬性值組合,從而繪製出所謂的多列ComboBox。

為便於驗證測試,下面給出一個完整的窗體程式程式碼: