1
votes

I have DataGridView with multi-select mode on and Grid row having DataGridViewButtonColumn(Button).I can select mutiliple rows using CRTL and SHIFT keys same as windows folder/file functionality but when I click on row button(DataGridViewButtonColumn) on any row after doing multi-selection this multi selected row information is getting lost and the current row is highlighted.I required to preserve this multi selected row information.If I use CTRL key while clicking on row button the current is deselected/selected.

I am using VS 2012, c# and winforms. What is the best way to hold multi selected row information on datagridview having buttons and checkbox on each grid row? Thanks for any help in advance and any suggestions/code snippets appreciated.

DatagridView properties Set:

        dataGridView1.AutoGenerateColumns = false;
        dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
        dataGridView1.MultiSelect = true;
        dataGridView1.ReadOnly = false;
1

1 Answers

0
votes

You have to customize your own DataGridView. This allows you to add custom code to the WndProc then you can catch the message WM_LBUTTONDOWN, check if the mouse is down on a DataGridViewButtonCell to discard that message. Somehow the CellContentClick is still raised (this is done by the internal implementation of DataGridView). However after discarding the WM_LBUTTONDOWN, the Button looses the look and feel of pressed state. That's a little annoying. So to mimic that state, we have to draw the button ourselves. Drawing the button makes us mimic more states than just the pressed state (such as hot state, normal state). Here is the code for you, works perfectly:

public class CustomGrid : DataGridView
{
    DataGridViewCell downButton;
    DataGridViewCell lastHoveredCell;
    protected override void WndProc(ref Message m)
    {
        if (m.Msg == 0x201)//WM_LBUTTONDOWN = 0x201
        {
            HitTestInfo ht = TryHitTest(m);
            if (ht.Type == DataGridViewHitTestType.Cell)
            {
                downButton = this[ht.ColumnIndex, ht.RowIndex];
                if (SelectedCells.Count > 1&&downButton is DataGridViewButtonCell){                                    
                   InvalidateCell(ht.ColumnIndex, ht.RowIndex);
                   return;
                }
            }
         } else if (m.Msg == 0x202) downButton = null; //WM_LBUTTONUP = 0x202
         else if (m.Msg == 0x200) { //WM_MOUSEMOVE = 0x200
            HitTestInfo ht = TryHitTest(m);
            if (ht.Type == DataGridViewHitTestType.Cell)
            {
                if (lastHoveredCell != this[ht.ColumnIndex, ht.RowIndex]){
                    if(lastHoveredCell != null &&
                       lastHoveredCell.DataGridView!=null)        
                       InvalidateCell(lastHoveredCell);                        
                    lastHoveredCell = this[ht.ColumnIndex, ht.RowIndex];
                    InvalidateCell(lastHoveredCell);                        
                }
            }
         }            
         base.WndProc(ref m);            
    }
    private HitTestInfo TryHitTest(Message m)
    {
        int x = m.LParam.ToInt32() & 0xffff;
        int y = m.LParam.ToInt32() >> 16;
        return HitTest(x, y);
    }
    protected override void OnCellPainting(DataGridViewCellPaintingEventArgs e)
    {
        if (e.ColumnIndex > -1 && e.RowIndex > -1 && this[e.ColumnIndex, e.RowIndex] is DataGridViewButtonCell)
        {
            e.Handled = true;
            e.PaintBackground(e.ClipBounds, false);
            Rectangle buttonBounds = e.CellBounds;
            string text = ((DataGridViewButtonColumn)Columns[e.ColumnIndex]).Text;
            var buttonState = System.Windows.Forms.VisualStyles.PushButtonState.Normal;
            if(buttonBounds.Contains(PointToClient(MousePosition))){
                buttonState = MouseButtons == MouseButtons.Left && downButton == this[e.ColumnIndex, e.RowIndex] ?
                              System.Windows.Forms.VisualStyles.PushButtonState.Pressed :
                              System.Windows.Forms.VisualStyles.PushButtonState.Hot;
            }                                
            ButtonRenderer.DrawButton(e.Graphics, buttonBounds, text, e.CellStyle.Font, false, buttonState);                
        }
        else base.OnCellPainting(e);            
    }
    protected override void OnColumnWidthChanged(DataGridViewColumnEventArgs e) {
        base.OnColumnWidthChanged(e);            
        InvalidateColumn(e.Column.Index);
    }  
}

This screen shot shows that one button is being pressed while all the selected cells are still being selected.

enter image description here