Back to Devexpress

Cascading Comboboxes

blazor-405363-components-data-editors-combobox-cascading-combobox.md

latest5.9 KB
Original Source

Cascading Comboboxes

  • Jan 20, 2026
  • 3 minutes to read

YouTube video

The <DxComboBox> allows you to create cascade lists - populate one ComboBox with items based on the user selection from another ComboBox. Use the Value property to access the selected item. To respond to the selected item change, handle the ValueChanged event.

razor
@using CountryCityData

<div class="row cw-480">
    <div class="col-md-6">
        <label for="cbCountryName" class="mb-1">
            Country Name
        </label>
        <DxComboBox Data="@Countries"
                    TextFieldName="@nameof(Country.CountryName)"
                    Value="@CurrentCountry"
                    ValueChanged="@((Country country) => SelectedCountryChanged(country))"
                    AllowUserInput="true">
                    InputId="cbCountryName">
        </DxComboBox>
    </div>
    <div class="col-md-6">
        <label for="cbCityName" class="mb-1">
            City Name
        </label>
        <DxComboBox Data="@CurrentCountryCities"
                    TextFieldName="@nameof(City.CityName)"
                    @bind-Value="@CurrentCity"
                    AllowUserInput="true"
                    InputId="cbCityName" >
        </DxComboBox>
    </div>
</div>

@code {
    List<Country> Countries { get; set; } = CountryData.Countries;
    List<City> CurrentCountryCities { get; set; } = new List<City>();
    Country CurrentCountry { get; set; } = CountryData.Countries[1];
    City CurrentCity { get; set; } = CityData.Cities[4];

    protected override void OnInitialized() {
        base.OnInitialized();
        SelectedCountryChanged(CurrentCountry);
    }

    void SelectedCountryChanged(Country country) {
        CurrentCountry = country;
        CurrentCountryCities = CityData.Cities.FindAll(city => city.CountryId == CurrentCountry.Id);
        CurrentCity = CurrentCountryCities[0];
    }
}
csharp
namespace CountryCityData {
    public class City {
        public int Id { get; set; }
        public int CountryId { get; set; }
        public string CityName { get; set; }
    }

    public static class CityData {
        private static readonly Lazy<List<City>> cities = new Lazy<List<City>>(() => {
            return new List<City>() {
            new City() { Id = 0, CountryId = 0, CityName = "Washington" },
            new City() { Id = 1, CountryId = 0, CityName = "New York" },
            new City() { Id = 2, CountryId = 0, CityName = "Los Angeles" },
            new City() { Id = 3, CountryId = 1, CityName = "Berlin" },
            new City() { Id = 4, CountryId = 1, CityName = "Munich" },
            new City() { Id = 5, CountryId = 1, CityName = "Hamburg" },
            new City() { Id = 6, CountryId = 2, CityName = "Tokyo" },
            new City() { Id = 7, CountryId = 2, CityName = "Osaka" },
            new City() { Id = 8, CountryId = 2, CityName = "Yokohama" }
        };
        });
        public static List<City> Cities { get { return cities.Value; } }
    }
    public class Country {
        public int Id { get; set; }
        public string CountryName { get; set; }
    }

    public static class CountryData {
        private static readonly Lazy<List<Country>> countries = new Lazy<List<Country>>(() => {
            return new List<Country>()
                {
            new Country() { Id = 0, CountryName = "USA" },
            new Country() { Id = 1, CountryName = "Germany" },
            new Country() { Id = 2, CountryName = "Japan" }
        };
        });
        public static List<Country> Countries { get { return countries.Value; } }
    }
}

If you use the DataAsync or CustomData property to bind cascading ComboBoxes to data, you need to set a key to force the component to fetch data on re-render, or use the Data property instead of the DataAsync delegate. Refer to this breaking change for additional information.

razor
<DxComboBox Data="FirstDataSource"
            ValueFieldName="@nameof(MyModel.ID)"
            TextFieldName="@nameof(MyModel.Name)"
            Value="@FirstValue" 
            ValueChanged="@((int? value) => { FirstValue = value; keyValue++;})" />

<DxComboBox @key=@keyValue
            DataAsync="(cancellationToken) => LoadDataAsync(FirstValue, cancellationToken)"
            ValueFieldName="@nameof(MyModel.ID)"
            TextFieldName="@nameof(MyModel.Name)"
            @bind-Value="@SecondValue" />

@code {
   int keyValue;
   IEnumerable<MyModel> FirstDataSource { get; set; }
   int? FirstValue { get; set; }
   string? SecondValue { get; set; }
   public class MyModel {
       public int ID { get; set; }
       public string Name { get; set; }
   }
   protected override void OnInitialized() {
       FirstDataSource = Enumerable.Range(0, 10).Select(i => new MyModel() { ID = i, Name = $"Name {i}" });        
   }
   public async Task<IEnumerable<string>> LoadDataAsync(int? value, CancellationToken cancellationToken = default(CancellationToken)) {
       if(!value.HasValue)
           return Enumerable.Empty<string>();
       return FirstDataSource.Where(i => i.ID % value == 0).Select(i => i.Name);
   }
}

Run Demo: ComboBox - Cascading Lists View Example: Grid - Implement Cascading ComboBoxes