DataGridView的选择更改事件触发多次

12

我在我的应用程序中使用DataGridView来显示列表。当用户选择表格视图中的记录时,它应该在另一个面板中显示详细信息。为了实现这个选择功能,我被要求使用DataGridView1_SelectionChanged事件。

DataGridView应该只包含一列,但是选定记录的详细信息可能会有更多的信息(我们可以通过查询所选主键值从数据库中获取所有详细信息)。

请问是否可以获取所选DataGridView记录的数据键(主键)?DataGridView是否基于主键进行绑定?

编辑

我已经实现了DataGridView1.Columns["ID"].Visible = false。它运作良好。为了选择,我添加了DataGridView1_SelectionChanged事件。

但是DataGridView1_SelectionChanged事件会触发多次。


1
我想建议您添加另一列作为主键字段,并通过dgv.CurrentRow.Cells["colPKField"].Value检索它。 - Shell
但是我被要求在GridView中不显示主键。我认为这也不安全...你怎么看? - Sanjeev4evr
2
你可以通过将可见属性赋值为false来隐藏该列。dgv.Columns["colPKField"].Visible = false; - Shell
@Nimesh 是的,我已经实现了它,它运行得很好。但是当我调用dgv_SelectionChanged事件时,我遇到了一个严重的问题,它被触发多次。我在SOF中发现了其他一些人也遇到了异常,但没有解释他如何解决它。 - Sanjeev4evr
尝试使用 RowEnter 事件。 - Shell
@Nimesh RowEnter事件也发生了同样的情况! - Sanjeev4evr
4个回答

38

在执行如下代码之前,您可以在selectionchanged事件中使用DataGrid.focused属性:

private void dg_SelectionChanged(object sender, EventArgs e)
    {
        if (dg.Focused)
        {
            // your code
        }
    } 

8
非常尊重!这个问题在 Win Forms 中很常见,你提供了最简单的解决方案!请问你能解释一下这个属性是做什么用的吗?MSDN 文档不够清晰。 非常敬重!此问题在Win Forms中很常见,您提供了最简单的解决方法!请问您能否解释一下该属性的作用?MSDN文档不够清晰。 - 3bdalla
非常感谢,你救了我的命;-) - Esi
解决 WinForms 中无法克服的烦恼的绝佳方案。 - CJ K

2
如果数据绑定被重置,您会收到一个 SelectionChanged 通知列表暂时为空,然后在数据填充后再次收到通知。更糟糕的是,选定的项目可能甚至自重置之前就没有改变。我通过检查每个调用中的 SelectedCells 来验证这一点。
一种解决方案是使用无效变量,并在 Application.Idle 事件中进行检查。这样做的好处是将更改分组并避免不必要的更新。Application.Idle 在消息队列为空时立即运行,因此用户不会注意到延迟。如果在网格排序完成后检查是否需要更改,那就更好了。
您需要在构造函数中设置静态表单实例属性。
private bool isViewUpToDate = false;

private void DataGrid_SelectionChanged(object sender, EventArgs e) => isViewUpToDate = false;

public void CheckDataGridSelectionView()
{
    if (isViewUpToDate)
        return;

    // Logic goes here

    isViewUpToDate = true;
}

static void Main()
{
    Application.Idle += (sender, eventData) => MainForm.Instance?.CheckDataGridSelectionView();

    // ...
}

2

今天我遇到了同样的问题,经过数小时的试验,我找到了一个解决方案,或者更确切地说是一个解决方法。

this.dgvSearchResult.SelectionChanged -= dgvSearchResult_SelectionChanged;
this.onSearch();
this.dgvSearchResult.SelectionChanged += new EventHandler(dgvSearchResult_SelectionChanged);

希望这有所帮助


1
我尝试使用RowEnter事件,但对我来说效果很好。你如何检查呢?使用消息框还是在事件中设置断点?因为断点和消息框会使所选行失去焦点。然后,在消息框或断点后继续执行时,网格将重新聚焦,并且事件将再次执行。
请尝试以下步骤以检查事件执行。 enter image description here 处理多次执行的方法。
int LastRowIndex =-1;

private void dgv_RowEnter(...)
{
    if (LastRowIndex != e.RowIndex)
    {
        //Place your code here.
    }
    LastRowIndex = e.RowIndex;
}

我也尝试了RowEnter事件,但它会多次触发。当窗体加载时,甚至在我点击网格外部(空白区域)时也会触发,因此所选行的索引值为0。 - Sanjeev4evr
你可以通过将上次选择的行索引存储在任何变量中来避免多次执行。 - Shell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接