C# datagridview 行切换
C# datagridview row toggle
我希望获得有关 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;
}
仅供参考
当一行被点击并且没有行被选中时 或者 一行已经被选中并且现在选中了一个新行它会触发
以下顺序的事件:
- receiptView_SelectionChanged
- receiptView_CellClick
- 当一行被点击并且它已经被选中时,它只会触发 receiptView_CellClick 事件
问题
发生的事情是,当我 select/deselect 非常快速地(类似于双击)一行时,它最终会变成 "de-syncing" 实际选择状态和 _selectionChanged。我的意思是:
- 当一行被选中时,它会highlight/select那一行(正常)
- 现在再次选择同一行时(在第一次单击后快速连续)它不会取消选择该行,但似乎在错误的 "do other stuff here" 被执行时保持选中状态(不正常,应该已取消选择)
- 第三次单击取消选择(如果是第 2 步,则正常,应该只有两步)
这不会在我每次快速点击时发生,但它会定期发生(大约每 second/third 个点击对)。如果我缓慢而有意地点击,它永远不会发生。
理论
我真的不知道为什么会发生这种情况,但我怀疑由于点击 1 和 2 发生的时间非常接近,第二次点击的事件触发而第一次点击仍然 运行,导致第一次点击单击以将 _selectionChanged 更改为 false,然后单击第二个将其更改回 true,同时保持该行处于选中状态。但是,由于我没有创建任何新线程,而且这是主 UI 线程上的全部 运行,它不应该是序列化执行吗?即点击 1 的事件触发,完成后,点击 2 的事件触发?
问题
如果您知道更简单的方法(在数据网格视图中切换),或者可以看到错误 and/or 有解决方案,我们将不胜感激。
谢谢。
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 在后面的代码中触发;未选择的行现在被选中。
^ SelectionChanged 由调用 ClearSelection() 触发。
分析:您的第一次点击会触发 SelectionChanged
并按预期突出显示该行。接下来,您 双击 该行,认为第一次单击会清除该行(您将手动触发 SelectionChanged
),然后第二次单击(再次触发SelectionChanged
在背景中)重新突出显示它。这就是我们出错的地方。
从双击,第一次点击按预期触发清除和SelectionChanged
事件。我们甚至看到了 SelectionChanged
的第二个预期打印输出,但没有看到 CellClick
事件的突出显示输出。为什么?
当您点击row/cell一次时,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;
}
}
我希望获得有关 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;
}
仅供参考
当一行被点击并且没有行被选中时 或者 一行已经被选中并且现在选中了一个新行它会触发 以下顺序的事件:
- receiptView_SelectionChanged
- receiptView_CellClick
- 当一行被点击并且它已经被选中时,它只会触发 receiptView_CellClick 事件
问题
发生的事情是,当我 select/deselect 非常快速地(类似于双击)一行时,它最终会变成 "de-syncing" 实际选择状态和 _selectionChanged。我的意思是:
- 当一行被选中时,它会highlight/select那一行(正常)
- 现在再次选择同一行时(在第一次单击后快速连续)它不会取消选择该行,但似乎在错误的 "do other stuff here" 被执行时保持选中状态(不正常,应该已取消选择)
- 第三次单击取消选择(如果是第 2 步,则正常,应该只有两步)
这不会在我每次快速点击时发生,但它会定期发生(大约每 second/third 个点击对)。如果我缓慢而有意地点击,它永远不会发生。
理论
我真的不知道为什么会发生这种情况,但我怀疑由于点击 1 和 2 发生的时间非常接近,第二次点击的事件触发而第一次点击仍然 运行,导致第一次点击单击以将 _selectionChanged 更改为 false,然后单击第二个将其更改回 true,同时保持该行处于选中状态。但是,由于我没有创建任何新线程,而且这是主 UI 线程上的全部 运行,它不应该是序列化执行吗?即点击 1 的事件触发,完成后,点击 2 的事件触发?
问题
如果您知道更简单的方法(在数据网格视图中切换),或者可以看到错误 and/or 有解决方案,我们将不胜感激。
谢谢。
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 在后面的代码中触发;未选择的行现在被选中。
^ SelectionChanged 由调用 ClearSelection() 触发。
分析:您的第一次点击会触发 SelectionChanged
并按预期突出显示该行。接下来,您 双击 该行,认为第一次单击会清除该行(您将手动触发 SelectionChanged
),然后第二次单击(再次触发SelectionChanged
在背景中)重新突出显示它。这就是我们出错的地方。
从双击,第一次点击按预期触发清除和SelectionChanged
事件。我们甚至看到了 SelectionChanged
的第二个预期打印输出,但没有看到 CellClick
事件的突出显示输出。为什么?
当您点击row/cell一次时,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;
}
}