ListView с редактируемыми ячейками

Данный пост написан по мотивам статьи с codeproject “ListView in-line editing”.

listTreeView pic1

Суть вопроса в том, что иногда возникает необходимость править данные в ячейках элемента ListView, который настроен на табличное представление (свойство View выставлено в Details). Как вы знаете напрямую это сделать нельзя, потому что ячейки эти реализованы как Read Only.

Исходный код доступен на GitHub.

В этом случае нам поможет TextBox. Как использовать данную методику я покажу на примере. В нашем распоряжении будет таблица с двумя столбцами Address и Value. При этом редактируемой может быть только ячейка в столбце Value. Таблица реализована при помощи элемента ListView и называется lvTable.

Идея подхода следующая: на форму мы поместим TextBox элемент (tbCell), он будет подставляться на место ячейки, данные который мы ходим изменить. Изменение осуществляется двойным щелчком левой кнопки мыши по соответствующей ячейке, после этого информация из нее будет скопирована в tbCell, доступный для редактирования. Для сохранения данных нужно нажать Enter или убрать фокус с элемента.

Далее предлагаю описание реализации в виде последовательности действий. Исходный код проекта прилагается к статье.

Шаг 1

На форме располагаем все необходимые элементы: ListView, TextBox, и настраиваем их.

ListView

Свойство Значение
BorderStyle None
FullRowSelect True
Name lvTable
Dock Fill
View Details

Добавим два столбца (Address и Value) на ListView, для этого нужно щелкнуть по значению свойства Columns и в появившемся окне сделать необходимые правки.

TextBox

Свойство Значение
Name tbCell
Dock Fill

Форма будет выглядеть примерно так, как показано ниже.
listTreeView_pic2

Шаг 2

Добавим загрузку демо данных на форму, для этого создадим обработчик события Load для формы и назовем его Form1_Load. После этого добавим в него код, заполняющий таблицу данными.

private void Form1_Load(object sender, EventArgs e)
{
    Random rnd = new Random();
    for (int i = 0; i < 10; i++)
    {
        ListViewItem lvi = new ListViewItem();
        lvi.Text = i.ToString();
        lvi.SubItems.Add(rnd.Next(0, 100).ToString());
        lvTable.Items.Add(lvi)
    }
}

Добавим обработчики событий для наших элементов.

ListView

Событие Значение
MouseDoubleClick lvTable_MouseDoubleClick

TextBox

Событие Значение
Leave tbCell_Leave
KeyPress tbCell_KeyPress

Шаг 3

Добавим в обработчики событий код, который позволяет “редактировать” ячейки таблицы.

Создадим три глобальных переменных.

bool CancelEdit = false;
ListViewItem.ListViewSubItem CurrentSubItem = default(ListViewItem.ListViewSubItem);
ListViewItem CurrentItem = default(ListViewItem);

CancelEdit – переменная, являющаяся флагом, через который передается разрешение на изменение данных ячейки.

CurrentItem – текущая запись таблицы.

CurrentSubItem – поле редактируемой записи.

Заполним кодом обработчики событий.

private void lvTable_MouseDoubleClick(object sender, MouseEventArgs e)
{
    // Get current item of ListView
    CurrentItem = lvTable.GetItemAt(e.X, e.Y);
    if (CurrentItem == null)
        return;

    // Get sub item of current item
    CurrentSubItem = CurrentItem.GetSubItemAt(e.X, e.Y);
    int SubItembIndex = CurrentItem.SubItems.IndexOf(CurrentSubItem);

    // Check that we try edit column "Value"
    switch (SubItembIndex)
    {
        case 1:
            break;
        default:
            return;
    }

    // Set params for TextBox, show it and set focus
    int lLeft = CurrentSubItem.Bounds.Left + 2;
    int lWidth = CurrentSubItem.Bounds.Width - 2;
    tbCell.SetBounds(lLeft + lvTable.Left, CurrentSubItem.Bounds.Top + lvTable.Top, lWidth, CurrentSubItem.Bounds.Height);
    tbCell.Text = CurrentSubItem.Text;
    tbCell.Show();
    tbCell.Focus();
}

private void tbCell_KeyPress(object sender, KeyPressEventArgs e)
{
    switch (e.KeyChar)
    {
        // If you press Enter than copy data from TextBox to ListView cell
        case (char)Keys.Return:
            CancelEdit = false;
            e.Handled = true;
            tbCell.Hide();
            break;
            
        // If you press Escape than data in ListView cell stay without changes
        case (char)Keys.Escape:
            CancelEdit = true;
            e.Handled = true;
            tbCell.Hide();
            break;
    }
}

private void tbCell_Leave(object sender, EventArgs e)
{
    tbCell.Hide();
    if (CancelEdit == false)
    {
        CurrentSubItem.Text = tbCell.Text;
    }
    else
    {
        CancelEdit = false;
    }

    lvTable.Focus();
}

В своем проекте, на этом этапе, вам будет необходимо внести в обработчики событий свои коррективы: проверка вводимых данных и т.п.
На этом все, спасибо!

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *