首页 文章

即使在排序之前清除了选择,DataGridView排序也会导致选择单元格

提问于
浏览
0

此问题通常适用于标准DataGridView . 出于某种原因,即使在用户单击列 Headers 以对DataGridView进行排序时没有选择单元格(选择已清除),它也将始终在排序后选择单元格 . 为了解释为什么我真的不想要这个,我需要提供一些关于我的项目的更多背景知识 .

我需要扩展DataGridView的功能,同时保持数据绑定完好无损 . 首先,我需要将数据组织成可扩展/可折叠组 . 之后,将添加专门为DataGridView(由其他人编写)的其他功能 . 这意味着我无法自由使用不是围绕DataGridView构建的第三方网格组件 .

因此我决定使用HotDog(Robert Verpalen)编写的DataGridViewGrouper组件,请参阅this link代码 . 在此组件中,通过将其visible属性设置为false来隐藏折叠的行 .

原则上它是有效的,直到我尝试在选择其中一个组行后对数据进行排序 . 在这种情况下,它会抛出一个错误:ArgumentOutOfRangeException . 我以为我会采取捷径来解决这个问题,并补充说:

private void dataGridView1_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if (dataGridViewGrouper1.CurrentRowIsGroupRow)
    {
        dataGridView1.ClearSelection();
    }
}

没有理由为什么用户必须能够选择其中一个组行,并清除他们的选择摆脱我尝试排序时得到的错误 . 但是,排序后,总会有一个单元被选中;即使在排序之前清除了选择 .

我添加了一个CellMouseDown事件来跟踪排序前最后选择的单元格,以便排序后我可以再次选择相同的单元格(而不是恰好位于同一行索引的单元格) .

private void dataGridView1_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.RowIndex == -1)
    {
        if (dataGridView1.SelectedCells.Count == 0) { return;  }
        selected = dataGridView1.Rows[dataGridView1.SelectedCells[0].RowIndex].Cells[0].Value.ToString();
    }
}

如果没有选定的单元格,我将从此方法返回(毕竟没有任何东西需要记住) . 如果在最后一次选择组行后尝试排序,则确实会发生此返回,这意味着我尝试清除该选择是成功的 .

但是,在这种情况下仍然选择了单元格 . 这是一个看似随机选择的小组,位于该组的某个地方 . 我怀疑它与选择被清除之前选择的单元格的位置有某种关系 . 这会导致相当恼人的行为,例如屏幕跳转到此选定单元格的位置(几百行之外)或折叠组中的不可见行在选中时变得可见 .

我无法确定在哪个事件中选择了单元格 . 我已经尝试跟踪在排序之前选择了哪个组行,以便我以后可以选择其他内容,如果需要,可以使该组中的所有行再次不可见,但我没有管理 . 我也觉得这不是解决这个问题的正确方法 .

类似地,在进入排序操作而不是清除选择之前,使用循环来选择最接近可见数据单元格似乎不是一个很好的解决方案 . 特别是因为当所有组都折叠时我仍然会遇到问题(没有可见的数据行) .

我真正想要的(我认为)是在排序之后停止选择单元格,如果在排序之前没有选择单元格 . 有人可以帮我吗?

2 回答

  • 0

    每次调用Sort()时,DataBindingCompleted事件也会上升(非常烦人),即使您在DataGridView中的选择被清除,BindingContext [dataGridView1.DataSource] .Position也不会改变,并且您的选择将自动设置为当前位置排序后的数据源(我认为) .

    要解决此问题,请在排序前重置数据位置:

    void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
            {
                if (e.RowIndex == -1)
                {
                    if (dataGridView1.DataSource != null)
                    {
                        BindingContext[dataGridView1.DataSource].Position = 0;
                    }
                }
            }
    

    排序后删除选择(请注意,这不会改变位置!)

    void dataGridView1_Sorted(object sender, EventArgs e)
            {
                if (dataGridView1.SelectedCells.Count > 0)
                {
                    dataGridView1.ClearSelection();
                }
            }
    

    EDIT: 我发现了一些丑陋的黑客,虽然它重新要求覆盖DataGridView保护功能 . 此外,我没有完全测试它,所以它可能会导致一些奇怪的行为(没有保证) . 但它适用于基本设置 . 首先,如果单击列 Headers ,则在CellClick上调用 dataGridView1.ClearSelection(); . 然后:

    public class DGV:DataGridView
    {
            bool isSorted = false;
    
            public override void Sort(DataGridViewColumn dataGridViewColumn, System.ComponentModel.ListSortDirection direction)
            {
                isSorted = true;
                base.Sort(dataGridViewColumn, direction);
            }
            protected override void OnSorted(EventArgs e)
            {
                base.OnSorted(e);
                isSorted = false;
    
            }
    
    protected override void SetSelectedCellCore(int columnIndex, int rowIndex, bool selected)
            {
                // here is where cell gets selected so just ignore it when sorting
                if (isSorted)
                {
                    return;
                }
    
                base.SetSelectedCellCore(columnIndex, rowIndex, selected);
    }
    }
    
  • 2

    您是否尝试将 CurrentCell Selected 属性设置为 False ,如:

    dataGridViewName.CurrentCell.Selected = false;
    

相关问题