Breaking Change T1248504
Visible to All Users

ComboBox, TagBox - The DataAsync property is not updated on every component re-render

What Changed

In v23.2 and earlier, data is reinitialized on every component re-render when you use the DataAsync property to bind the ComboBox/TagBox to data. For example, when you use the DataAsync property in cascading components:

Razor
<DxComboBox Data="FirstDataSource" ValueFieldName="@nameof(MyModel.ID)" TextFieldName="@nameof(MyModel.Name)" @bind-Value="@FirstValue" /> <DxComboBox DataAsync="(cancellationToken) => LoadDataAsync(FirstValue, cancellationToken)" ValueFieldName="@nameof(MyModel.ID)" TextFieldName="@nameof(MyModel.Name)" @bind-Value="@SecondValue" /> @code { 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); } }

In v24.1, ComboBox/TagBox does not fetch data on re-render. If you need to force the component to fetch data, use one of the following approaches:

  • Set a key and update it when you need to update data
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); } }
  • Use the Data property instead of the DataAsync delegate
Razor
<DxComboBox Data="FirstDataSource"             ValueFieldName="@nameof(MyModel.ID)"             TextFieldName="@nameof(MyModel.Name)"             Value="@FirstValue"             ValueChanged="@(async (int? value) => await OnValueChanged(value))" /> <DxComboBox Data=@SecondDataSource             ValueFieldName="@nameof(MyModel.ID)"             TextFieldName="@nameof(MyModel.Name)"             @bind-Value="@SecondValue" /> @code {     IEnumerable<MyModel> FirstDataSource { get; set; }     IEnumerable<string> SecondDataSource { 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>> LoadDataAsyncCore(CancellationToken cancellationToken = default(CancellationToken)) {         if (!FirstValue.HasValue)             return Enumerable.Empty<string>();         return FirstDataSource.Where(i => i.ID % FirstValue == 0).Select(i => i.Name);     }     async Task OnValueChanged(int? value)  {         FirstValue = value;         await RefreshData();     }     async Task RefreshData()  {         SecondDataSource = await LoadDataAsyncCore();     } }

Reason for Change

In previous versions, ComboBox/TagBox reinitialized data on every component re-render when the DataAsync property is used. This can cause side effects and reduce performance. In the current version, you should force the ComboBox/TagBox to fetch data as needed. This approach aligns better with Blazor's architecture and helps us to improve performance.

Impact on Existing Apps

This change affects your application if you use the DataAsync property to bind the ComboBox/TagBox to data and need to update the data at runtime.

How to Update Existing Apps

Use one of the following approaches:

  • Set a key and update it when you need to update data.
  • Use the Data property instead of the DataAsync delegate.

Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.

Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.