Creating a dropdown list in a grid cell whose list values are dependent on another cell

Mike Saltzman / Friday, May 08, 2009

Introduction

The UltraGridColumn has a ValueList property which allows you to attach a dropdown list to the column. The dropdown list may be any class that implements the IValueList interface, which includes the ValueList, BindableValueList, or UltraDropDown.

But suppose you want the list in a cell to change based on some other data in the row. For example, let’s say you have a grid populated with a list of customers. The customer address might include a “State” and a “City” field. The “State” field would be ideally suited to display a dropdown where the user can choose from a list of states. You might also want to provide the user with a dropdown list of cities in the “City” column. But since cities vary for each state, you don’t want the list to display every city, you only want the cities that are in the appropriate state for each row.

Setting up the DropDowns

In this example, you would set up the dropdowns for the grid in the InitializeLayout event. In the following code, the variable “ds” is a DataSet which contains three tables: “Customers”, “States”, and “Cities”. The grid is bound to the “Customers” table which has fields for the customers “Name”, “State”, and “City”. This code creates dropdowns for the “State” and “City” columns. These list will contain a complete list of all states and a complete list of all cities (in every state). 

private void ultraGrid1_InitializeLayout(object sender, Infragistics.Win.UltraWinGrid.InitializeLayoutEventArgs e)
{
    // Allow adding new rows.
    //
    e.Layout.Override.AllowAddNew = AllowAddNew.TemplateOnBottom;

    // Create an UltraDropDown with a list of States for the State column.
    //
    this.statesDropDown = new UltraDropDown();
    this.Controls.Add(statesDropDown);
    statesDropDown.SetDataBinding(this.ds, "States");
    statesDropDown.ValueMember = "ID";
    statesDropDown.DisplayMember = "State";

    // Create an UltraDropDown with a list of cities for the City column.
    // This dropdown will contain a complete list of all cities in all states
    // and we will filter it based on the current row so that only cities for the
    // selected state are displayed.
    //
    this.citiesDropDown = new UltraDropDown();
    this.Controls.Add(citiesDropDown);
    citiesDropDown.SetDataBinding(this.ds, "Cities");
    citiesDropDown.ValueMember = "ID";
    citiesDropDown.DisplayMember = "City";

    // Attach the dropdowns to the grid columns.
    //
    e.Layout.Bands[0].Columns["State"].ValueList = statesDropDown;
    e.Layout.Bands[0].Columns["City"].ValueList = citiesDropDown;
}

 

Filtering the list

The cities dropdown will contain a list of all cities in all states. To filter the list based on the state for the row, we will use the BeforeCellActivate event. This event fires before the cell becomes the active cell for any reason, so it will always fire before the list drops down. Here we will apply a filter to the cities dropdown so that it only displays the cities for the appropriate state, as determined by the “State” field in the grid row.

private void ultraGrid1_BeforeCellActivate(object sender, CancelableCellEventArgs e)
{
    if (e.Cell.Column.Key == "City")
    {
        // Before a cell in the City column is activated, change the filter on the
        // DropDown to only display cities in the selected State.
        UltraGridBand rootBand = this.citiesDropDown.DisplayLayout.Bands[0];
        rootBand.ColumnFilters.ClearAllFilters();
        rootBand.ColumnFilters["StateID"].FilterConditions.Add(FilterComparisionOperator.Equals, e.Cell.Row.Cells["State"].Value);
    }
}

Handling changes in the first cell

If the user changes the “State” for a particular row, the “City” field would no longer be valid, since it still contains a city from a different state. To deal with this, we will handle the AfterCellUpdate event and clear out the “City” field any time the “State” is edited.

private void ultraGrid1_AfterCellUpdate(object sender, CellEventArgs e)
{
    UltraGrid grid = (UltraGrid)sender;

    // Turn off the event to prevent recursion
    grid.EventManager.SetEnabled(GridEventIds.AfterCellUpdate, false);


    try
    {
        if (e.Cell.Column.Key == "State")
        {
            // If the State is changed, the city is no longer valid, so clear it out.
            e.Cell.Row.Cells["City"].Value = DBNull.Value;
        }
    }
    finally
    {
        // Re-enabled this event.
        grid.EventManager.SetEnabled(GridEventIds.AfterCellUpdate, true);
    }
}
WinGrid - Dependent Dropdowns CS.zip