Переопределить элемент списка со списком

#c# #inheritance #combobox #controls #ondraw

#c# #наследование #список со списком #элементы управления #ondraw

Вопрос:

Я изменил цвет подсветки различных элементов управления и планирую внести дополнительные изменения. Поэтому я считаю, что лучше создавать свои собственные элементы управления и повторно использовать их вместо того, чтобы вносить изменения для каждого из них.

Я создал новый пользовательский элемент управления и унаследовал от System.Windows.Forms.ComboBox . Проблема в том, что я не могу найти способ переопределить onDraw , как я бы для onClick .

Итак, как бы я пошел и переопределил его? Вот код, который я использовал для каждого управляющего onDraw события

 public void comboMasterUsers_DrawItem(object sender, DrawItemEventArgs e)
    {
        e.DrawBackground();

        Graphics g = e.Graphics;
        Brush brush = ((e.State amp; DrawItemState.Selected) == DrawItemState.Selected) ?
                      Brushes.LightSeaGreen : new SolidBrush(e.BackColor);

        g.FillRectangle(brush, e.Bounds);
        e.Graphics.DrawString(comboMasterUsers.Items[e.Index].ToString(), e.Font,
                 new SolidBrush(e.ForeColor), e.Bounds, StringFormat.GenericDefault);

        e.DrawFocusRectangle();
    }
  

Спасибо!

Ответ №1:

Вот так:

 public class myCombo : ComboBox
{
    // expose properties as needed
    public Color SelectedBackColor{ get; set; }

    // constructor
    public myCombo()
    {
        DrawItem  = new DrawItemEventHandler(DrawCustomMenuItem);
        DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed;
        SelectedBackColor= Color.LightSeaGreen;
    }

    protected  void DrawCustomMenuItem(object sender, DrawItemEventArgs e)
    {
        e.DrawBackground();
         // a dropdownlist may initially have no item selected, so skip the highlighting:
        if (e.Index >= 0) 
        {  
          Graphics g = e.Graphics;
          Brush brush = ((e.State amp; DrawItemState.Selected) == DrawItemState.Selected) ?
                         new SolidBrush(SelectedBackColor) : new SolidBrush(e.BackColor);
          Brush tBrush = new SolidBrush(e.ForeColor);

          g.FillRectangle(brush, e.Bounds);
          e.Graphics.DrawString(this.Items[e.Index].ToString(), e.Font,
                     tBrush, e.Bounds, StringFormat.GenericDefault);
          brush.Dispose();
          tBrush.Dispose();
        }
        e.DrawFocusRectangle();
    }
}
  

Вы можете рассмотреть возможность предоставления дополнительных свойств по мере расширения вашей пользовательской базы, чтобы вы могли изменять их для каждого экземпляра, когда захотите..

Также не забудьте удалить созданные вами объекты GDI, такие как кисти и ручки!

Редактировать: только что заметил, что BackColor это скроет исходное свойство. Изменил его на SelectedBackColor , который на самом деле говорит, что это такое!

Редактировать 2: как отметил Саймон в комментариях, существует HasFlag метод, и поэтому, начиная с .Net 4.0, можно также написать:

       Brush brush = ((e.State.HasFlag(DrawItemState.Selected) ?
  

что немного понятнее и короче.

Редактировать 3: на самом деле для рисования на элементах управления TextRenderer.DrawText рекомендуется использовать graphics.DrawString ..

Комментарии:

1. Спасибо, это работает. Но есть одна проблема. Когда я меняю выпадающий список на выпадающий список, появляется ошибка: InvalidArgument =значение -1 недопустимо для индекса

2. посмотрите на мое небольшое исправление в tBrush! Объекты GDI имеют отвратительную тенденцию к тихой утечке..

3. И еще одно небольшое исправление 😉 Я не заметил предупреждения, но теперь все выглядит нормально..

4. Короче говоря, длинная и грустная история: кисти, ручки и растровые изображения являются особенными. Это не обычные объекты c #, которые собирает GC; они хранятся отдельно, и вы несете ответственность за их удаление. Наследие GDI из 90-х годов..

5. о, я понимаю.. Спасибо за информацию!

Ответ №2:

Спасибо за этот полезный пост. Я внес одно небольшое улучшение, которое другие могут счесть полезным.

Когда для свойства ComboBox установлено свойство DisplayMember для доступа к определенному свойству отображаемых элементов, toString() может не выдавать ожидаемый текст. Исправление для этого заключается в использовании:

     GetItemText(Items[e.Index])
  

для получения требуемого текста в вызове DrawString() .

Ответ №3:

Это будет полезно для тех, кто ищет VB.net

Открытый класс myCombo

 Inherits ComboBox

Public Property SelectedBackColor As Color

Public Sub New()
    AddHandler DrawItem, New DrawItemEventHandler(AddressOf DrawCustomMenuItem)
    DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed
    DropDownStyle = ComboBoxStyle.DropDownList
End Sub

Protected Sub DrawCustomMenuItem(ByVal sender As Object, ByVal e As DrawItemEventArgs)
    If e.Index < 0 Then
        Return
    End If
    e.Graphics.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAlias
    Dim Cb As ComboBox = TryCast(sender, ComboBox)
    If (e.State And DrawItemState.Selected) = DrawItemState.Selected Then
        e.Graphics.FillRectangle(New SolidBrush(Color.OrangeRed), e.Bounds) ' selected item background color
    Else
        e.Graphics.FillRectangle(New SolidBrush(Color.White), e.Bounds) ' background color
    End If
    e.Graphics.DrawString(Cb.Items(e.Index).ToString(), e.Font, New SolidBrush(e.ForeColor),
                          New Point(e.Bounds.X, e.Bounds.Y), StringFormat.GenericTypographic)
End Sub
  

Конечный класс