Пишем свой ListBox

Платформа .NET Framework предлагает достаточно большой выбор элементов управления. Но иногда разработчику бывает недостаточно предлагаемого набора. Благо, .NET позволяет перенастраивать элементы под себя. Этим мы и займёмся сейчас. Создадим свой ListBox, элементы которого будут в виде кнопок.

Приступим.
Создадим в Visual Studio новое Windows Forms приложение. После этого в дерево проектов добавляем файл с классом ButtonListBox:

sealed class ButtonListBox : ListBox
{
    ...
}

Как видно из кода, свой класс мы унаследовали от класса ListBox и установили модификатор sealed, поскольку этот класс мы не будем проектировать как родителя для других классов.

Объявим дополнительные переменные:

//вспомогательные переменные для отрисовки
int x, y, itemWidth, itemHeight;

public ButtonListBox()
{
    DrawMode = DrawMode.OwnerDrawVariable;
}

Свойство DrawMode мы установили OwnerDrawVariable для того, чтобы можно было самим рисовать на компоненте.

При наследовании нашего класса от ListBox мы получили холст для рисования. Нам нужно будет перегрузить три метода:

  • OnDrawItem – вызывается при прорисовке каждого элемента списка
  • OnSizeChanged – при изменении размера компонента
  • OnMeasureItem – при измерении высоты и ширины элемента

Начнем с самого большого и сложного метода:

protected override void OnDrawItem(DrawItemEventArgs e)
{
    //e - элемент, с которым мы дальше и работаем
    //если текущего элемента нет или в списке нет вообще элементов, выходим из метода
    if (e.Index <= -1 || this.Items.Count == 0)
        return;

    //получаем текст элемента
    string s = Items[e.Index].ToString();

    //формат строки для рисования текста
    StringFormat sf = new StringFormat();
    //формат выставляем по центру
    sf.Alignment = StringAlignment.Near;
    sf.FormatFlags = StringFormatFlags.NoWrap;

    //создаем обычную кисть с заданным цветом
    Brush textBrush = new SolidBrush(Color.Black);
    Brush bgBrush = new SolidBrush(SystemColors.Control);

    //определяем координаты элемента в списке
    //т.к. для каждого элемента они разные
    x = e.Bounds.X;
    y = e.Bounds.Y;

    //также определяем его ширину и высоту
    itemWidth = e.Bounds.Width;
    itemHeight = e.Bounds.Height;

    if ((e.State & DrawItemState.Focus) == DrawItemState.Focus)//если активный
    {
        //рисуем выбранный элемент
        e.Graphics.FillRectangle(new SolidBrush(SystemColors.Info), x + 2, y + 2,
            itemWidth - 4, itemHeight - 4);

        //рисуем текст элемента
        e.Graphics.DrawString(s, Font, new SolidBrush(Color.Black),
            new Rectangle(5, y + 10, itemWidth, 16), sf);

        //рисуем границы элемента
        e.Graphics.DrawLine(new Pen(Color.White), x + 1, y + 1, itemWidth, y + 1);
        e.Graphics.DrawLine(new Pen(Color.White), x + 1, y + 1, x + 1, y + itemHeight - 1);
        e.Graphics.DrawLine(new Pen(SystemColors.ControlDarkDark), itemWidth - 1, y + 1, itemWidth - 1, y + itemHeight - 1);
        e.Graphics.DrawLine(new Pen(Color.Gray), itemWidth - 2, y + 2, itemWidth - 2, y + itemHeight - 2);
        e.Graphics.DrawLine(new Pen(SystemColors.ControlDarkDark), x + 1, y + itemHeight - 1, itemWidth - 1, y + itemHeight - 1);
        e.Graphics.DrawLine(new Pen(Color.Gray), x + 2, y + itemHeight - 2, itemWidth - 2, y + itemHeight - 2);
    }
    else // если не активный
    {
        //заполняем прямоугольник выбранным цветом
        e.Graphics.FillRectangle(bgBrush, x, y, itemWidth, itemHeight + 1);

        //пишем текст
        e.Graphics.DrawString(s, Font, textBrush,
            new Rectangle(5, y + 10, itemWidth, 16), sf);

        //рисуем границы элемента
        e.Graphics.DrawLine(new Pen(Color.White), x + 1, y + 1, itemWidth, y + 1);
        e.Graphics.DrawLine(new Pen(Color.White), x + 1, y + 1, x + 1, y + itemHeight - 1);
        e.Graphics.DrawLine(new Pen(SystemColors.ControlDarkDark), itemWidth - 1, y + 1, itemWidth - 1, y + itemHeight - 1);
        e.Graphics.DrawLine(new Pen(Color.Gray), itemWidth - 2, y + 2, itemWidth - 2, y + itemHeight - 2);
        e.Graphics.DrawLine(new Pen(SystemColors.ControlDarkDark), x + 1, y + itemHeight - 1, itemWidth - 1, y + itemHeight - 1);
        e.Graphics.DrawLine(new Pen(Color.Gray), x + 2, y + itemHeight - 2, itemWidth - 2, y + itemHeight - 2);
    }
}

Осталось два небольшх метода:

//после изменения размера
protected override void OnSizeChanged(EventArgs e)
{
    //вызываем обновление компонента
    Refresh();
    base.OnSizeChanged(e);
}
protected override void OnMeasureItem(MeasureItemEventArgs e)
{
    //если это элемент
    if (e.Index > -1)
    {
        //задаем высоту
        e.ItemHeight = 30;
        //ширину
        e.ItemWidth = Width;
    }
}

На этом написане нашего ListBox закончено. Отсалось его применить. Обратите внимание, на панели ToolBox появился наш элемент. Можете напрямую перетащить его на форму либо же прописать его вручную.
 

 

public Form1()
{
    InitializeComponent();

    ButtonListBox butListBox = new ButtonListBox();
    butListBox.SetBounds(10, 10, 170, 250);
    butListBox.Items.AddRange(new object[] { "One", "Two", "Three", "Four", "Five"});
    this.Controls.Add(butListBox);
}

В итоге получаем другое отображение привычного элемента управления.
 

  

  ListBoxButtons.rar (35,7 KiB, 983 закачек)

Поделиться в соц. сетях

Опубликовать в Facebook
Опубликовать в Google Plus
Опубликовать в LiveJournal
Опубликовать в Google Buzz
Опубликовать в Одноклассники
Опубликовать в Яндекс
Опубликовать в Мой Мир

Похожие статьи

Комментарии (2) на “Пишем свой ListBox”

Оставить комментарий