DxListBox<TData, TValue> Class
A component that can connect to a data source and display a list of selectable items.
Namespace: DevExpress.Blazor
Assembly: DevExpress.Blazor.v24.2.dll
NuGet Package: DevExpress.Blazor
Declaration
public class DxListBox<TData, TValue> :
DxListEditorBase<TData, TValue>,
IListBoxComponent<TData, TValue>,
IListBox<TData, TValue>,
IListEditorBase<TData, TValue>,
IEditorBase,
IListBoxAccessor<TData>,
IListEditorAccessorBase<TData>
Type Parameters
Name | Description |
---|---|
TData | The data item type. |
TValue | The value type. |
Remarks
The DevExpress List Box for Blazor (<DxListBox>
) allows you to display a list of selectable items from a data source.
Add a List Box to a Project
Follow the steps below to add a List Box component to an application:
- Use a DevExpress Project Template to create a new Blazor Server or Blazor WebAssembly application. If you use a Microsoft project template or already have a Blazor project, configure your project to incorporate DevExpress Blazor components.
- Add the
<DxListBox>
…</DxListBox>
markup to a.razor
file. - Bind the component to data.
- Configure the component: handle an item selection, customize item appearance, and so on (see sections below).
.NET 8 and .NET 9 Specifics
Blazor ListBox does not support static render mode. Enable interactivity to use the component in your application. Refer to the following topic for more details: Enable Interactive Render Mode.
Bind to Data
Strongly Typed Collection
Use the Data property to bind the List Box to a strongly typed collection. Initialize this collection in the OnInitialized lifecycle method or before this method is invoked. Use the DataAsync property instead of the Data
property if a strongly typed collection is loaded asynchronously (for instance, from an HTTP request).
Use the Value or Values property to select one or multiple List Box items programmatically. You can use the @bind attribute to bind these properties to a data field. Refer to the following topic for more information: Two-Way Data Binding.
<DxListBox Data="@Cities" @bind-Values="@Values"></DxListBox>
@code {
IEnumerable<string> Cities = new List<string>() {
"London",
"Berlin",
"Paris",
};
IEnumerable<string> Values { get; set; }
}
The List Box control can detect IQueryable collections and use benefits of the corresponding LINQ query providers (such as Entity Framework).
Custom Object Collection
You can bind the List Box to a data collection (Data
) that stores custom objects (IEnumerable<CustomType>
). The Values
collection can also contain custom objects. In this case, you need to override the following methods for your custom object:
GetHashCode(). The List Box uses hash codes to compare items. Override this method to make sure that compared objects have the same hash code.
Equals. The default
Equals
method determines whether two object instances are equal. The compared items will not be equal if they are different instances (even if they have exactly the same properties). As a result, the component will not display the selected items.
You also need to set the List Box’s TextFieldName property. It specifies the custom object’s field name that returns strings to be shown in the List Box. If the TextFieldName
property is not specified, the List Box component searches for a Text field in the data source and uses this field as a text field. Otherwise, the List Box is populated with CustomType.ToString() values.
As an alternative, you can use KeyFieldName and KeyFieldNames properties to specify which field the List Box should use as an identifier to compare items.
@using StaffData
<DxListBox Data="@Staff.DataSource"
@bind-Values="@Values"
TextFieldName="@nameof(Person.Text)">
</DxListBox>
@code {
IEnumerable<Person> Values { get; set; } = Staff.DataSource.Take(1);
}
Custom Data
When you bind an editor to data from a Web API service, assign the data type to the component’s T
parameter and use the CustomData property to implement custom data load logic.
You can also enable Virtual Scrolling to improve client-side performance.
Item Selection
Use the SelectionMode property to change the selection mode. The component supports the following modes:
- Single (default)
Users can only select one List Box item at a time. A user should click a List Box item to select it.
Use the Value property to access/specify the selected item in code. To respond to selection changes, handle the ValueChanged event.
- Multiple
Users can select multiple items in the List Box. A user should click the initial item, hold the Shift key, and select the final item to specify the range of items. To add/remove individual items to/from the selection, a user should click an item with the Ctrl key pressed. Enable the ShowCheckboxes property to allow users to use checkboxes to select items.
Use the Values property to access/specify selected items in multiple selection mode. To respond to selection changes, handle the ValuesChanged event.
- None (selection functionality is disabled)
- Users cannot select List Box items.
The following code snippet enables multiple selection in the List Box and adds checkboxes to the component. Users can click items or corresponding checkboxes to change selection.
@using StaffData
<DxListBox Data="@Staff.DataSource"
TextFieldName="@nameof(Person.Text)"
SelectionMode="ListBoxSelectionMode.Multiple"
ShowCheckboxes="true"
@bind-Values="@Values">
</DxListBox>
@code {
IEnumerable<Person> Values { get; set; }
}
Multiple Columns
The List Box control can display data across multiple columns. Follow the steps below to create columns:
- Add a
<Columns>
tag to the component’s markup to declare the column collection. Populate the
Columns
collection with DxListEditorColumn objects. These objects include the following properties:- Caption - Specifies the column’s caption text.
- FieldName - Specifies the data source field that populates column items in multi-column editors.
- SearchEnabled - Specifies whether the component can search text in cells of the current column.
- Visible - Specifies whether the column is visible.
- VisibleChanged - Fires when the column visibility changes.
- VisibleIndex - Specifies a column’s position among other columns.
- VisibleIndexChanged - Fires when the column’s visible index changes.
- Width - Specifies the column’s width.
@using StaffData
<DxListBox Data="@Staff.DataSource"
@bind-Values="@Values">
<Columns>
<DxListEditorColumn FieldName="Id" Width="50px" />
<DxListEditorColumn FieldName="FirstName" Caption="Name"/>
<DxListEditorColumn FieldName="LastName" Caption="Surname"/>
</Columns>
</DxListBox>
@code {
IEnumerable<Person> Values { get; set; } = Staff.DataSource.Take(1);
}
Group Data
The Blazor ListBox allows you to organize list items into groups. This enhance user experience by allowing users to locate required values faster. To group data, specify the GroupFieldName property. Values from the specified field appear within group headers.
Note the following specifics:
- The ListBox supports only one group level.
- Users cannot collapse groups.
- Group headers do not take part in search operations.
- Multi-column ListBox controls also support groups.
- You can use the GroupHeaderDisplayTemplate property to customize group headers.
The following code organizes data items into groups based on the Country data source field:
@inject NwindDataService NwindDataService
<DxListBox Data="@Data"
@bind-Value="@Value"
ShowSearchBox="true"
@bind-SearchText="@SearchText"
TextFieldName="@nameof(Customer.ContactName)"
GroupFieldName="@nameof(Customer.Country)">
</DxListBox>
@code {
string SearchText { get; set; }
IEnumerable<Customer> Data { get; set; }
Customer Value { get; set; }
protected override async Task OnInitializedAsync() {
Data = await NwindDataService.GetCustomersAsync();
Value = Data.FirstOrDefault(x => x.Country == "Argentina");
}
}
Virtual Scrolling
Set the ListRenderMode property to ListRenderMode.Virtual to enable virtual scrolling. In this mode, the List Box renders data on demand when a user scrolls list items.
@using StaffData
<DxListBox Data="@Staff.DataSource"
TData="Person"
TValue="Person"
ListRenderMode="ListRenderMode.Virtual">
</DxListBox>
Item Display Template
The ItemDisplayTemplate property allows you to customize the appearance of List Box items. The property accepts a ListBoxItemDisplayTemplateContext<TData> object as the context parameter. You can use the parameter’s members to get information about items:
The following code snippet displays List Box items as contact cards. Each item shows an employee’s first name, last name, photo, and phone number.
@inject NwindDataService NwindDataService
<DxListBox Data="@Data"
@bind-Value="@Value"
SizeMode="Params.SizeMode"
CssClass="cw-400 chi-220">
<ItemDisplayTemplate>
<div class="listbox-item-template">
<img src="@StaticAssetUtils.GetImagePath(GetImageFileName(context.DataItem))" alt="@context.DataItem.FullName" />
<div class="listbox-item-template-text">
<span>@context.DataItem.FullName</span>
<span class="listbox-item-template-text-phone">@context.DataItem.HomePhone</span>
</div>
</div>
</ItemDisplayTemplate>
</DxListBox>
@code {
IEnumerable<Employee> Data { get; set; }
Employee Value { get; set; }
protected override async Task OnInitializedAsync() {
Data = await NwindDataService.GetEmployeesAsync();
Value = Data.FirstOrDefault();
}
string GetImageFileName(Employee employee) {
return $"employees/item-template{employee.EmployeeId}.jpg";
}
}
Column Cell Display Template
The ColumnCellDisplayTemplate allows you to specify custom content and change cell appearance in List Box columns. The template accepts a ListBoxColumnCellDisplayTemplateContext<TData> object as the context
parameter. You can use the parameter’s members to get information about columns.
The following code snippet customizes the appearance of different columns.
@inject NwindDataService NwindDataService
<DxListBox TData="Product" TValue="Product" Data="@Data"
@bind-Values="@SelectedProducts"
SelectionMode="ListBoxSelectionMode.Multiple">
<Columns>
<DxListEditorColumn FieldName="@nameof(Product.ProductName)" Caption="Product" Width="30%"/>
<DxListEditorColumn FieldName="@nameof(Product.UnitPrice)" Caption="Unit Price"/>
<DxListEditorColumn FieldName="@nameof(Product.Quantity)"/>
<DxListEditorColumn FieldName="@nameof(Product.Discount)"/>
<DxListEditorColumn FieldName="@nameof(Product.Total)" />
</Columns>
<ColumnCellDisplayTemplate>
@{
object displayValue;
string cssClass = string.Empty;
switch (context.Column.FieldName) {
case nameof(Product.UnitPrice):
cssClass = alignRightCssClass;
displayValue = $"{context.Value:c}";
break;
case nameof(Product.Quantity):
cssClass = alignRightCssClass;
displayValue = context.DisplayText;
break;
case nameof(Product.Discount):
displayValue = $"{context.Value:p}";
break;
case nameof(Product.Total):
var value = context.DataItem.UnitPrice * context.DataItem.Quantity;
var valueCssClass = value >= totalPriceCeiling ? textGreenCssClass : textRedCssClass;
cssClass = $"{alignRightCssClass} {valueCssClass}";
displayValue = $"{value:c}";
break;
default:
displayValue = context.DisplayText;
break;
}
}
<div class="@cssClass">@displayValue</div>
</ColumnCellDisplayTemplate>
</DxListBox>
@code {
IEnumerable<Product> Data { get; set; }
IEnumerable<Product> SelectedProducts { get; set; }
int totalPriceCeiling = 100;
string alignRightCssClass = "align-right";
string textGreenCssClass = "text-green";
string textRedCssClass = "text-red";
protected override async Task OnInitializedAsync() {
var invoices = await NwindDataService.GetInvoicesAsync();
var products = await NwindDataService.GetProductsAsync();
Data = invoices.Join(products, i => i.ProductId, p => p.ProductId, (i, p) =>
new Product {
ProductName = i.ProductName,
UnitPrice = i.UnitPrice,
Quantity = i.Quantity,
Discount = i.Discount
}
);
SelectedProducts = Data.Skip(1).Take(3);
}
public class Product {
public string ProductName { get; set; }
public decimal UnitPrice { get; set; }
public int Quantity { get; set; }
public float Discount { get; set; }
public int Total { get; set; }
public override bool Equals(object obj) {
return obj is Product product && string.Equals(product.ProductName, ProductName) && product.Quantity == Quantity;
}
public override int GetHashCode() {
return HashCode.Combine(ProductName, Quantity);
}
}
}
Empty Data Area Template
The List Box displays an empty data area in the following cases:
- The Data property is unset.
- The specified data source does not contain items.
- You use the DataAsync property or the CustomData property to bind the List Box to a data source. The component sends the first request to a remote data source and waits for a response.
Use the EmptyDataAreaTemplate to customize content displayed in the empty data area. The template’s context
parameter has the IsDataLoading property that allows you to determine whether the List Box data is still loading data.
The following code snippet embeds the Wait Indicator component into the List Box.
@inject NwindDataService NwindDataService
<DxListBox TData="@WebApiLookup" TValue="string"
ListRenderMode="ListRenderMode.Virtual"
CssClass="cw-400 chi-220"
CustomData="@LoadCustomData"
@key="ComponentKey">
<EmptyDataAreaTemplate>
@if (context.IsDataLoading) {
<div class="empty-data-area-template">
<div class="d-flex flex-column">
<DxWaitIndicator Visible="true"
CssClass="m-auto"
AnimationType="WaitIndicatorAnimationType.Spin" />
<p class="dxbl-text d-block mt-1">Loading, please wait...</p>
</div>
</div>
}
</EmptyDataAreaTemplate>
</DxListBox>
@code {
[Inject] protected HttpClient Client { get; set; }
Guid ComponentKey { get; set; } = Guid.NewGuid();
async Task<LoadResult> LoadCustomData(DataSourceLoadOptionsBase options, CancellationToken cancellationToken) {
using var response = await Client.GetAsync(options.ConvertToGetRequestUri
("https://js.devexpress.com/Demos/NetCore/api/DataGridWebApi/CustomersLookup"), cancellationToken);
response.EnsureSuccessStatusCode();
if(options.RequireTotalCount)
await Task.Delay(3000, cancellationToken);
using var responseStream = await response.Content.ReadAsStreamAsync();
var result = await JsonSerializer.DeserializeAsync<LoadResult>(responseStream, cancellationToken: cancellationToken);
return result;
}
void ReloadListBox() {
ComponentKey = Guid.NewGuid();
}
public class WebApiLookup {
public string Text { get; set; }
public string Value { get; set; }
}
}
Search and Filter Data
The Blazor List Box ships with API members that allow you to use search and filter capabilities.
Search Box
Use the ShowSearchBox property to display the search box in the List Box component. Once a user enters the text in the search box, the List Box looks for rows with matching values, highlights search results, and filters out all other rows. Search is case-insensitive and applies to cells in visible columns only.
<DxListBox TData=Person TValue=Person Data="Staff.DataSource"
ShowSearchBox="true"
ShowCheckboxes="true"
SelectionMode="@ListBoxSelectionMode.Multiple">
<Columns>
<DxListEditorColumn FieldName="FirstName"></DxListEditorColumn>
<DxListEditorColumn FieldName="LastName"></DxListEditorColumn>
<DxListEditorColumn FieldName="Department"></DxListEditorColumn>
</Columns>
</DxListBox>
@code {
public string SearchText { get; set; }
}
Search Text
You can use the SearchText property to specify the search text in code. Refer to Search Syntax.
<DxListBox TData=Person TValue=Person Data="Staff.DataSource"
ShowCheckboxes="true"
SearchText="Sa"
SelectionMode="@ListBoxSelectionMode.Multiple">
<Columns>
<DxListEditorColumn FieldName="FirstName"></DxListEditorColumn>
<DxListEditorColumn FieldName="LastName"></DxListEditorColumn>
<DxListEditorColumn FieldName="Department"></DxListEditorColumn>
</Columns>
</DxListBox>
To respond to search text changes, handle the SearchTextChanged event. The event is handled automatically when you use two-way data binding for the SearchText property (@bind-SearchText
).
Set a column’s SearchEnabled property to false
to exclude a specific column from search operations.
If the search text contains multiple words separated by space characters, the words can be treated as a single condition or individual conditions based on the SearchTextParseMode property value.
Filter Criteria
The List Box allows you to filter its data in code. You can create a criteria operator object that specifies the filter expression and pass this object to the SetFilterCriteria(CriteriaOperator) method. To get the applied filter criteria, use the GetFilterCriteria() method.
For more information about criteria operators, see the following topics:
When a filter is applied, the List Box raises the FilterCriteriaChanged event.
You can call the ClearFilter() method to clear any previously applied filters and apply a new filter to list box data.
The following code creates a toolbar that allows you to apply filter criteria to List Box data and clear filter.
<DxToolbar ItemClick="@OnItemClick">
<Items>
<DxToolbarItem Name="_setFilterCriteria" Text="Set Filter Criteria" Tooltip="Set Filter Criteria" />
<DxToolbarItem Name="_clearFilterCriteria" Text="Clear Filter Criteria" Tooltip="Clear Filter Criteria" />
</Items>
</DxToolbar>
<br/>
<DxListBox @ref="@_listBox" TData=Person TValue=Person Data="Staff.DataSource"
ShowCheckboxes="true"
SelectionMode="@ListBoxSelectionMode.Multiple">
<Columns>
<DxListEditorColumn FieldName="FirstName"></DxListEditorColumn>
<DxListEditorColumn FieldName="LastName"></DxListEditorColumn>
<DxListEditorColumn FieldName="Department"></DxListEditorColumn>
<DxListEditorColumn FieldName="Salary"></DxListEditorColumn>
</Columns>
</DxListBox>
<p class="cw-480 mt-3">
Filter Criteria: <b>@_listBox?.GetFilterCriteria()?.ToString()</b>
</p>
@code {
IListBox<Person, Person> _listBox;
void OnItemClick(ToolbarItemClickEventArgs e) {
switch(e.ItemName) {
case "_setFilterCriteria":
_listBox.SetFilterCriteria(new BinaryOperator(nameof(Person.Salary), 2000, BinaryOperatorType.Greater));
break;
case "_clearFilterCriteria":
_listBox.ClearFilter();
break;
}
}
}
Disabled Items
You can disable individual items in the List Box. To do this, use the DisabledFieldName property. The property specifies a Boolean field that stores each item’s enabled or disabled state. Disabled items are grayed out and cannot be selected.
Note
Disabled items can improve component usability, but cannot replace adequate security measures. Users may still be able to select disabled items on the client side, so you should implement appropriate security checks in your code.
@inject NwindDataService NwindDataService
<DxListBox Data="@Products"
@bind-Values="@SelectedProducts"
TextFieldName="@nameof(Product.ProductName)"
DisabledFieldName="@nameof(Product.Discontinued)"
SelectionMode="ListBoxSelectionMode.Multiple"
CssClass="cw-400 chi-220">
</DxListBox>
@code {
IEnumerable<Product> Products { get; set; }
IEnumerable<Product> SelectedProducts { get; set; }
protected override async Task OnInitializedAsync() {
Products = await NwindDataService.GetProductsAsync();
SelectedProducts = Products.Take(1);
}
}
Input Validation
You can add a standalone List Box or the corresponding Form Layout component to the Blazor’s standard EditForm. This form validates user input based on data annotation attributes defined in a model and indicates errors.
<EditForm Model="@model" Context="EditFormContext">
<DataAnnotationsValidator />
<DxFormLayout >
<DxFormLayoutItem Caption="Values:" ColSpanMd="6" >
<DxListBox Data="@(new List<string>() { "Defense", "Exploration", "Diplomacy" })"
@bind-Values="@model.Values" />
</DxFormLayoutItem >
@*...*@
</DxFormLayout>
</EditForm>
@code {
private Model model=new Model();
}
If you handle the ValueChanged
event and cannot use two-way binding, specify the ValueExpression or ValuesExpression property to identify the value passed to the event handler.
For more information, refer to the following help topic: Validate Input.
Keyboard Navigation
The DevExpress Blazor List Box supports keyboard navigation. Users can navigate through List Box items and select them.
When a user focuses the List Box component, the first selected item or first selected row (in multiple columns mode) is focused.
The following shortcut keys are available:
Shortcut Keys | Description |
---|---|
Tab, Shift + Tab | When the List Box is focused, moves focus to the next/previous focusable element on a page. |
Up Arrow | Moves focus one item up. |
Down Arrow | Moves focus one item down. |
Home | Moves focus to the first item or the first row (in multiple columns mode). |
End | Moves focus to the last item or the last row (in multiple columns mode). |
Page Up | Moves focus to the previous item page. |
Page Down | Moves focus to the next item page. |
Enter | If the focused item contains an ItemDisplayTemplate or a ColumnCellDisplayTemplate, moves focus to the first element in the template. Users can use Tab to navigate through inner elements (buttons, links, etc.). |
Space | Selects the focused item/row, deselects previously selected items/rows. Updates Value and Values parameter values. |
Shift + Space | In multiple selection mode, selects a range of items between the previously selected item and the focused item. |
Ctrl + Shift + Home | In multiple selection mode, selects the focused item and all items above it, focuses the first item. |
Ctrl + Shift + End | In multiple selection mode, selects the focused item and all items below it, focuses the last item. |
Note
In read-only state, List Box supports keyboard navigation, but users cannot select items.
When the Enabled property is set to false
, the editor does not respond to user interactions.
Read-Only State
<DxListBox>
supports read-only state. Set the ReadOnly‘ property to true
to activate this option.
@using StaffData
<DxListBox Data="@Staff.DataSource"
Values="@Values"
ReadOnly="true" />
@code {
IEnumerable<Person> Values => Staff.DataSource.Take(1);
}
Troubleshooting
If a Blazor application throws unexpected exceptions, refer to the following help topic: Troubleshooting.