You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将DataGridView中匹配设备类型的搜索结果行置于顶部

问题分析与解决方案

原代码存在的问题

  1. 多余的单元格循环:内层遍历所有单元格完全没必要,你只需要检查指定的「设备类型」列,浪费性能且逻辑混乱。
  2. 提前终止循环:找到第一个匹配行后就break,导致后续匹配的行完全没被处理。
  3. 行选择逻辑错误:dtgridappliance.Rows[index].Selected中的index是传入的列索引,不是当前匹配行的行索引,根本选不到正确的行。
  4. 排序逻辑错误:每次找到匹配就执行默认列升序排序,没有区分「匹配行」和「非匹配行」,反而会打乱结果。
  5. 滚动索引错误:dtgridappliance.SelectedRows[i].Index中的i是内层单元格循环的变量,逻辑完全不对应,会导致索引越界或滚动到错误位置。

解决方案

根据你的需求,我们需要把所有匹配「设备类型」的行移到顶部,同时保留匹配行和非匹配行各自的相对顺序,以下提供两种实现方式:

方式一:自定义排序(适合未绑定数据源的DataGridView)

通过给每行标记「是否匹配」,再用自定义比较器让匹配行优先排在前面:

private void SearchAndMoveToTop(string searchText, DataGridView dataGridView, int targetColumnIndex)
{
    // 配置选择模式
    dataGridView.MultiSelect = true;
    dataGridView.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
    dataGridView.ClearSelection();

    // 遍历所有行,标记是否匹配并选中匹配行
    foreach (DataGridViewRow row in dataGridView.Rows)
    {
        if (row.IsNewRow) continue; // 跳过新增行
        object cellValue = row.Cells[targetColumnIndex].Value;
        bool isMatch = cellValue != null && cellValue.ToString().ToLower().Contains(searchText.ToLower());
        
        row.Tag = isMatch; // 用Tag存储匹配标记
        if (isMatch) row.Selected = true;
    }

    // 执行自定义排序:匹配行在前,同组内保持原顺序
    dataGridView.Sort(new MatchRowComparer(ListSortDirection.Ascending));

    // 滚动到第一个匹配行
    if (dataGridView.SelectedRows.Count > 0)
    {
        dataGridView.FirstDisplayedScrollingRowIndex = dataGridView.SelectedRows[0].Index;
    }
}

// 自定义行比较器
private class MatchRowComparer : System.Collections.IComparer
{
    private readonly ListSortDirection _sortDirection;

    public MatchRowComparer(ListSortDirection direction)
    {
        _sortDirection = direction;
    }

    public int Compare(object x, object y)
    {
        DataGridViewRow rowX = x as DataGridViewRow;
        DataGridViewRow rowY = y as DataGridViewRow;

        if (rowX == null || rowY == null) return 0;

        bool isMatchX = rowX.Tag is bool tagX && tagX;
        bool isMatchY = rowY.Tag is bool tagY && tagY;

        // 匹配行优先排序
        if (isMatchX && !isMatchY)
        {
            return _sortDirection == ListSortDirection.Ascending ? -1 : 1;
        }
        else if (!isMatchX && isMatchY)
        {
            return _sortDirection == ListSortDirection.Ascending ? 1 : -1;
        }
        // 同组内保持原行顺序
        return rowX.Index.CompareTo(rowY.Index);
    }
}

方式二:操作数据源(适合绑定DataTable的场景,更高效)

直接从数据源层面分离匹配和非匹配行,合并后重新绑定,性能比排序更优:

private void SearchAndMoveToTopWithDataTable(string searchText, DataGridView dataGridView, int targetColumnIndex)
{
    if (dataGridView.DataSource is not DataTable dt) return;

    string targetColumnName = dt.Columns[targetColumnIndex].ColumnName;
    dataGridView.MultiSelect = true;
    dataGridView.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
    dataGridView.ClearSelection();

    // 分离匹配与非匹配行
    DataTable matchedTable = dt.Clone();
    DataTable unmatchedTable = dt.Clone();

    foreach (DataRow row in dt.Rows)
    {
        object cellValue = row[targetColumnName];
        bool isMatch = cellValue != null && cellValue.ToString().ToLower().Contains(searchText.ToLower());
        
        if (isMatch) matchedTable.ImportRow(row);
        else unmatchedTable.ImportRow(row);
    }

    // 合并结果:匹配行在前,非匹配行在后
    dt.Clear();
    foreach (DataRow row in matchedTable.Rows) dt.ImportRow(row);
    foreach (DataRow row in unmatchedTable.Rows) dt.ImportRow(row);

    // 选中所有匹配行并滚动到第一行
    foreach (DataGridViewRow row in dataGridView.Rows)
    {
        if (row.IsNewRow) continue;
        object cellValue = row.Cells[targetColumnIndex].Value;
        if (cellValue != null && cellValue.ToString().ToLower().Contains(searchText.ToLower()))
        {
            row.Selected = true;
        }
    }

    if (dataGridView.SelectedRows.Count > 0)
    {
        dataGridView.FirstDisplayedScrollingRowIndex = dataGridView.SelectedRows[0].Index;
    }
}

调用示例

在搜索框的TextChanged事件中调用方法(假设设备类型列是第0列,根据实际情况调整索引):

private void txtApplianceTypeSearch_TextChanged(object sender, EventArgs e)
{
    string searchText = txtApplianceTypeSearch.Text.Trim();
    if (string.IsNullOrEmpty(searchText))
    {
        // 清空搜索时恢复原排序
        dtgridappliance.Sort(dtgridappliance.Columns[0], ListSortDirection.Ascending);
        dtgridappliance.ClearSelection();
        return;
    }

    // 选择对应方式调用
    SearchAndMoveToTop(searchText, dtgridappliance, 0);
    // SearchAndMoveToTopWithDataTable(searchText, dtgridappliance, 0);
}

内容的提问来源于stack exchange,提问作者Tionge

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 21:05:25