【问题标题】:C# datagridview row toggleC# datagridview 行切换
【发布时间】:2015-08-19 02:34:57
【问题描述】:

我正在寻求有关 datagridview 的帮助。

我想要做的是,当我单击receiptView(datagridview)列表中的一个项目(一行)时,它应该切换该行的选择(即,如果它已经被选择,它将取消选择,反之亦然)。

到目前为止,我已经找到了这段代码,但是,这并不总是有效:

    private void receiptView_CellClick(object sender, DataGridViewCellEventArgs e)
    {
        if (!_selectionChanged)
        {
            //do other stuff here
            receiptView.ClearSelection();
            _selectionChanged = true;
        }
        else
        {
            //do other stuff here
            _selectionChanged = false;
        }
    }

    private void receiptView_SelectionChanged(object sender, EventArgs e)
    {
        _selectionChanged = true;
    }

仅供参考

  • 当点击一行而没有选择行时OR已经选择了一行并且现在选择了一个新行,它会触发 事件按以下顺序:

    1. receiptView_SelectionChanged
    2. receiptView_CellClick
  • 当点击一行并且它已经被选中时,它只会触发 receiptView_CellClick 事件

问题

发生的情况是,当我非常快速地选择/取消选择一行时(类似于双击),它最终会“取消同步”实际选择状态和 _selectionChanged。我的意思是:

  1. 一旦选择一行,它将突出显示/选择该行(正常)
  2. 现在再次选择同一行时(在第一次单击之后快速连续),它不会取消选择该行,但似乎在执行错误的“在此处执行其他操作”时保持选中状态(不正常,应该有取消选择)
  3. 在第三次单击时取消选择(如果是第 2 步,则正常,应该只有两个步骤)

这种情况不会在我每次快速点击时发生,但它确实会定期发生(大约每第二/第三次点击对)。如果我缓慢而刻意地点击,它永远不会发生。

理论

我真的不知道为什么会发生这种情况,但我怀疑由于点击 1 和 2 彼此非常接近,第二次点击的事件在第一次点击仍在运行时触发,导致第一次点击改变 _selectionChanged 为 false,第二个将其更改回 true,同时保持选中行。但是,由于我没有创建任何新线程并且这一切都在主 UI 线程上运行,所以它不应该是序列化执行吗?即点击1的事件触发,完成后点击2的事件触发?

问题

如果你们中的任何人知道更简单的方法(在 datagridview 中切换),或者可以看到错误和/或有解决方案,我们将不胜感激。

谢谢。

【问题讨论】:

  • 有调试和调用堆栈窗口。您可以看到发生了什么问题。
  • 嗨,我的生日...所以是的,我已经尝试过了,但我似乎仍然无法弄清楚发生了什么

标签: c# datagridview toggle


【解决方案1】:

TL;DR

您的第二次点击被CellDoubleClick 事件劫持。使用来自 CellClick 事件处理程序的相同代码订阅它。
- 请参阅答案末尾的解决方案

调试说明

为了演示发生了什么,我们将以下输出添加到您的方法中,然后运行您在 OP 中描述的场景。

private void receiptView_CellClick(object sender, DataGridViewCellEventArgs e)
{
    if (!_selectionChanged)
    {
        Console.WriteLine("Cleared.......");
        receiptView.ClearSelection(); // NOTE: Triggers SelectionChanged event.
        _selectionChanged = true;
    }
    else
    {
        Console.WriteLine("Highlighted...");
        _selectionChanged = false;
    }
}

private void receiptView_SelectionChanged(object sender, EventArgs e)
{
    Console.WriteLine("Changed!");
    _selectionChanged = true;
}

当前未选择任何行,以下测试、预期结果和实际结果:

+======================+=================+================+=================+
|       ACTION         | EXPECTED OUTPUT | ACTUAL OUTPUT  |   GUI RESULTS   |
+======================+=================+================+=================+
| Single-click 1st row | Changed!*       | Changed!*      | Row Highlighted |
|                      | Highlighted...  | Highlighted... |                 |
+----------------------+-----------------+----------------+-----------------+
| Double-click 1st row | Cleared.......  | Cleared....... | Row Highlighted |
|                      | Changed!^       | Changed!^      |                 |
|                      | Changed!*       | Changed!*      |                 |
|                      | Highlighted...  |                |                 |
+----------------------+-----------------+----------------+-----------------+
| Single-click 1st row | Cleared.......  | Highlighted... | Row Highlighted |
|                      | Changed!^       |                | (Still...?)     |
+----------------------+-----------------+----------------+-----------------+

* SelectionChanged 在后面的代码中触发;现在选择了未选择的行。
^ 调用 ClearSelection() 触发了 SelectionChanged。

分析:您的第一次点击触发SelectionChanged 并按预期突出显示该行。接下来,您双击该行,认为第一次单击将清除该行(您将手动触发SelectionChanged),第二次单击(再次触发SelectionChanged背景)重新突出显示它。这就是我们出错的地方。

双击中,第一次点击会按预期触发 clear 和 SelectionChanged 事件。我们甚至看到来自SelectionChanged 的第二个预期打印输出,但没有看到来自CellClick 事件的突出显示打印输出。为什么?

当您单击行/单元格一次时,会触发CellClick。当您快速连续单击两次时,CellClick 触发第一次单击,CellDoubleClick 触发第二次单击。因此,您的第一次点击会按预期命中您的代码。第二次点击永远不会点击您的代码,除了在后台未选择的行仍然被选中,因此SelectionChanged 仍然被第二次触发。从此时起,您的 _selectionChanged 标志已关闭 - 导致更多不准确的结果。

解决方案:订阅CellDoubleClick 事件并在其中执行与CellClick 中相同的代码,就可以了。

private void receiptView_CellClick(object sender, DataGridViewCellEventArgs e)
{
    this.DoStuff();
}

private void receiptView_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
    this.DoStuff();
}

private void DoStuff()
{
    if (!_selectionChanged)
    {
        //do other stuff here
        receiptView.ClearSelection();
        _selectionChanged = true;
    }
    else
    {
        //do other stuff here
        _selectionChanged = false;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-25
    • 1970-01-01
    • 2015-08-18
    • 1970-01-01
    • 1970-01-01
    • 2016-07-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多