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

У меня есть DataGridView, источником данных которого является 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 выводит «Is Not Selected».

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

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

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


person Community    schedule 29.09.2008    source источник


Ответы (7)


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

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

Моим инстинктом было бы переопределить класс 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 в здесь.

person ManiacZX    schedule 29.09.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);
}

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

person Community    schedule 18.12.2008

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

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

Это явно вызовет второе событие CellClick и предотвратит рассинхронизацию.

person Rob Smith    schedule 01.09.2009

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

person Ian Jacobs    schedule 29.09.2008

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

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

person Community    schedule 29.09.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
          }

  }
}
person Vivek    schedule 29.09.2008

Не знаю, почему мне пришлось, но я смог добавить событие таймера, прикрепленное к обновлению datagridview, которое только что обновило 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;
    }**
person Community    schedule 04.11.2008