New to Telerik UI for WinForms? Download free 30-day trial

How to Create Custom AutoComplete Items in RadAutoCompleteBox

Environment

Product Version Product Author
2021.1.223 RadAutoCompleteBox for WinForms Desislava Yordanova

Description

RadAutoCompleteBox allows the end-user to easily fill-in text thanks to the auto-complete functionality and tokens of text. This behavior is similar to the "To" field of Outlook and Facebook where you are filling-in the recipients to which you are going to send a message.

A common requirement is to add more details to each item in the autocomplete popup.

autocompletebox-with-custom-autocomplete-items

The following solution will demonstrate how to use the Northwind.Employee table and construct a custom visual auto complete item to display more information for each suggested employee.

Solution

Subscribe to the RadAutoCompleteBox.ListElement.CreatingVisualItem event before assigning the AutoCompleteDataSource collection. In the event handler, you can replace the default RadListVisualItem with a custom one according to specific design you may have. The following code snippet demonstrates a sample solution:

private void Form1_Load(object sender, EventArgs e)
{ 
    this.employeesTableAdapter.Fill(this.nwindDataSet.Employees);

    this.radAutoCompleteBox1.ListElement.CreatingVisualItem += ListElement_CreatingVisualItem;
    this.radAutoCompleteBox1.ListElement.ItemHeight = 100;
    this.radAutoCompleteBox1.DropDownMinSize = new Size(300,300);

    this.radAutoCompleteBox1.AutoCompleteDataSource = this.employeesBindingSource;
    this.radAutoCompleteBox1.AutoCompleteDisplayMember = "LastName";
    this.radAutoCompleteBox1.AutoCompleteValueMember = "EmployeeID";
}

private void ListElement_CreatingVisualItem(object sender, CreatingVisualListItemEventArgs args)
{
      args.VisualItem = new CustomVisualItem();
} 
public class CustomVisualItem : RadListVisualItem
{
    Font boldFont = new Font("Arial",10f, FontStyle.Bold);
    Font italicFont = new Font("Arial",10f, FontStyle.Italic);
    DockLayoutPanel mainContainer;
    StackLayoutElement leftColumn;
    StackLayoutElement rightColumn;
    LightVisualElement titleElement;
    LightVisualElement photoElement;
    LightVisualElement nameElement;
    LightVisualElement addressElement;
    LightVisualElement phoneElement;

    protected override Type ThemeEffectiveType     
    { 
        get    
        { 
            return typeof(RadListVisualItem);     
        }
    } 
    protected override void CreateChildElements()
    {
        base.CreateChildElements(); 

        mainContainer = new DockLayoutPanel();
        leftColumn = new StackLayoutElement();
        rightColumn = new StackLayoutElement();
        titleElement = new LightVisualElement();
        photoElement = new LightVisualElement();
        nameElement = new LightVisualElement();
        addressElement = new LightVisualElement();
        phoneElement = new LightVisualElement();

        this.Children.Add(mainContainer);
        mainContainer.LastChildFill = true;

        leftColumn.Orientation = Orientation.Vertical;
        leftColumn.Children.Add(photoElement);
        photoElement.DrawBorder = true;

        rightColumn.Orientation = Orientation.Vertical;
        rightColumn.Children.Add(nameElement);
        nameElement.Font = boldFont;
        rightColumn.Children.Add(addressElement);
        rightColumn.Children.Add(phoneElement);
        rightColumn.Children.Add(titleElement);
        titleElement.DrawBorder = true;
        titleElement.Font = italicFont;
        titleElement.BorderBoxStyle = Telerik.WinControls.BorderBoxStyle.FourBorders;
        titleElement.BorderLeftWidth = 0;
        titleElement.BorderTopWidth = 1;
        titleElement.BorderRightWidth = 0;
        titleElement.BorderBottomWidth = 0;

        mainContainer.Children.Add(leftColumn);
        mainContainer.Children.Add(rightColumn);  
        DockLayoutPanel.SetDock(leftColumn, Telerik.WinControls.Layouts.Dock.Left);
        DockLayoutPanel.SetDock(rightColumn, Telerik.WinControls.Layouts.Dock.Right);
        leftColumn.NotifyParentOnMouseInput = true;
        rightColumn.NotifyParentOnMouseInput = true;
        titleElement.NotifyParentOnMouseInput = true;
        photoElement.NotifyParentOnMouseInput = true;
        nameElement.NotifyParentOnMouseInput = true;
        addressElement.NotifyParentOnMouseInput = true;
        phoneElement.NotifyParentOnMouseInput = true;
    }

    public override void Synchronize()
    {
        base.Synchronize();
        this.Text = string.Empty;
        DataRowView rowView = this.Data.DataBoundItem as DataRowView;
        if (rowView != null)
        {
            this.photoElement.Image = GetImageFromData(rowView.Row["Photo"] as byte[]);
            this.titleElement.Text = rowView.Row["Title"].ToString();
            this.nameElement.Text = rowView.Row["FirstName"].ToString() + " " + rowView.Row["LastName"].ToString();
            this.addressElement.Text = "Address: " + rowView.Row["Address"].ToString().Replace(System.Environment.NewLine, " ");
            this.phoneElement.Text = "Phone: " + rowView.Row["HomePhone"].ToString();
        }
    }

    private Image GetImageFromData(byte[] imageData)
    {
        const int OleHeaderLength = 78;
        MemoryStream memoryStream = new MemoryStream();
        if (HasOleContainerHeader(imageData))
        {
            memoryStream.Write(imageData, OleHeaderLength, imageData.Length - OleHeaderLength);
        }
        else
        {
            memoryStream.Write(imageData, 0, imageData.Length);
        }
        Bitmap bitmap = new Bitmap(memoryStream);
        return bitmap.GetThumbnailImage(55, 65, null, new IntPtr());
    }

    private bool HasOleContainerHeader(byte[] imageByteArray)
    {
        const byte OleByte0 = 21;
        const byte OleByte1 = 28;
        return (imageByteArray[0] == OleByte0) && (imageByteArray[1] == OleByte1);
    }
}


Private Sub RadForm1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    Me.EmployeesTableAdapter.Fill(Me.NwindDataSet.Employees)

    AddHandler Me.RadAutoCompleteBox1.ListElement.CreatingVisualItem, AddressOf ListElement_CreatingVisualItem
    Me.RadAutoCompleteBox1.ListElement.ItemHeight = 100
    Me.RadAutoCompleteBox1.DropDownMinSize = New Size(300, 300)
    Me.RadAutoCompleteBox1.AutoCompleteDataSource = Me.EmployeesBindingSource
    Me.RadAutoCompleteBox1.AutoCompleteDisplayMember = "LastName"
    Me.RadAutoCompleteBox1.AutoCompleteValueMember = "EmployeeID"
End Sub

Private Sub ListElement_CreatingVisualItem(sender As Object, args As CreatingVisualListItemEventArgs)
    args.VisualItem = New CustomVisualItem()
End Sub

Public Class CustomVisualItem
    Inherits RadListVisualItem

    Private boldFont As Font = New Font("Arial", 10.0F, FontStyle.Bold)
    Private italicFont As Font = New Font("Arial", 10.0F, FontStyle.Italic)
    Private mainContainer As DockLayoutPanel
    Private leftColumn As StackLayoutElement
    Private rightColumn As StackLayoutElement
    Private titleElement As LightVisualElement
    Private photoElement As LightVisualElement
    Private nameElement As LightVisualElement
    Private addressElement As LightVisualElement
    Private phoneElement As LightVisualElement

    Protected Overrides ReadOnly Property ThemeEffectiveType As Type
        Get
            Return GetType(RadListVisualItem)
        End Get
    End Property

    Protected Overrides Sub CreateChildElements()
        MyBase.CreateChildElements()
        mainContainer = New DockLayoutPanel()
        leftColumn = New StackLayoutElement()
        rightColumn = New StackLayoutElement()
        titleElement = New LightVisualElement()
        photoElement = New LightVisualElement()
        nameElement = New LightVisualElement()
        addressElement = New LightVisualElement()
        phoneElement = New LightVisualElement()
        Me.Children.Add(mainContainer)
        mainContainer.LastChildFill = True
        leftColumn.Orientation = Orientation.Vertical
        leftColumn.Children.Add(photoElement)
        photoElement.DrawBorder = True
        rightColumn.Orientation = Orientation.Vertical
        rightColumn.Children.Add(nameElement)
        nameElement.Font = boldFont
        rightColumn.Children.Add(addressElement)
        rightColumn.Children.Add(phoneElement)
        rightColumn.Children.Add(titleElement)
        titleElement.DrawBorder = True
        titleElement.Font = italicFont
        titleElement.BorderBoxStyle = Telerik.WinControls.BorderBoxStyle.FourBorders
        titleElement.BorderLeftWidth = 0
        titleElement.BorderTopWidth = 1
        titleElement.BorderRightWidth = 0
        titleElement.BorderBottomWidth = 0
        mainContainer.Children.Add(leftColumn)
        mainContainer.Children.Add(rightColumn)
        DockLayoutPanel.SetDock(leftColumn, Telerik.WinControls.Layouts.Dock.Left)
        DockLayoutPanel.SetDock(rightColumn, Telerik.WinControls.Layouts.Dock.Right)
        leftColumn.NotifyParentOnMouseInput = True
        rightColumn.NotifyParentOnMouseInput = True
        titleElement.NotifyParentOnMouseInput = True
        photoElement.NotifyParentOnMouseInput = True
        nameElement.NotifyParentOnMouseInput = True
        addressElement.NotifyParentOnMouseInput = True
        phoneElement.NotifyParentOnMouseInput = True
    End Sub

    Public Overrides Sub Synchronize()
        MyBase.Synchronize()
        Me.Text = String.Empty
        Dim rowView As DataRowView = TryCast(Me.Data.DataBoundItem, DataRowView)

        If rowView IsNot Nothing Then
            Me.photoElement.Image = GetImageFromData(TryCast(rowView.Row("Photo"), Byte()))
            Me.titleElement.Text = rowView.Row("Title").ToString()
            Me.nameElement.Text = rowView.Row("FirstName").ToString() & " " + rowView.Row("LastName").ToString()
            Me.addressElement.Text = "Address: " & rowView.Row("Address").ToString().Replace(System.Environment.NewLine, " ")
            Me.phoneElement.Text = "Phone: " & rowView.Row("HomePhone").ToString()
        End If
    End Sub

    Private Function GetImageFromData(ByVal imageData As Byte()) As Image
        Const OleHeaderLength As Integer = 78
        Dim memoryStream As MemoryStream = New MemoryStream()

        If HasOleContainerHeader(imageData) Then
            memoryStream.Write(imageData, OleHeaderLength, imageData.Length - OleHeaderLength)
        Else
            memoryStream.Write(imageData, 0, imageData.Length)
        End If

        Dim bitmap As Bitmap = New Bitmap(memoryStream)
        Return bitmap.GetThumbnailImage(55, 65, Nothing, New IntPtr())
    End Function

    Private Function HasOleContainerHeader(ByVal imageByteArray As Byte()) As Boolean
        Const OleByte0 As Byte = 21
        Const OleByte1 As Byte = 28
        Return (imageByteArray(0) = OleByte0) AndAlso (imageByteArray(1) = OleByte1)
    End Function
End Class   


In this article