数据网格中的 CurrentRow 在选择不同的行后给出第一行

CurrentRow in Data Grid giving first row after Selecting differant Row

我有一个 C# 项目 (VS 2017),它使用数据网格视图在对象列表中显示数据。使用 contextMenuStrip 我希望能够右键单击一行并将其从 datagridview 和基础数据源中删除。

我在 Datagridview 的属性中设置了 contextMenuStrip,其中一项具有以下处理事件的方法。

    private void dgv_Test_MouseDown(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Right)
        {
            var hti = dgv_Test.HitTest(e.X, e.Y);

            dgv_Test.ClearSelection();
            dgv_Test.Rows[hti.RowIndex].Selected = true;
        }
    }

    private void cms_DGV_Remove_Click(object sender, EventArgs e)
    {
        MessageBox.Show("Content Menu Clicked on Remove Option");

        PersonModel temp = (PersonModel)dgv_Test.CurrentRow.DataBoundItem;

        string msg = $"The index for the selected Person is {temp.Id}.";
        MessageBox.Show(msg);

    }

我希望这会将当前行发送到右键单击的行。这不会发生,因为 CurrentRow 停留在顶行。如果我先左键单击该行然后右键单击同一行,它确实有效。

您描述的问题来自 cms_DGV_Remove_Click 事件。当用户 right-clicks 在网格上时,这不会使光标下方的 cell/row 成为网格的 CurrentRow. 即使 dgv_Test_MouseDown 方法中的代码将行设置为“selected”……它不一定是“当前”行。网格 CurrentRow 属性 是只读的,您不能直接从代码中设置它。

鉴于此,很明显从上下文菜单中获取“相对于网格”的鼠标坐标会花费一些精力,因为它的坐标是全局的。您显然已经从连接网格 MouseDown 事件中注意到了这一点。这个事件使得捕获鼠标相对于网格的位置变得容易。问题是……您没有保存此信息。当上下文菜单触发时,该信息已丢失。

解决方案:将 DataGridView.HitTest 信息设为全局。然后,每次用户右键单击进入网格时设置它。有了这个全局变量集,当上下文菜单触发时,它会知道光标在哪一行。

DataGridView.HitTestInfo HT_Info;   // <- Global variable

private void dgv_Test_MouseDown(object sender, MouseEventArgs e) {
  if (e.Button == MouseButtons.Right) {
    HT_Info = dgv_Test.HitTest(e.X, e.Y);
    if (HT_Info.RowIndex >= 0) {
      dgv_Test.ClearSelection();
      dgv_Test.Rows[HT_Info.RowIndex].Selected = true;
    }
  }
}

发布的代码似乎并没有真正删除该行,但是下面是上下文菜单“删除”事件的外观......

下面应该适用于 non-data 绑定网格以及具有数据绑定的网格 DataTable.

private void cms_DGV_Remove_Click(object sender, EventArgs e) {
  if (HT_Info.RowIndex >= 0) {
    dgv_Test.Rows.Remove(dgv_Test.Rows[HT_Info.RowIndex]);
  }
}

如果您使用的是 List<T>,删除方法可能如下所示...

private void cms_DGV_Remove_Click(object sender, EventArgs e) {
  if (HT_Info.RowIndex >= 0) {
    PersonModel targetPerson = (PersonModel)dgv_Test.Rows[HT_Info.RowIndex].DataBoundItem;
    AllPersons.Remove(targetPerson);
    dgv_Test.DataSource = null;
    dgv_Test.DataSource = AllPersons;
  }
}

我猜这就是您正在寻找的行为。用户 right-clicks 进入网格,光标下的行被 select 编辑,上下文菜单“删除”弹出。用户可以“select”删除以删除该行或单击上下文菜单以外的地方以取消删除。

希望这是有道理的。