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

DevExpress GridView行级联动问题:如何根据每行选中的国家动态加载对应城市下拉列表

解决DevExpress GridView每行独立加载对应国家城市的问题

你的问题根源很明确:你给整个il列设置了同一个RepositoryItemLookUpEdit实例,所以不管哪一行修改国家,所有行的城市列都会共享最后一次创建的下拉编辑器,自然显示的都是最后选中国家的城市列表。要实现每行独立的城市下拉,我们需要动态为每行的城市单元格分配对应的编辑器,而不是给整个列设置统一的编辑器。

下面是完整的解决方案:

步骤1:添加编辑器缓存字典

首先在窗体类中定义一个字典,用来缓存不同国家对应的下拉编辑器,避免重复创建和重复查询数据库,提升性能:

private Dictionary<string, RepositoryItemLookUpEdit> _cityEditorsCache = new Dictionary<string, RepositoryItemLookUpEdit>();
private SqlConnection con; // 确保你的数据库连接已正确初始化

步骤2:修改CellValueChanged事件

原来的事件里直接给列设置编辑器的逻辑要改掉,改成刷新当前行,触发编辑器重新分配:

private void gridView4_CellValueChanged(object sender, DevExpress.XtraGrid.Views.Base.CellValueChangedEventArgs e)
{
    if (e.Column.Caption == "country")
    {
        // 修改国家后,刷新当前行的城市列编辑器
        gridView4.RefreshRow(e.RowHandle);
    }
}

步骤3:实现CustomRowCellEdit事件

这个事件是核心,它会在每个单元格需要显示编辑器时触发,我们在这里根据当前行的国家值,动态分配对应的城市下拉编辑器:

private void gridView4_CustomRowCellEdit(object sender, DevExpress.XtraGrid.Views.Grid.CustomRowCellEditEventArgs e)
{
    // 只处理城市列(这里的"il"是你的城市列字段名,要和实际一致)
    if (e.Column.FieldName != "il") return;

    GridView view = sender as GridView;
    // 获取当前行的国家ID(这里的"country"要对应你数据源中国家ID的字段名,不是显示的国家名称)
    object countryIdObj = view.GetRowCellValue(e.RowHandle, "country");
    if (countryIdObj == null || countryIdObj == DBNull.Value)
    {
        e.RepositoryItem = null;
        return;
    }
    string countryId = countryIdObj.ToString();

    // 如果缓存里没有这个国家的编辑器,就创建并缓存
    if (!_cityEditorsCache.ContainsKey(countryId))
    {
        // 使用参数化查询,绝对不要用字符串拼接!避免SQL注入
        string sqlquery2 = @"SELECT [ObjID] as ObjID, [CityName] as CityName 
                             FROM [NPDB].[dbo].[YN_Cities] 
                             WHERE [Active]=1 AND [CountryID]=@CountryID 
                             ORDER BY [CityName] ASC";
        SqlDataAdapter da2 = new SqlDataAdapter(sqlquery2, con);
        da2.SelectCommand.Parameters.AddWithValue("@CountryID", countryId);
        
        DataTable dt_iller = new DataTable();
        da2.Fill(dt_iller);

        RepositoryItemLookUpEdit illookup = new RepositoryItemLookUpEdit();
        illookup.DataSource = dt_iller;
        illookup.ValueMember = "ObjID";
        illookup.DisplayMember = "CityName";
        illookup.BestFitMode = DevExpress.XtraEditors.Controls.BestFitMode.BestFitResizePopup;
        illookup.SearchMode = DevExpress.XtraEditors.Controls.SearchMode.AutoComplete;
        illookup.AutoSearchColumnIndex = 1;
        illookup.AutoHeight = false;
        illookup.DropDownRows = 10;
        illookup.NullText = string.Empty;
        illookup.PopulateColumns();

        foreach (LookUpColumnInfo col in illookup.Columns)
        {
            if (col.FieldName == "ObjID") col.Visible = false;
            if (col.FieldName == "CityName") col.Caption = "City Name";
        }

        // 把编辑器添加到GridControl的RepositoryItems中,防止被GC回收
        gridControl4.RepositoryItems.Add(illookup);
        _cityEditorsCache.Add(countryId, illookup);
    }

    // 给当前单元格分配对应的编辑器
    e.RepositoryItem = _cityEditorsCache[countryId];
}

关键说明

  1. 编辑器缓存:用_cityEditorsCache存储每个国家对应的下拉编辑器,同一个国家的行共用一个编辑器,避免重复创建和数据库查询,性能更好。
  2. 参数化查询:替换了原来的字符串拼接SQL,彻底避免SQL注入风险,这是必须的安全规范。
  3. 动态分配编辑器:通过CustomRowCellEdit事件,每行的城市单元格都会根据自己的国家值获取对应的编辑器,实现了每行独立的城市列表。
  4. 刷新触发:修改国家后调用RefreshRow,确保当前行的城市编辑器立即更新,不需要手动刷新整个网格。

注意事项

  • 确保GetRowCellValue中使用的字段名是你数据源里存储国家ID的字段(不是显示的国家名称),如果你的国家列存的是名称,要调整SQL里的条件为CountryName=@CountryName。
  • 如果你的数据源是绑定的DataTable,确保国家列的数值类型和SQL里的CountryID类型匹配,避免参数类型错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 23:39:05