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

WPF项目中Telerik GridView级联ComboBox实现求助

问题描述

我在WPF项目中使用Telerik控件,现有如下SQL Server表:

IDCountryPlantAreaMachine
1DEMUCBAA
2DEMUCBAB
3ATVIEBE1
4ATVIEBE2

希望实现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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 16:57:02