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]; }
关键说明
- 编辑器缓存:用
_cityEditorsCache存储每个国家对应的下拉编辑器,同一个国家的行共用一个编辑器,避免重复创建和数据库查询,性能更好。 - 参数化查询:替换了原来的字符串拼接SQL,彻底避免SQL注入风险,这是必须的安全规范。
- 动态分配编辑器:通过
CustomRowCellEdit事件,每行的城市单元格都会根据自己的国家值获取对应的编辑器,实现了每行独立的城市列表。 - 刷新触发:修改国家后调用
RefreshRow,确保当前行的城市编辑器立即更新,不需要手动刷新整个网格。
注意事项
- 确保
GetRowCellValue中使用的字段名是你数据源里存储国家ID的字段(不是显示的国家名称),如果你的国家列存的是名称,要调整SQL里的条件为CountryName=@CountryName。 - 如果你的数据源是绑定的DataTable,确保国家列的数值类型和SQL里的
CountryID类型匹配,避免参数类型错误。
内容的提问来源于stack exchange,提问作者Ilhan Ates
相关产品推荐
相关产品推荐

