Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DataGridViewComboBoxColumn - value lags for a split second

I have a DataGridView with a few DataGridViewComboBoxColumns. There is a CellEnter event handler on the DataGridView for the purpose of single-click dropping down of the comboboxes.

The column is bound to a List of KeyValuePairs, ValueMember being "Key", and DisplayMember being "Value".

When I click on a combobox column, it works fine. However, if the cell is in the "dropdown" state and I click on another combobox (same column, different row), it properly deselects the old cell, selects and drops down the new cell, however the selected value on top changes to the value from the old cell for a split second, before changing back to the correct one.

For example, let's say the list is A, B, C. In row1, A is selected, in row2, B is selected. I click the cell in row1, all is as it should be. Then, while this cell is dropped down, I click on the cell in row2. It drops down properly, but the selected value on top becomes A, then switches back to B (the correct one) immediately.

If I click on a cell in some other column before clicking the second combobox cell, this doesn't happen.

Is there a way to prevent this from happening?

Example code to reproduce the problem (the event handlers are hooked up to the obvious events):

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace PDGV
{
    public partial class Form1 : Form
    {
        List<KeyValuePair<string, string>> bindingList = new List<KeyValuePair<string, string>>();

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            dataGridView1.Rows.Add(10);
            bindingList.Add(new KeyValuePair<string,string>("aaa", "111"));
            bindingList.Add(new KeyValuePair<string,string>("bbb", "222"));
            bindingList.Add(new KeyValuePair<string,string>("ccc", "333"));
            bindingList.Add(new KeyValuePair<string,string>("ddd", "444"));
            bindingList.Add(new KeyValuePair<string,string>("eee", "555"));
            BindComboList(2, bindingList);

        }

        private void BindComboList(int columnIndex, object list)
        {
            var column = dataGridView1.Columns[columnIndex] as DataGridViewComboBoxColumn;
            if (column != null)
            {
                column.DataSource = new BindingSource(list, null);
                column.DisplayMember = "Value";
                column.ValueMember = "Key";
            }
        }

        private void dataGridView1_CellEnter(object sender, DataGridViewCellEventArgs e)
        {
            if (e.RowIndex == -1)
                return;

            dataGridView1.BeginEdit(true);
            var control = dataGridView1.EditingControl as DataGridViewComboBoxEditingControl;
            if (control != null)
                control.DroppedDown = true;
        }
    }
}
like image 985
svinja Avatar asked Jul 13 '12 07:07

svinja


3 Answers

I didn't 100% repro the problem as described (I never saw a lag), but try unsubscribing to the CellEnter event and try changing your code to this (from How do I get DataGridView comboboxes to display their drop down list in one click?)

public Form1() {
  InitializeComponent();

  dataGridView1.EditMode = DataGridViewEditMode.EditOnEnter;
  dataGridView1.EditingControlShowing += dataGridView1_EditingControlShowing;
}

void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e) {
  if (e.Control is ComboBox) {
    SendKeys.Send("{F4}");
  }
}

that should pop open the ComboBox when the user enters the cell.


or from this solution Open dropdown(in a datagrid view) items on a single click

void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e) {
  if (e.Control is ComboBox) {
    ComboBox ctl = e.Control as ComboBox;
    ctl.Enter -= new EventHandler(ctl_Enter);
    ctl.Enter += new EventHandler(ctl_Enter);
  }
}

void ctl_Enter(object sender, EventArgs e) {
  (sender as ComboBox).DroppedDown = true;
}
like image 30
LarsTech Avatar answered Nov 08 '22 10:11

LarsTech


The Cuase:

Deep down in DataGridView's EndEdit method it stores a copy of the previously used EditingControl this.latestEditingControl = this.editingControl; Then when you start editing another cell it Kicks in BeginEditInternal. During this it checks if the latestEditingControl is not null and the editing types are the same as the last cell, if so it reuses the control, which is why you see the flash, it really is the same control.

The Solution:

Set the latestEditingControl to null, this control is not accessible through normal properties/methods, have to use reflection. NOTE: This leads to a totally different annoyance, now the cell you are leaving flashes white :), but it does resolve the specific issue you asked for help on.

    private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
    {
        if (e.RowIndex == -1)
            return;

        //this.latestEditingControl
        Type t = dataGridView1.GetType();
        FieldInfo viewSetter = t.GetField("latestEditingControl", BindingFlags.Default | BindingFlags.NonPublic | BindingFlags.Instance);
        viewSetter.SetValue(dataGridView1, null);
    }
like image 137
Peter Avatar answered Nov 08 '22 09:11

Peter


I assume its with that 3d styled combobox of windows 7 (maybe vista too, I haven't checked)

I've never seen this happen if you

comboboxcolumn.FlatStyle = System.Windows.Forms.FlatStyle.Flat;

You might not like how it looks, though. You can hide the ugly flat down arrow with

comboboxcolumn.DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing;

Like the other guy said, there's only one combobox control per column (the 'editing control') and that same combobox is displayed in the currently active cell of that column. When the cell isn't selected, its up to the drawing methods of the column class to paint a fake combobox for the user to see. So it could be some kind of internal combox drawing issue for that particular 3d popup style that happens when you push a value to an invisible combobox then redraw it in a different spot, who knows.

Try switching to the 'classic' windows theme. The comboboxes should behave themselves then. It would be interesting if you could force a combobox to render the way it does under the classic theme while being in Aero. I'm not sure if its possible, but you might want to look into it.

But anyway, the fact that the dgv doesn't have this problem with the other combobox styles makes me think that its just that new combobox style not fitting well with the datagridview.

like image 1
Isaac Bolinger Avatar answered Nov 08 '22 10:11

Isaac Bolinger