【问题标题】:DataGridViewComboBoxColumn - value lags for a split secondDataGridViewComboBoxColumn - 值滞后一瞬间
【发布时间】:2012-07-18 15:32:39
【问题描述】:

我有一个带有几个 DataGridViewComboBoxColumns 的 DataGridView。 DataGridView 上有一个 CellEnter 事件处理程序,用于单击下拉组合框。

该列绑定到一个 KeyValuePairs 列表,ValueMember 为“Key”,DisplayMember 为“Value”。

当我单击组合框列时,它工作正常。但是,如果单元格处于“下拉”状态并且我单击另一个组合框(同一列,不同行),它会正确取消选择旧单元格,选择并下拉新单元格,但是顶部的选定值会更改为旧单元格中的值一瞬间,然后改回正确的值。

例如,假设列表是 A、B、C。在第 1 行中,选择了 A,在第 2 行中,选择了 B。我单击 row1 中的单元格,一切正常。然后,当这个单元格被下拉时,我单击 row2 中的单元格。它正确下降,但顶部选定的值变为 A,然后立即切换回 B(正确的值)。

如果我在单击第二个组合框单元格之前单击其他列中的单元格,则不会发生这种情况。

有没有办法防止这种情况发生?

重现问题的示例代码(事件处理程序与明显的事件挂钩):

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;
        }
    }
}

【问题讨论】:

  • 不清楚您的问题是什么 - 我已尝试根据您的描述重新创建此内容,但无法复制您所描述的任何内容。请提供一个最小且完整的代码示例 - 最好从表单中复制此问题的代码(仅包含相关代码)。
  • 我已经添加了代码。注意 - 必须通过单击打开组合框。我不能只删除此功能。
  • 仍然不确定您的问题是什么 - 您能否将所有事件附加到代码后面,如果可能的话还添加列。目前尚不清楚您在设计器中所做的确切操作,因此在代码中进行更改的完全标准的 datagridview(只是拖到一个空表单上)会更容易遵循。然后我正在尝试解决您遇到的确切问题-如果我有两个组合单元格,并且都选择了值,那么我下拉一个单元格并选择第二个单元格-您说您暂时看到了第一个单元格中的选定值第二个细胞?我根本看不到。
  • 罢工 - 终于设法看到你的问题是什么。
  • 仍然在看这个 - 有一种可怕的感觉,你不走运。问题是当您在同一列中的单元格之间移动时,DataGridView 只有 1 个编辑控件实例。因此,有时您会看到最后一个单元格的值,因为它在更新控件之前会重绘控件。我试图找到一个事件来强制编辑控件及时重绘,但到目前为止还没有运气。顺便说一句 - 在 EditingControlShowing 事件中强制控件打开比在 CellEnter 事件中打开更好。

标签: c# datagridview


【解决方案1】:

原因:

DataGridView 的EndEdit 方法的深处,它存储了以前使用的EditingControl this.latestEditingControl = this.editingControl; 的副本,然后当您开始编辑另一个单元格时,它会启动BeginEditInternal。在此期间,它会检查 latestEditingControl 是否不为 null 并且编辑类型是否与最后一个单元格相同,如果是,它会重用控件,这就是为什么你看到 flash 的原因,它确实是同一个控件。

解决方案:

将 latestEditingControl 设置为 null,此控件无法通过普通属性/方法访问,必须使用反射。注意:这会导致完全不同的烦恼,现在您要离开的单元格呈白色闪烁 :),但它确实解决了您寻求帮助的特定问题。

    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);
    }

【讨论】:

  • 谢谢!由于白色闪烁,这不是一个完美的解决方案,但至少是一些东西。 :D
  • 为我工作,没有任何白色闪烁(VS 2015):D
  • 很棒的提示!我有同样的问题,这解决了问题。无论如何,我有“闪烁的白色”不受欢迎的行为。
  • @ElmoDev001 很高兴你能成功。我看到了你之前的评论,7年后不知道如何帮助你:)
  • 这是一个小问题,我的 dataGridView 是一个继承类,所以我必须使用 dataGridView1.GetType().BaseType (在这里得到解决方案stackoverflow.com/questions/48008545/…
【解决方案2】:

我没有 100% 重现所描述的问题(我从未见过延迟),但请尝试取消订阅 CellEnter 事件并尝试将代码更改为此(来自 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}");
  }
}

当用户进入单元格时应该弹出打开组合框。


或者来自这个解决方案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;
}

【讨论】:

  • 要重现问题,请使用给定的数据绑定一个组合框列,并让每个单元格都有一个选定的项目。一旦完成,选择单元格然后移动到其他单元格将偶尔显示旧选定值的瞬间。我 99% 确定这是在正确刷新之前绘制的编辑控件。尝试了很多乱七八糟的事件来强制控件正确绘制,但无法正常工作。我的最后一个想法是对 ComboBoxColumn 进行子类化,但也许您有比这更好的解决方案:)
  • @DavidHall 我只看到空单元格上的旧值。不然看不到这个鬼值,也绝对看不到延迟。也许这是一个 windows 动画的东西,因为它试图在放下它时产生“幻灯片”效果。
【解决方案3】:

我假设它与 windows 7 的 3d 样式组合框(也许 vista 也是,我没有检查过)

我从没见过这种情况发生

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

不过,您可能不喜欢它的外观。您可以使用

隐藏丑陋的扁平向下箭头
comboboxcolumn.DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing;

就像其他人说的那样,每列只有一个组合框控件(“编辑控件”),并且相同的组合框显示在该列的当前活动单元格中。当单元格未被选中时,由列类的绘制方法来绘制一个假的组合框供用户查看。因此,当您将一个值推送到一个不可见的组合框然后在不同的位置重新绘制它时,可能会发生这种特定 3d 弹出样式的某种内部组合框绘制问题,谁知道呢。

尝试切换到“经典”Windows 主题。组合框应该表现自己。如果您可以强制组合框在 Aero 中以经典主题下的方式呈现它,那将会很有趣。我不确定它是否可能,但您可能想调查一下。

但无论如何,dgv 与其他组合框样式没有这个问题的事实让我认为它只是新的组合框样式不适合 datagridview。

【讨论】:

  • 如果我这样做,前一个单元格会闪烁白色,类似于我按照 Peter 的建议进行操作时发生的情况。这让我觉得编辑控件在这种样式中默认重置,而在新样式中被重用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-05
  • 1970-01-01
  • 2017-02-04
相关资源
最近更新 更多