New to Telerik UI for WinForms? Download free 30-day trial

Cascading ComboBoxes in RadGridView

Product Version Product Author Last modified
2012.3.1017 RadGridView for WinForms Stefan Stefanov Dec 15, 2012

HOW-TO

This article demonstrates how you can implement the popular 'cascading combos' scenario where the range of options available in a drop-down list of a combo column depend on the choice made by the end-user in another combo column for the same row.

SOLUTION

1.Lets create two classes that are going to be used in this example. The first is called FoodType and the other one is Food. As the classes names imply, we will have two combo boxes - the first will allow choosing the type of the food (i.e. Fruits and Vegetables) and the second will allow for choosing the food itself (i.e Cucumbers, Bananas etc):

public class FoodType
{
    private int foodTypeID;
    private string foodType;

    public FoodType(int foodTypeID, string foodType)
    {
        this.foodTypeID = foodTypeID;
        this.foodType = foodType;
    }

    public int FoodTypeID
    {
        get { return foodTypeID; }
        set { foodTypeID = value; }
    }

    public string FoodTypeName
    {
        get { return foodType; }
        set { foodType = value; }
    }
}

public class Food
{
    private int foodID;
    private string foodName;

    public Food(int foodID, string foodName)
    {
        this.foodID = foodID;
        this.foodName = foodName;
    }

    public int FoodID
    {
        get { return foodID; }
        set { foodID = value; }
    }

    public string FoodName
    {
        get { return foodName; }
        set { foodName = value; }
    }
}

Public Class FoodType
    Private foodTypeID As Integer
    Private foodType As String

    Public Sub New(ByVal foodTypeID As Integer, ByVal foodType As String)
        Me.foodTypeID = foodTypeID
        Me.foodType = foodType
    End Sub

    Public Property FoodTypeID As Integer
        Get
            Return foodTypeID
        End Get
        Set(ByVal value As Integer)
            foodTypeID = value
        End Set
    End Property

    Public Property FoodTypeName As String
        Get
            Return foodType
        End Get
        Set(ByVal value As String)
            foodType = value
        End Set
    End Property
End Class

Public Class Food
    Private foodID As Integer
    Private foodName As String

    Public Sub New(ByVal foodID As Integer, ByVal foodName As String)
        Me.foodID = foodID
        Me.foodName = foodName
    End Sub

    Public Property FoodID As Integer
        Get
            Return foodID
        End Get
        Set(ByVal value As Integer)
            foodID = value
        End Set
    End Property

    Public Property FoodName As String
        Get
            Return foodName
        End Get
        Set(ByVal value As String)
            foodName = value
        End Set
    End Property
End Class


2.Create three BindingLists (as fields) that will hold the necessary data and populate them

BindingList<Food> fullList;
BindingList<Food> fruitsList;
BindingList<Food> vegetablesList;

public Form1()
{
    InitializeComponent();

    fullList = new BindingList<Food>();
    fullList.Add(new Food(0, "Onion"));
    fullList.Add(new Food(1, "Cucumber"));
    fullList.Add(new Food(2, "Tomato"));
    fullList.Add(new Food(3, "Peach"));
    fullList.Add(new Food(4, "Banana"));
    fullList.Add(new Food(5, "Grape"));

    fruitsList = new BindingList<Food>();
    fruitsList.Add(fullList[3]);
    fruitsList.Add(fullList[4]);
    fruitsList.Add(fullList[5]);

    vegetablesList = new BindingList<Food>();
    vegetablesList.Add(fullList[0]);
    vegetablesList.Add(fullList[1]);
    vegetablesList.Add(fullList[2]);

    BindingList<FoodType> typesList = new BindingList<FoodType>();
    typesList.Add(new FoodType(0, "Vegetables"));
    typesList.Add(new FoodType(1, "Fruits"));

    GridViewComboBoxColumn foodType = new GridViewComboBoxColumn();
    foodType.FieldName = "FoodType";
    this.radGridView1.Columns.Add(foodType);
    foodType.DataSource = typesList;
    foodType.Width = 100;
    foodType.DisplayMember = "FoodTypeName";
    foodType.ValueMember = "FoodTypeID";

    GridViewComboBoxColumn food = new GridViewComboBoxColumn();
    food.FieldName = "Food";
    this.radGridView1.Columns.Add(food);
    food.DataSource = fullList;
    food.Width = 100;
    food.DisplayMember = "FoodName";
    food.ValueMember = "FoodID";
}

    Private fullList As BindingList(Of Food)
    Private fruitsList As BindingList(Of Food)
    Private vegetablesList As BindingList(Of Food)

    Public Sub New()
        InitializeComponent()
        fullList = New BindingList(Of Food)()
        fullList.Add(New Food(0, "Onion"))
        fullList.Add(New Food(1, "Cucumber"))
        fullList.Add(New Food(2, "Tomato"))
        fullList.Add(New Food(3, "Peach"))
        fullList.Add(New Food(4, "Banana"))
        fullList.Add(New Food(5, "Grape"))
        fruitsList = New BindingList(Of Food)()
        fruitsList.Add(fullList(3))
        fruitsList.Add(fullList(4))
        fruitsList.Add(fullList(5))
        vegetablesList = New BindingList(Of Food)()
        vegetablesList.Add(fullList(0))
        vegetablesList.Add(fullList(1))
        vegetablesList.Add(fullList(2))
        Dim typesList As BindingList(Of FoodType) = New BindingList(Of FoodType)()
        typesList.Add(New FoodType(0, "Vegetables"))
        typesList.Add(New FoodType(1, "Fruits"))
        Dim foodType As GridViewComboBoxColumn = New GridViewComboBoxColumn()
        foodType.FieldName = "FoodType"
        Me.radGridView1.Columns.Add(foodType)
        foodType.DataSource = typesList
        foodType.Width = 100
        foodType.DisplayMember = "FoodTypeName"
        foodType.ValueMember = "FoodTypeID"
        Dim food As GridViewComboBoxColumn = New GridViewComboBoxColumn()
        food.FieldName = "Food"
        Me.radGridView1.Columns.Add(food)
        food.DataSource = fullList
        food.Width = 100
        food.DisplayMember = "FoodName"
        food.ValueMember = "FoodID"
    End Sub

3.Create the GridViewComboBoxColumn columns and make their settings. The first column is responsible for the food types, while the second for the food according to the food type:

GridViewComboBoxColumn foodType = new GridViewComboBoxColumn();
foodType.FieldName = "FoodType";
this.radGridView1.Columns.Add(foodType);
foodType.DataSource = typesList;
foodType.Width = 100;
foodType.DisplayMember = "FoodTypeName";
foodType.ValueMember = "FoodTypeID";

GridViewComboBoxColumn food = new GridViewComboBoxColumn();
food.FieldName = "Food";
this.radGridView1.Columns.Add(food);
food.DataSource = fullList;
food.Width = 100;
food.DisplayMember = "FoodName";
food.ValueMember = "FoodID";

Dim foodType As GridViewComboBoxColumn = New GridViewComboBoxColumn()
foodType.FieldName = "FoodType"
Me.radGridView1.Columns.Add(foodType)
foodType.DataSource = typesList
foodType.Width = 100
foodType.DisplayMember = "FoodTypeName"
foodType.ValueMember = "FoodTypeID"
Dim food As GridViewComboBoxColumn = New GridViewComboBoxColumn()
food.FieldName = "Food"
Me.radGridView1.Columns.Add(food)
food.DataSource = fullList
food.Width = 100
food.DisplayMember = "FoodName"
food.ValueMember = "FoodID"

4.Last subscribe for the CellEditorInitialized event of RadGridView, where modifications for the dynamic editor will be placed:

void radGridView1_CellEditorInitialized(object sender, Telerik.WinControls.UI.GridViewCellEventArgs e)
{
    if (e.Column.HeaderText == "Food")
    {
        if (this.radGridView1.CurrentRow.Cells["FoodType"].Value != DBNull.Value
            && this.radGridView1.CurrentRow.Cells["FoodType"].Value != null)
        {
            RadDropDownListEditor editor = (RadDropDownListEditor)this.radGridView1.ActiveEditor;
            RadDropDownListEditorElement editorElement = (RadDropDownListEditorElement)editor.EditorElement;
            if (int.Parse(this.radGridView1.CurrentRow.Cells["FoodType"].Value.ToString()) == 0)
            {
                editorElement.DataSource = vegetablesList;
            }
            else
            {
                editorElement.DataSource = fruitsList;
            }
            editorElement.SelectedValue = null;
            editorElement.SelectedValue = this.radGridView1.CurrentCell.Value;
        }
    }
}
Private Sub radGridView1_CellEditorInitialized(ByVal sender As Object, ByVal e As Telerik.WinControls.UI.GridViewCellEventArgs)
    If e.Column.HeaderText = "Food" Then

        If Me.radGridView1.CurrentRow.Cells("FoodType").Value <> DBNull.Value AndAlso Me.radGridView1.CurrentRow.Cells("FoodType").Value IsNot Nothing Then
            Dim editor As RadDropDownListEditor = CType(Me.radGridView1.ActiveEditor, RadDropDownListEditor)
            Dim editorElement As RadDropDownListEditorElement = CType(editor.EditorElement, RadDropDownListEditorElement)

            If Integer.Parse(Me.radGridView1.CurrentRow.Cells("FoodType").Value.ToString()) = 0 Then
                editorElement.DataSource = vegetablesList
            Else
                editorElement.DataSource = fruitsList
            End If

            editorElement.SelectedValue = Nothing
            editorElement.SelectedValue = Me.radGridView1.CurrentCell.Value
        End If
    End If
End Sub

5.Last, but not least, we should subscribe to the CellValueChanged event which is fired after the editing process of a cell is finished and there is a new value committed to the cell. In the CellValueChanged event handler we should check if the cell for which the value has been changed is in the column FoodType. If 'yes', this means that the value of the Food cell in the same row is not valid anymore (for example, you cannot have "Vegetable" entered for the FoodType leaving the value of the Food cell to "Apple") and we should delete it:

void radGridView1_CellValueChanged(object sender, GridViewCellEventArgs e)
{
    if (e.Column.HeaderText == "FoodType")
    {
        e.Row.Cells["Food"].Value = null;
    }
}

Private Sub radGridView1_CellValueChanged(ByVal sender As Object, ByVal e As GridViewCellEventArgs)
    If e.Column.HeaderText = "FoodType" Then
        e.Row.Cells("Food").Value = Nothing
    End If
End Sub

The result is:

cascading-comboboxes001

cascading-comboboxes002cascading-comboboxes003

You can download a complete VB and C# project from the following link.

In this article