在WinForm应用程序中排序DataGridView时选择的行

时间:2011-01-27 17:14:28

标签: .net winforms datagridview c#-4.0

在WinForm应用程序C#4.0中,我有一个绑定到SortableBindingList的DataGridView。因此,可以通过单击标题列进行排序 - 到目前为止一切正常; - )

问题是,所选行似乎被行号“记住”。以下是发生的事情:

A*  <- "Selected"
B
C

现在排序降序,C在顶部并选中。我想要选择A:

C*  <- "Selected"
B
A   <- "Want have"

类似地,选择了多行。有解决方法吗?

3 个答案:

答案 0 :(得分:11)

您可以通过在排序之前存储当前所选行(或行)的值然后重新选择该行来解决此问题。

您需要使用CellMouseDown事件 - 必须使用此事件,因为它是唯一一个在排序发生之前触发的事件。像ColumnHeaderMouseClick这样的替代事件都太晚了。

在CellMouseDown事件处理程序中检查行索引是否为-1,以确保选择了标题。

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

我有一个类级别字段selected,用于存储所选列的唯一标识符。如果您没有唯一ID,则可以为此添加一列并隐藏它。

然后在DataGridView的Sorted eventhandler中,您可以使用网格绑定源的.Find()方法:

void dataGridView1_Sorted(object sender, EventArgs e)
{
    if (!string.IsNullOrEmpty(selected))
    {
        int itemFound = _bindingSource.Find("name", selected);
        _bindingSource.Position = itemFound;
    }
}

在调查此问题时,我在MSDN论坛上找到了以下post,答案使用了DataBindingComplete事件 - 我不是100%为什么他们发现必要,因为我的方法适用于我的所有测试,但是你可能会发现它是一个有用的参考。

答案 1 :(得分:4)

这是我在VB.NET中的方法

Private cSelectedRow As String

Private Sub DataGridView1_CellMouseDown(sender As Object, e As DataGridViewCellMouseEventArgs) Handles DataGridView1.CellMouseDown
    If e.RowIndex = -1 AndAlso DataGridView1.SelectedRows.Count > 0 Then
        cSelectedRow = DataGridView1.SelectedRows(0).Cells("ID").Value.ToString()
    End If
End Sub

我使用了与David Hall相同的事件,但没有使用BindingSource。所以我遍历网格的所有行以找到之前选择的那个。

Private Sub DataGridView1_Sorted() Handles DataGridView1.Sorted
    DataGridView1.ClearSelection()
    For Each xRow As DataGridViewRow In DataGridView1.Rows
        If xRow.Cells("ID").Value = cSelectedRow Then
            DataGridView1.CurrentCell = xRow.Cells(0)
            'Line Found. No need to loop through the rest.
            Exit For
        End If
    Next
End Sub

答案 2 :(得分:1)

在网格的三个状态之一中,我尝试了David Hall的回答,但对我没有用,所以我在MyDataGridView.cs类中做了一些更改,这样:

public string SelectedValue { get; set; }
private bool headerFirstClick = true;
public bool HeaderWasClicked = false;

private void MyDataGridView_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
    {
    try
       {
            if (headerFirstClick) Columns[e.ColumnIndex].HeaderCell.SortGlyphDirection = SortOrder.None;
            if (Columns[e.ColumnIndex].HeaderCell.SortGlyphDirection == SortOrder.None)
            {
                Columns[e.ColumnIndex].SortMode = DataGridViewColumnSortMode.Automatic;
                Sort(Columns[e.ColumnIndex], System.ComponentModel.ListSortDirection.Ascending);
                Columns[e.ColumnIndex].HeaderCell.SortGlyphDirection = SortOrder.Ascending;
            }
                else if (Columns[e.ColumnIndex].HeaderCell.SortGlyphDirection == SortOrder.Ascending)
            {
                Columns[e.ColumnIndex].SortMode = DataGridViewColumnSortMode.Programmatic;
                ((BindingSource)DataSource).Sort = string.Empty;
                Columns[e.ColumnIndex].HeaderCell.SortGlyphDirection = SortOrder.None;
            }
            headerFirstClick = false;
            int findValue = ((BindingSource)DataSource).Find(Columns[e.ColumnIndex].Name, SelectedValue);
            ((BindingSource)DataSource).Position = findValue;
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex);
        }
    }

protected override void OnCellClick(DataGridViewCellEventArgs e)
    {
        base.OnCellClick(e);
        if (e != null)
        {
            try
            {
                HeaderWasClicked = (e.RowIndex == -1);
                SelectedValue = SelectedRows[0].Cells[e.ColumnIndex].Value.ToString();
            }
            catch(Exception){}
        }
    }