Back to Devexpress

Lookup Editors

windowsforms-116008-controls-and-libraries-editors-and-simple-controls-lookup-editors.md

latest36.5 KB
Original Source

Lookup Editors

  • Sep 12, 2025
  • 15 minutes to read

Data Lookups

The DevExpress WinForms Subscription includes four lookup controls. Lookups are data-bound editors that display data source records in their dropdowns. Users can select one item (record) at a time. Users cannot edit records in the dropdown.

Standard Lookup

LookUpEdit is a text box editor with a dropdown panel that displays data in a simple table layout.

Run Demo: LookUp Edit

Grid-based Lookup

GridLookUpEdit is a lookup editor that embeds the Data Grid within the dropdown. With the Data Grid’s countless visualization and data presentation options, you have total control over the lookup’s UI/UX.

Run Demo: Grid LookUp

SearchLookUpEdit is a grid-based lookup with an embedded Find Panel. Unlike the GridLookUpEdit, this editor supports Instant Feedback mode, but does not allow users to enter values in the text box.

Run Demo: LookUp with Search

TreeList-based Lookup

TreeListLookUpEdit is a lookup editor that embeds the Tree List control within the dropdown. Users can select values form hierarchical lists.

Run Demo: TreeList LookUp

Feature Matrix

LookupGrid LookupTreeList LookupSearch Lookup
In-Place Mode (use within data-aware controls)
Resizable Dropdown Window
Multiple Columns
Unbound Columns
Show/Hide Horizontal and Vertical Lines
Insert New Records/Values
Autocomplete
Case Sensitive Search
AI-powered Semantic Search
Sorting
Display Data in Table Layout
Autosuggest Mode
Data Aggregation (Summaries)
Arrange Columns into Bands
Row Auto Height
Grouping
Server Mode (Optimized Data Loading)
Instant Feedback UI
Auto Filter Row
Find Panel
Display Records as Tiles (Table, List, Kanban Board)
Hierarchical Data Structures
Multiple Item Selection

Note

Use the PopupContainerEdit control if you need functionality that is not supported by lookup editors. This control allows you to display any controls within its popup window.

How to Use a PopupContainerEdit to Create an Editable Grid-based Lookup

Bind to Data

Lookups are data-bound controls. Use the following properties to bind a lookup editor to a data source:

  • DataSource – Specifies the source of records.
  • DisplayMember – The data source field with display values. A value from this field is displayed in the lookup’s text box when a user selects a record.
  • ValueMember – The data source field with unique/key values. A value from this data field is assigned to the lookup’s EditValue property when a user selects a record.

Important

When a lookup editor is used to edit cell values in the Data Grid, the type of the ValueMember field must match the type of the field assigned to the grid’s lookup column (GridColumn.FieldName). Enable the lookup’s ThrowExceptionOnInvalidLookUpEditValueType option to detect data type issues.

Use the lookup’s smart tag menu to bind it to data.

The following example shows how to bind a lookup editor to data created at runtime:

csharp
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

public partial class Form1 : DevExpress.XtraEditors.XtraForm {
    public Form1() {
        InitializeComponent();
        // Binds the lookup to data.
        lookUpEdit1.Properties.DataSource = Employee.GetSampleData();
        // Sets the lookup's data fields.
        lookUpEdit1.Properties.DisplayMember = "FullName";
        lookUpEdit1.Properties.ValueMember = "ID";
        // Sets the lookup's value. Selects the first record.
        lookUpEdit1.EditValue = 0;
    }
}

public class Employee {
    public Employee(int iD, string firstName, string lastName) {
        ID = iD;
        FirstName = firstName;
        LastName = lastName;
    }
    public static List<Employee> GetSampleData() {
        return new List<Employee>() {
            new Employee(0, "Bart", "Arnaz"),
            new Employee(1, "Leah", "Simpson"),
            new Employee(2, "Arnold", "Schwartz"),
            new Employee(3, "William", "Zimmer"),
            new Employee(4, "Samantha", "Piper")
        };
    }
    // The 'ID' field must contain unique values.
    public int ID { get; private set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    [Display(Order = -1)]
    public string FullName {
        get {
            return string.Format("{0} {1}", FirstName, LastName);
        }
    }
}
vb
Imports System
Imports System.Collections.Generic
Imports System.ComponentModel.DataAnnotations

Partial Public Class Form1
    Inherits DevExpress.XtraEditors.XtraForm

    Public Sub New()
        InitializeComponent()
        ' Binds the lookup to data.
        lookUpEdit1.Properties.DataSource = Employee.GetSampleData()
        ' Sets the lookup's data fields.
        lookUpEdit1.Properties.DisplayMember = "FullName"
        lookUpEdit1.Properties.ValueMember = "ID"
        ' Sets the lookup's value.
        lookUpEdit1.EditValue = 0
    End Sub
End Class

Public Class Employee
    Public Sub New(ByVal iD As Integer, ByVal firstName As String, ByVal lastName As String)
        Me.ID = iD
        Me.FirstName = firstName
        Me.LastName = lastName
    End Sub
    Public Shared Function GetSampleData() As List(Of Employee)
        Return New List(Of Employee)() From {
            New Employee(0, "Bart", "Arnaz"),
            New Employee(1, "Leah", "Simpson"),
            New Employee(2, "Arnold", "Schwartz"),
            New Employee(3, "William", "Zimmer"),
            New Employee(4, "Samantha", "Piper")
        }
    End Function
    ' The 'ID' field must contain unique values.
    Private privateID As Integer
    Public Property ID() As Integer
        Get
            Return privateID
        End Get
        Private Set(ByVal value As Integer)
            privateID = value
        End Set
    End Property
    Public Property FirstName() As String
    Public Property LastName() As String
    <Display(Order := -1)>
    Public ReadOnly Property FullName() As String
        Get
            Return String.Format("{0} {1}", FirstName, LastName)
        End Get
    End Property
End Class

The image below shows the result.

See the following articles for more information:

Tip

How to create a LookUp and use it in the Data Grid

Allow Users to Enter New Values

Set the lookup’s TextEditStyle property to Standard to allow users to type in the text box. Handle the ProcessNewValue event to parse entered values and add new records to the lookup’s data source.

csharp
using DevExpress.Utils;
using DevExpress.XtraEditors;
using DevExpress.XtraEditors.Controls;
using System.ComponentModel.DataAnnotations;

public Form1() {
    InitializeComponent();
    // Binds the lookup to data.
    lookUpEdit1.Properties.DataSource = Task.GetSampleData();
    // Sets the lookup's data fields.
    lookUpEdit1.Properties.DisplayMember = "Caption";
    lookUpEdit1.Properties.ValueMember = "ID";
    // Sets the lookup's value.
    lookUpEdit1.EditValue = 0;
    // Enables adding new values.
    lookUpEdit1.Properties.TextEditStyle = TextEditStyles.Standard;
    lookUpEdit1.ProcessNewValue += new ProcessNewValueEventHandler(this.lookUpEdit1_ProcessNewValue);
}
private void lookUpEdit1_ProcessNewValue(object sender, ProcessNewValueEventArgs e) {
    if((string)e.DisplayValue == String.Empty) return;
    List<Task> dataSource = (sender as LookUpEdit).Properties.DataSource as List<Task>;
    dataSource.Add(new Task(dataSource.Count) { Caption = (string)e.DisplayValue});
    e.Handled = true;
}

public class Task {
    public Task(int id) {
        ID = id;
        CreateDate = DateTime.Today;
    }
    [Display(Order = -1)]
    public int ID { get; private set; }
    public string Caption { get; set; }
    public DateTime CreateDate { get; set; }
    public static List<Task> GetSampleData() {
        return new List<Task>() {
            new Task(0){Caption = "Research", CreateDate = new DateTime(2022, 10, 15)},
            new Task(1){Caption = "UI Design", CreateDate = new DateTime(2022, 11, 5)},
            new Task(2){Caption = "Environment Setup", CreateDate = new DateTime(2022, 11, 10)},
            new Task(3){Caption = "Sprint 1", CreateDate = new DateTime(2022, 11, 11)},
            new Task(4){Caption = "Sprint 2", CreateDate = new DateTime(2022, 12, 12)},
            new Task(5){Caption = "Sprint 3", CreateDate = new DateTime(2023, 1, 10)},
            new Task(6){Caption = "Testing", CreateDate = new DateTime(2022, 2, 10)}
        };
    }
}
vb
Imports DevExpress.Utils
Imports DevExpress.XtraEditors
Imports DevExpress.XtraEditors.Controls
Imports System.ComponentModel.DataAnnotations

Public Sub New()
    InitializeComponent()
    ' Binds the lookup to data.
    lookUpEdit1.Properties.DataSource = Task.GetSampleData()
    ' Sets the lookup's data fields.
    lookUpEdit1.Properties.DisplayMember = "Caption"
    lookUpEdit1.Properties.ValueMember = "ID"
    ' Sets the lookup's value.
    lookUpEdit1.EditValue = 0
    ' Enables adding new values.
    lookUpEdit1.Properties.TextEditStyle = TextEditStyles.Standard
    AddHandler lookUpEdit1.ProcessNewValue, AddressOf lookUpEdit1_ProcessNewValue
End Sub
Private Sub lookUpEdit1_ProcessNewValue(ByVal sender As Object, ByVal e As ProcessNewValueEventArgs)
    If CStr(e.DisplayValue) = String.Empty Then
        Return
    End If
    Dim dataSource As List(Of Task) = TryCast((TryCast(sender, LookUpEdit)).Properties.DataSource, List(Of Task))
    dataSource.Add(New Task(dataSource.Count) With {.Caption = CStr(e.DisplayValue)})
    e.Handled = True
End Sub

Public Class Task
    Public Sub New(ByVal id As Integer)
        Me.ID = id
        CreateDate = Date.Today
    End Sub
    Private privateID As Integer
    <Display(Order := -1)>
    Public Property ID() As Integer
        Get
            Return privateID
        End Get
        Private Set(ByVal value As Integer)
            privateID = value
        End Set
    End Property
    Public Property Caption() As String
    Public Property CreateDate() As Date

    Public Shared Function GetSampleData() As List(Of Task)
        Return New List(Of Task)() From {
            New Task(0) With { .Caption = "Research", .CreateDate = New DateTime(2022, 10, 15) },
            New Task(1) With { .Caption = "UI Design", .CreateDate = New DateTime(2022, 11, 5) },
            New Task(2) With { .Caption = "Environment Setup", .CreateDate = New DateTime(2022, 11, 10) },
            New Task(3) With { .Caption = "Sprint 1", .CreateDate = New DateTime(2022, 11, 11) },
            New Task(4) With { .Caption = "Sprint 2", .CreateDate = New DateTime(2022, 12, 12) },
            New Task(5) With { .Caption = "Sprint 3", .CreateDate = New DateTime(2023, 1, 10) },
            New Task(6) With { .Caption = "Testing", .CreateDate = New DateTime(2022, 2, 10) }
        }
    End Function
End Class

Note

The LookUpEdit and GridLookUpEdit support ComboBox mode. In this mode, the lookups behave as a standard ComboBox control. Read the following topic for detailed information: ComboBox Mode for LookUp Controls.

Enable Multiple Item Selection

Important

Multiple item selection is supported only in the WinForms LookUpEdit control. GridLookUpEdit, TreeListLookUpEdit, and SearchLookUpEdit controls do not support this feature.

Set the EditValueType property to ValueList or CSVString to allow users to select multiple items.

Run Demo: Multi Select Lookup

Display a Checkbox Selector Column

You can display the checkbox selector column in two ways:

Create Columns Manually Before Data Binding

Use AddCheckBoxSelectorColumn() and RemoveCheckBoxSelectorColumn() methods to manually add and remove the checkbox selector column.

csharp
var lookUpEdit1 = new LookUpEdit() { 
    EditValue = new List<object>() { 0, 1 } 
};
lookUpEdit1.Properties.EditValueType = LookUpEditValueType.ValueList;

// Create lookup columns manually.
lookUpEdit1.Properties.Columns.AddRange(new LookUpColumnInfo[] {
    new LookUpColumnInfo("ID"),
    new LookUpColumnInfo("FirstName"),
    new LookUpColumnInfo("LastName"),
});

// Add a checkbox selector column manually.
lookUpEdit1.Properties.AddCheckBoxSelectorColumn();

// Bind the lookup to data and set data fields.
lookUpEdit1.Properties.DataSource = Employee.GetSampleData();
lookUpEdit1.Properties.DisplayMember = "FullName";
lookUpEdit1.Properties.ValueMember = "ID";

this.Controls.Add(lookUpEdit1);

Auto-Create Columns

If you do not define lookup columns manually, the LookUpEdit generates columns for all data fields when you bind it to a data source. The LookUpEdit also creates a checkbox selector column automatically.

Specify the EditValue Type

The EditValueType property specifies the data type of the EditValue property:

ValueList

The EditValue property returns a List<object> object with selected items.

Use the EnableEditValueCollectionEditing property to bind EditValue to a read-only collection property (for example, a HashSet<T>).

CSVStringThe EditValue property returns a String with DisplayMember values of selected items, separated by SeparatorChar + space.

The following example activates multiple item selection. The example sets the lookup’s EditValue property to a list with IDs to select corresponding products on app startup. In this example, the LookUpEdit automatically creates a checkbox selector column.

csharp
using System.Windows.Forms;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using DevExpress.XtraEditors;
using DevExpress.XtraEditors.Repository;

public partial class Form1 : XtraForm {
    public Form1() {
        InitializeComponent();
        lookUpEdit1.Properties.DataSource = ProductA.GetList();
        lookUpEdit1.Properties.DisplayMember = "Name";
        lookUpEdit1.Properties.ValueMember = "ID";
        lookUpEdit1.Properties.EditValueType = LookUpEditValueType.ValueList;
        lookUpEdit1.EditValue = new List<object>() {0, 1, 4};
    }
}
public class ProductA {
    int id;
    public ProductA(int id) {
        this.id = id;
    }
    [Display(Order = -1)]
    public int ID {
        get { return id; }
    }
    [Display(ShortName = "Bakery & Desserts")]
    public string Name { get; set; }
    [DisplayFormat(DataFormatString = "c2")]
    public double Price { get; set; }
    public static List<ProductA> GetList() {
        return new List<ProductA>() {
            new ProductA(0){ Name = "Butter Cake", Price = 56.99 },
            new ProductA(1){ Name = "Chocolate Pie ", Price = 89.99 },
            new ProductA(2){ Name = "Frozen Cookie Dough", Price = 54.99 },
            new ProductA(3){ Name = "Truffie Cake", Price = 59.99 },
            new ProductA(4){ Name = "Original Apple Pie", Price = 59.99 }
        };
    }
}
vb
Imports System.Windows.Forms
Imports System.Collections.Generic
Imports System.ComponentModel.DataAnnotations
Imports DevExpress.XtraEditors
Imports DevExpress.XtraEditors.Repository

Partial Public Class Form1
    Inherits XtraForm

    Public Sub New()
        InitializeComponent()
        lookUpEdit1.Properties.DataSource = ProductA.GetList()
        lookUpEdit1.Properties.DisplayMember = "Name"
        lookUpEdit1.Properties.ValueMember = "ID"
        lookUpEdit1.Properties.EditValueType = LookUpEditValueType.ValueList
        lookUpEdit1.EditValue = New List(Of Object)() From {0, 1, 4}
    End Sub
End Class
Public Class ProductA
    Private fid As Integer
    Public Sub New(ByVal id As Integer)
        Me.fid = id
    End Sub
    <Display(Order := -1)>
    Public ReadOnly Property ID() As Integer
        Get
            Return fid
        End Get
    End Property
    <Display(ShortName := "Bakery & Desserts")>
    Public Property Name() As String
    <DisplayFormat(DataFormatString := "c2")>
    Public Property Price() As Double
    Public Shared Function GetList() As List(Of ProductA)
        Return New List(Of ProductA)() From {
            New ProductA(0) With {
                .Name = "Butter Cake",
                .Price = 56.99
            },
            New ProductA(1) With {
                .Name = "Chocolate Pie ",
                .Price = 89.99
            },
            New ProductA(2) With {
                .Name = "Frozen Cookie Dough",
                .Price = 54.99
            },
            New ProductA(3) With {
                .Name = "Truffie Cake",
                .Price = 59.99
            },
            New ProductA(4) With {
                .Name = "Original Apple Pie",
                .Price = 59.99
            }
        }
    End Function
End Class

Bind the Selected State to a Property

Use the CheckBoxSelectorMember property bind item selection state to a data source field. The column created for this field becomes the selector column.

  • The LookUpEdit updates the bound field when users change selection.
  • The Cancel button is hidden in this mode.
  • EditValue is not populated automatically. Specify it explicitly to display selected items in the editor.

The following example binds selection to the “Selected” data field (with Boolean values):

csharp
public partial class Form1 : XtraForm {
    public Form1() {
        InitializeComponent();
        lookUpEdit2.Properties.DataSource = ProductB.GetList();
        lookUpEdit2.Properties.DisplayMember = "Name";
        lookUpEdit2.Properties.ValueMember = "ID";
        lookUpEdit2.Properties.CheckBoxSelectorMember = "Selected";
        lookUpEdit2.Properties.EditValueType = LookUpEditValueType.ValueList;
        lookUpEdit2.EditValue = new List<object>() {0, 1};
    }
}
public class ProductB {
    int id;
    public ProductB(int id) {
        this.id = id;
    }
    [Display(Order = -1)]
    public int ID {
        get { return id; }
    }
    [Display(ShortName = "Bakery & Desserts")]
    public string Name { get; set; }
    [DisplayFormat(DataFormatString = "c2")]
    public double Price { get; set; }
    public int InStock { get; set; }
    [Display(ShortName = "Add to Order")]
    public bool Selected { get; set; }
    public static List<ProductB> GetProductList() {
        return new List<ProductB>() {
            new ProductB(0){ Name = "Butter Cake", Price = 56.99, InStock = 50 },
            new ProductB(1){ Name = "Chocolate Pie ", Price = 89.99, InStock = 32 },
            new ProductB(2){ Name = "Frozen Cookie Dough", Price = 54.99, InStock = 0 },
            new ProductB(3){ Name = "Truffie Cake", Price = 59.99, InStock = 42 },
            new ProductB(4){ Name = "Original Apple Pie", Price = 59.99, InStock = 0}
        };
    }
}
vb
Partial Public Class Form1
    Inherits XtraForm

    Public Sub New()
        InitializeComponent()
        lookUpEdit2.Properties.DataSource = ProductB.GetList()
        lookUpEdit2.Properties.DisplayMember = "Name"
        lookUpEdit2.Properties.ValueMember = "ID"
        lookUpEdit2.Properties.CheckBoxSelectorMember = "Selected"
        lookUpEdit2.Properties.EditValueType = LookUpEditValueType.ValueList
        lookUpEdit2.EditValue = New List(Of Object)() From {0, 1}
    End Sub
End Class
Public Class ProductB
    Private fid As Integer
    Public Sub New(ByVal id As Integer)
        Me.fid = id
    End Sub
    <Display(Order := -1)>
    Public ReadOnly Property ID() As Integer
        Get
            Return fid
        End Get
    End Property
    <Display(ShortName := "Bakery & Desserts")>
    Public Property Name() As String
    <DisplayFormat(DataFormatString := "c2")>
    Public Property Price() As Double
    Public Property InStock() As Integer
    <Display(ShortName := "Add to Order")>
    Public Property Selected() As Boolean
    Public Shared Function GetProductList() As List(Of ProductB)
        Return New List(Of ProductB)() From {
            New ProductB(0) With {
                .Name = "Butter Cake",
                .Price = 56.99,
                .InStock = 50
            },
            New ProductB(1) With {
                .Name = "Chocolate Pie ",
                .Price = 89.99,
                .InStock = 32
            },
            New ProductB(2) With {
                .Name = "Frozen Cookie Dough",
                .Price = 54.99,
                .InStock = 0
            },
            New ProductB(3) With {
                .Name = "Truffie Cake",
                .Price = 59.99,
                .InStock = 42
            },
            New ProductB(4) With {
                .Name = "Original Apple Pie",
                .Price = 59.99,
                .InStock = 0
            }
        }
    End Function
End Class

If the bound field is not Boolean, handle he following events to convert values:

Control User Behavior

The LookUpEdit raises the following events when a user selects items in the popup:

MethodDescription
SelectionChangingOccurs before a user selects an item in the editor’s popup.
SelectionChangedOccurs after a user selects an item in the editor’s popup.

Handle the SelectionChanging event and set the e.Cancel parameter to true to cancel item selection:

csharp
using DevExpress.XtraEditors.Controls;

public partial class Form1 : XtraForm {
    List<ProductB> products;
    public Form1() {
        InitializeComponent();
        //...
        lookUpEdit1.Properties.SelectionChanging += Properties_SelectionChanging;
    }
    private void Properties_SelectionChanging(object sender, PopupSelectionChangingEventArgs e) {
        e.Cancel = products[e.RecordIndex].InStock == 0;
    }
}
vb
Imports DevExpress.XtraEditors.Controls

Partial Public Class Form1
    Inherits XtraForm

    Private products As List(Of ProductB)
    Public Sub New()
        InitializeComponent()
        '...
        AddHandler lookUpEdit1.Properties.SelectionChanging, AddressOf Properties_SelectionChanging
    End Sub
    Private Sub Properties_SelectionChanging(ByVal sender As Object, ByVal e As PopupSelectionChangingEventArgs)
        e.Cancel = products(e.RecordIndex).InStock = 0
    End Sub
End Class

If the editor works in AutoSearch or AutoSuggest mode, users can type text in the edit box to search for items:

AutoSearch ModeThe LookUpEdit always displays selected items regardless of the search string.AutoSuggest ModeThe LookUpEdit‘s data source should always include selected items. Add these items to the suggestion collection in the AutoSuggest event handler to support the multiple items selection.

If the edit box contains selected items, users can edit only the last item.

Cascading Lookups

Lookups can filter their values based on the currently selected values of other lookups. See the following examples for detailed information:

Unbound Columns

Lookups can display columns that are not bound to data source fields.

AutoSuggest and AutoSearch

A lookup can filter its records or suggest matching values as a user types.

Read the corresponding sections in the LookUpEdit topic for detailed information and examples.

Tip

GridControl, GridLookUpEdit, and SearchLookUpEdit support AI-powered Semantic Search. Unlike standard keyword-based search, semantic search leverages Natural Language Processing (NLP) to analyze search queries beyond exact keyword matching. See the following help topic for additional information: Semantic Search.

Run Demo: Semantic Search

Custom Filter Expression

Handle the LookUpEdit’s PopupFilter event to specify a custom filter expression.

csharp
using DevExpress.Data.Filtering;
using DevExpress.XtraEditors.Controls;

private void LookUpEdit1_PopupFilter(object sender, PopupFilterEventArgs e)
{
    e.Criteria = CriteriaOperator.Parse(string.Format("DeliveryDate < '{0}'", DateTime.Today));
}
vb
Imports DevExpress.Data.Filtering
Imports DevExpress.XtraEditors.Controls

Private Sub LookUpEdit1_PopupFilter(ByVal sender As Object, ByVal e As PopupFilterEventArgs)
    e.Criteria = CriteriaOperator.Parse("ShipCountry == 'Brazil'")
End Sub

Examples

See Also