WPF项目中Telerik GridView级联ComboBox实现求助
问题描述
我在WPF项目中使用Telerik控件,现有如下SQL Server表:
| ID | Country | Plant | Area | Machine |
|---|---|---|---|---|
| 1 | DE | MUC | BA | A |
| 2 | DE | MUC | BA | B |
| 3 | AT | VIE | BE | 1 |
| 4 | AT | VIE | BE | 2 |
希望实现Telerik GridView中的级联ComboBox功能:选择Country后自动加载对应可选的Plant,选择Plant后加载对应Area,选择Area后加载对应Machine。我已尝试多种方式但未找到解决方案,现有代码如下:
public partial class MainWindow : Window { private SqlConnection connection; private string dbName = string.Empty; public MainWindow() { InitializeComponent(); LoadData(); } private void LoadData() { try { string connectionString = "Data Source=localhost;Initial Catalog=Test_DB;Integrated Security=True"; using (SqlConnection connection = new SqlConnection(connectionString)) { connection.Open(); string query = "SELECT * FROM dbo.MachineAreas"; SqlDataAdapter adapter = new SqlDataAdapter(query, connection); DataTable dataTable = new DataTable(); adapter.Fill(dataTable); gridMachineAreas.ItemsSource = dataTable.DefaultView; } } catch (Exception ex) { MessageBox.Show("Error: " + ex.Message); } } private void GridMachineAreas_AutoGeneratingColumn(object sender, GridViewAutoGeneratingColumnEventArgs e) { switch ((e.Column as GridViewDataColumn).DataMemberBinding.Path.Path) { case "ID": var newColumn1 = new GridViewDataColumn(); newColumn1.CopyPropertiesFrom(e.Column); newColumn1.Header = "ID"; newColumn1.Width = 60; e.Column = newColumn1; break; case "Country": var newColumn2 = new GridViewComboBoxColumn(); newColumn2.CopyPropertiesFrom(e.Column); newColumn2.Header = "Country"; newColumn2.Width = 60; newColumn2.UniqueName = "Country"; newColumn2.IsComboBoxEditable = false; newColumn2.ItemsSource = MakeCountryCollection(); e.Column = newColumn2; break; case "Plant": var newColumn3 = new GridViewComboBoxColumn(); newColumn3.CopyPropertiesFrom(e.Column); newColumn3.Header = "Plant"; newColumn3.Width = 60; e.Column = newColumn3; break; case "Area": var newColumn4 = new GridViewComboBoxColumn(); newColumn4.CopyPropertiesFrom(e.Column); newColumn4.Header = "Area"; newColumn4.Width = 60; e.Column = newColumn4; break; case "Machine": var newColumn5 = new GridViewComboBoxColumn(); newColumn5.CopyPropertiesFrom(e.Column); newColumn5.Header = "Machine"; newColumn5.Width = 60; e.Column = newColumn5; break; } } private List<string> MakeCountryCollection() { List<string> countryCollection = new List<string>(); string query = "SELECT Country FROM dbo.MachineAreas Group By Country"; try { string connectionString = "Data Source=localhost;Initial Catalog=Test_DB;Integrated Security=True"; using (SqlConnection connection = new SqlConnection(connectionString)) { connection.Open(); using (SqlCommand command = new SqlCommand(query, connection)) { using (SqlDataReader reader = command.ExecuteReader()) { while (reader.Read()) { string value = reader.GetString(0); countryCollection.Add(value); } } } } } catch (Exception ex) { MessageBox.Show("Error: " + ex.Message); } return countryCollection; } }
实现方案
要实现Telerik GridView的级联ComboBox,核心是在上级ComboBox选择值变化时,动态更新下级ComboBox的数据源,同时处理GridView中每行的独立级联逻辑。
步骤1:添加各级数据源获取方法
新增三个方法,分别根据上级选择值获取对应的下级选项:
private List<string> MakePlantCollection(string country) { List<string> plantCollection = new List<string>(); string query = "SELECT DISTINCT Plant FROM dbo.MachineAreas WHERE Country = @Country"; try { string connectionString = "Data Source=localhost;Initial Catalog=Test_DB;Integrated Security=True"; using (SqlConnection connection = new SqlConnection(connectionString)) { connection.Open(); using (SqlCommand command = new SqlCommand(query, connection)) { command.Parameters.AddWithValue("@Country", country); using (SqlDataReader reader = command.ExecuteReader()) { while (reader.Read()) { plantCollection.Add(reader.GetString(0)); } } } } } catch (Exception ex) { MessageBox.Show("Error: " + ex.Message); } return plantCollection; } private List<string> MakeAreaCollection(string plant) { List<string> areaCollection = new List<string>(); string query = "SELECT DISTINCT Area FROM dbo.MachineAreas WHERE Plant = @Plant"; try { string connectionString = "Data Source=localhost;Initial Catalog=Test_DB;Integrated Security=True"; using (SqlConnection connection = new SqlConnection(connectionString)) { connection.Open(); using (SqlCommand command = new SqlCommand(query, connection)) { command.Parameters.AddWithValue("@Plant", plant); using (SqlDataReader reader = command.ExecuteReader()) { while (reader.Read()) { areaCollection.Add(reader.GetString(0)); } } } } } catch (Exception ex) { MessageBox.Show("Error: " + ex.Message); } return areaCollection; } private List<string> MakeMachineCollection(string area) { List<string> machineCollection = new List<string>(); string query = "SELECT DISTINCT Machine FROM dbo.MachineAreas WHERE Area = @Area"; try { string connectionString = "Data Source=localhost;Initial Catalog=Test_DB;Integrated Security=True"; using (SqlConnection connection = new SqlConnection(connectionString)) { connection.Open(); using (SqlCommand command = new SqlCommand(query, connection)) { command.Parameters.AddWithValue("@Area", area); using (SqlDataReader reader = command.ExecuteReader()) { while (reader.Read()) { machineCollection.Add(reader.GetString(0)); } } } } } catch (Exception ex) { MessageBox.Show("Error: " + ex.Message); } return machineCollection; }
步骤2:绑定ComboBox选择变化事件
修改GridMachineAreas_AutoGeneratingColumn方法,为每个ComboBoxColumn绑定SelectionChanged事件,并设置显示和值路径:
private void GridMachineAreas_AutoGeneratingColumn(object sender, GridViewAutoGeneratingColumnEventArgs e) { switch ((e.Column as GridViewDataColumn).DataMemberBinding.Path.Path) { case "ID": var newColumn1 = new GridViewDataColumn(); newColumn1.CopyPropertiesFrom(e.Column); newColumn1.Header = "ID"; newColumn1.Width = 60; e.Column = newColumn1; break; case "Country": var newColumn2 = new GridViewComboBoxColumn(); newColumn2.CopyPropertiesFrom(e.Column); newColumn2.Header = "Country"; newColumn2.Width = 60; newColumn2.UniqueName = "Country"; newColumn2.IsComboBoxEditable = false; newColumn2.ItemsSource = MakeCountryCollection(); newColumn2.DisplayMemberPath = "."; newColumn2.SelectedValuePath = "."; newColumn2.SelectionChanged += CountryComboBox_SelectionChanged; e.Column = newColumn2; break; case "Plant": var newColumn3 = new GridViewComboBoxColumn(); newColumn3.CopyPropertiesFrom(e.Column); newColumn3.Header = "Plant"; newColumn3.Width = 60; newColumn3.DisplayMemberPath = "."; newColumn3.SelectedValuePath = "."; newColumn3.SelectionChanged += PlantComboBox_SelectionChanged; e.Column = newColumn3; break; case "Area": var newColumn4 = new GridViewComboBoxColumn(); newColumn4.CopyPropertiesFrom(e.Column); newColumn4.Header = "Area"; newColumn4.Width = 60; newColumn4.DisplayMemberPath = "."; newColumn4.SelectedValuePath = "."; newColumn4.SelectionChanged += AreaComboBox_SelectionChanged; e.Column = newColumn4; break; case "Machine": var newColumn5 = new GridViewComboBoxColumn(); newColumn5.CopyPropertiesFrom(e.Column); newColumn5.Header = "Machine"; newColumn5.Width = 60; newColumn5.DisplayMemberPath = "."; newColumn5.SelectedValuePath = "."; e.Column = newColumn5; break; } }
步骤3:实现级联逻辑
在选择变化事件中,获取当前行数据,更新下级数据源并重置更下级的选择:
private void CountryComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { var comboBox = sender as RadComboBox; var rowData = comboBox.DataContext as DataRowView; if (rowData == null) return; string selectedCountry = comboBox.SelectedValue as string; var plantColumn = gridMachineAreas.Columns["Plant"] as GridViewComboBoxColumn; if (plantColumn != null) { rowData.Row["Plant"] = null; plantColumn.ItemsSource = MakePlantCollection(selectedCountry); } // 重置Area和Machine var areaColumn = gridMachineAreas.Columns["Area"] as GridViewComboBoxColumn; var machineColumn = gridMachineAreas.Columns["Machine"] as GridViewComboBoxColumn; if (areaColumn != null) { rowData.Row["Area"] = null; areaColumn.ItemsSource = null; } if (machineColumn != null) { rowData.Row["Machine"] = null; machineColumn.ItemsSource = null; } } private void PlantComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { var comboBox = sender as RadComboBox; var rowData = comboBox.DataContext as DataRowView; if (rowData == null) return; string selectedPlant = comboBox.SelectedValue as string; var areaColumn = gridMachineAreas.Columns["Area"] as GridViewComboBoxColumn; if (areaColumn != null) { rowData.Row["Area"] = null; areaColumn.ItemsSource = MakeAreaCollection(selectedPlant); } // 重置Machine var machineColumn = gridMachineAreas.Columns["Machine"] as GridViewComboBoxColumn; if (machineColumn != null) { rowData.Row["Machine"] = null; machineColumn.ItemsSource = null; } } private void AreaComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { var comboBox = sender as RadComboBox; var rowData = comboBox.DataContext as DataRowView; if (rowData == null) return; string selectedArea = comboBox.SelectedValue as string; var machineColumn = gridMachineAreas.Columns["Machine"] as GridViewComboBoxColumn; if (machineColumn != null) { rowData.Row["Machine"] = null; machineColumn.ItemsSource = MakeMachineCollection(selectedArea); } }
额外说明
- 使用参数化查询避免SQL注入,同时保证查询准确性;
- 清空下级选择是为了避免出现与上级不匹配的无效数据;
- 如果需要支持新增行的级联,可在
GridViewAddingNewDataItem事件中初始化第一级ComboBox的数据源,逻辑与现有代码一致。
内容的提问来源于stack exchange,提问作者eifeltarzan
相关产品推荐
相关产品推荐

