#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
Конечный класс