How can I capture the mouse in a DataGridViewRow, so it only moves within the row

215 Views Asked by At

I am writing a reservation application which utilizes a DataGridView to list the available rooms down the Y axis and the available times on the X axis as the columns.

I would like the user to be able to drag select a time frame, but it has to be limited to one row at a time.

Either controlling the highlight aspect of the grid so only the desired row is highlighted when the mouse moves or capturing the mouse within the rows bounds are the options I have thought of. Any help in implementation either of these or even a new way to handle the task are all welcome!

I would prefer to just capture the mouse with the DataRow where the mouse down event occurs, not sure if I have to use a clipping rectangle to achieve this or not.

Thanks in advance for any help.

2

There are 2 best solutions below

0
On BEST ANSWER

As an improvement on your CellStateChanged event code, the below could be used.

private void dataGridView1_CellStateChanged(object sender, DataGridViewCellStateChangedEventArgs e)
{
  if ((e.StateChanged == DataGridViewElementStates.Selected) && // Only handle it when the State that changed is Selected
      (dataGridView1.SelectedCells.Count > 1))
  {
    // A LINQ query on the SelectedCells that does the same as the for-loop (might be easier to read, but harder to debug)
    // Use either this or the for-loop, not both
    if (dataGridView1.SelectedCells.Cast<DataGridViewCell>().Where(cell => cell.RowIndex != e.Cell.RowIndex).Count() > 0)
    {
      e.Cell.Selected = false;
    }

    /*
    foreach (DataGridViewCell cell in dataGridView1.SelectedCells)
    {
      if (cell.RowIndex != e.Cell.RowIndex)
      {
        e.Cell.Selected = false;
        break;  // stop the loop as soon as we found one
      }
    }
    */
  }
}

The differences in this for-loop is the usage of e.Cell as a reference point for RowIndex since e.Cell is the cell that was selected by the user, setting of e.Cell.Selected to false instead of cell.Selected and finally a break; in the for-loop since after the first RowIndex mismatch, we can stop the checking.

1
On

Probably a better way to write this but it works.

private void dataGridView1_CellStateChanged(object sender, DataGridViewCellStateChangedEventArgs e)
    {
        if (dataGridView1.SelectedCells.Count > 1)
        {
            //Retrieves the first cell selected
            var startRow = dataGridView1.SelectedCells[dataGridView1.SelectedCells.Count - 1].RowIndex;

            foreach (DataGridViewCell cell in dataGridView1.SelectedCells)
            {
                if (cell.RowIndex != startRow)
                {
                    cell.Selected = false;
                }
            }
        }
    }