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);
    }
}

In this article