Связанная таблица DataGridView генерирует только одно событие RowChanged при двойном щелчке. Как мне сделать это сделать два? - PullRequest
4 голосов
/ 30 сентября 2008

У меня есть DataGridView, DataSource которого является DataTable. Этот DataTable имеет логический столбец, который интерпретируется как флажок в DataGridView.

employeeSelectionTable.Columns.Add("IsSelected", typeof(bool));
...
employeeSelectionTable.RowChanged += selectionTableRowChanged;
dataGridViewSelectedEmployees.DataSource = employeeSelectionTable;

...

private void selectionTableRowChanged(object sender, DataRowChangeEventArgs e)
{
    if ((bool)e.Row["IsSelected"])
    {
        Console.Writeline("Is Selected");
    }
    else
    {
        Console.Writeline("Is Not Selected");
    }
    break;
}

Когда пользователь нажимает один раз на флажок, он проверяется, и selectionTableRowChanged выдаст «Выбрано».

Аналогичным образом, когда пользователь проверяет его снова, поле очищается, и selectionTableRowChanged выводит «Не выбрано».

Вот где у меня проблема:

Когда пользователь дважды щелкает по флажку, флажок устанавливается, вызывается событие RowChanged («Выбрано»), а затем флажок очищается, и соответствующее событие RowChanged не вызывается. Теперь подписчик на событие RowChanged не синхронизирован.

Мое решение сейчас состоит в том, чтобы создать подкласс DataGridView и переопределить WndProc для использования WM_LBUTTONDBLCLICK, поэтому любой двойной щелчок по элементу управления игнорируется. Есть ли лучшее решение?

Ответы [ 7 ]

2 голосов
/ 18 декабря 2008

Если вам нужен столбец с флажком внутри DataGridView, создайте что-то вроде этого:

DataGridViewCheckBoxCell checkBoxCell = new MyDataGridViewCheckBoxCell();
...
DataGridViewColumn col = new DataGridViewColumn(checkBoxCell);
...
col.Name = "colCheckBox";
...
this.dgItems.Columns.Add(col);

где dgItems - это экземпляр DataGridView.

Как видите, у меня есть класс MyDataGridViewCheckBoxCell, который является подклассом класса DataGridViewCheckBoxCell. В этом подклассе я определяю:

protected override void OnContentDoubleClick(DataGridViewCellEventArgs e)
{
    //This the trick to keep the checkbox in sync with other actions.
    //base.OnContentDoubleClick(e);
}

Когда пользователь теперь дважды щелкает по флажку в столбце флажка, флажок будет вести себя так, как если бы он был нажат один раз. Это должно решить вашу проблему с синхронизацией.

2 голосов
/ 01 сентября 2009

Это не совсем элегантное решение, но почему бы просто не сделать следующее?

private void dgv_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
    dgv_CellClick(sender, e);
}

Это явно вызовет второе событие CellClick и позволит избежать рассинхронизации.

2 голосов
/ 30 сентября 2008

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

Если вы посмотрите на код, сгенерированный окнами, или примеры программного добавления обработчиков событий, вы используете + =, чтобы назначить обработчик событий. Это означает, что вы добавляете этот обработчик событий в дополнение к другим, которые уже существуют, у вас может быть несколько обработчиков событий, запускаемых при сохранении события.

Мой инстинкт был бы переопределить класс DataGridView, затем переопределить метод OnDoubleClick и не вызывать базовый метод OnDoubleClick.

Однако я проверил это очень быстро и вижу некоторые интересные результаты.

Я собрал следующий тестовый класс:

using System;
using System.Windows.Forms;

namespace TestApp
{
    class DGV : DataGridView
    {
        private string test = "";

        protected override void OnDoubleClick(EventArgs e)
        {
            MessageBox.Show(test + "OnDoubleClick");
        }

        protected override void OnCellMouseDoubleClick(System.Windows.Forms.DataGridViewCellMouseEventArgs e)
        {
            MessageBox.Show(test + "OnCellMouseDoubleClick");
        }

        protected override void OnCellMouseClick(System.Windows.Forms.DataGridViewCellMouseEventArgs e)
        {
            if (e.Clicks == 1)
            {
                // Had to do this with a variable as using a MessageBox
                // here would block us from pulling off a double click
                test = "1 click ";
                base.OnCellMouseClick(e);
            }
            else
            {
                MessageBox.Show("OnCellMouseClick");
            }
        }
    }
}

Затем вставил это в форму Windows, добавив столбец флажка и запустив программу.

При повторном запуске двойной щелчок на флажке вызывает отображение в окне сообщения «1 щелчок по OnDoubleClick».

Это означает, что OnCellMouseClick выполняется в первой части двойного щелчка, а затем OnDoubleClick выполняется во втором щелчке.

Кроме того, к сожалению, удаление вызова базовых методов, по-видимому, не препятствует тому, чтобы флажок передавал ему щелчок.

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

Я разместил ответ на другой вопрос, в котором говорится о создании пользовательских столбцов и ячеек DataGridView, на здесь .

1 голос
/ 04 ноября 2008

Не знаю, зачем мне это было нужно, но я смог добавить событие отметки таймера, прикрепленное к обновлению сетки данных, которое просто обновило dgv после второго щелчка.

В событии щелчка по ячейке

**          _RefreshTimer = new Timer();
                _RefreshTimer.Tick += new EventHandler(RefreshTimer_Tick);
                _RefreshTimer.Interval = 100;
                _RefreshTimer.Start();

            }
        }

    }

    void RefreshTimer_Tick(object sender, EventArgs e)
    {
        dgv.Refresh();
        _RefreshTimer.Stop();
        _RefreshTimer = null;
    }**
1 голос
/ 30 сентября 2008

Почему бы просто не оставить столбец IsSelected неограниченным? Используйте событие CellContentClick, чтобы отправить данные в базовую таблицу данных и оставить событие CellDoubleClick или RowChange в покое.

private void dgv_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
  if(e.ColumnIndex == <columnIndex of IsSelected>)
  {
      string value = dgv[e.ColumnIndex, e.RowIndex].EditedFormattedValue;
       if( value == null || Convert.ToBoolean(value) == false)
          {
              //push false to employeeSelectionTable
          }
      else
          {
            //push true to employeeSelectionTable
          }

  }
}
1 голос
/ 30 сентября 2008

Я уже пытался переопределить метод OnDoubleClick в подклассе DataGridView, чтобы ничего не делать, но он все еще позволял менять флажок во второй раз.

В идеале я искал, чтобы событие RowChanged объекта DataTable вызывалось дважды. Есть ли способ повлиять на базовый объект DataTable с помощью переопределенного метода OnDoubleClick?

1 голос
/ 30 сентября 2008

Есть ли какая-то причина, по которой это нужно сделать на этом низком уровне? Может ли метод DoubleClick быть пустым методом, который его ест?

...