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

Custom Items in RadCheckedDropDownList's AutoComplete Popup

Environment

Product Version Product Author
2020.3.1020 RadCheckedDropDownList for WinForms Desislava Yordanova

Description

RadCheckedDropDownList combines RadDropDownList and RadAutoCompleteBox in order to provide functionality to check multiple items in the drop down area and tokenize them in the text area.

The AutoCompleteMode property controls the auto-complete behavior and can be set to None, Suggest, Append and SuggestAppend.

Similar to RadDropDownList, RadCheckedDropDownList also provides two pop ups. The first one is opened when the user presses the arrow button next to the editable area. It lists the content in the Items collection and a check box is shown next to each item. The second pop up is displayed when the user starts typing in the editable part and the items that match the user's input are shown in it. However, the displayed suggestions in the auto-complete pop up doesn't show a check box.

Default drop down AutoComplete drop down
custom-items-in-checkeddropdownlist-autocomplete-popup 001 custom-items-in-checkeddropdownlist-autocomplete-popup 002

A common requirement is to show a check box next to each item in the auto complete pop up in order to allow the end users to filter the items first and then select multiple items from the sub list.

Figure 1: Checkboxes in AutoComplete Items

custom-items-in-checkeddropdownlist-autocomplete-popup 003

Solution

It can be achieved by using a custom RadListVisualItem which contains a RadCheckBoxElement. In the CheckedDropDownListElement.AutoCompleteEditableAreaElement.AutoCompleteTextBox.ListElement.CreatingVisualItem event, the default visual item can be replaced with the custom one.

static List<string> checkedItems = new List<string>();

private void RadForm1_Load(object sender, EventArgs e)
{ 
    this.productsTableAdapter.Fill(this.nwindDataSet.Products);
    this.radCheckedDropDownList1.DisplayMember = "ProductName";
    this.radCheckedDropDownList1.DataSource = this.productsBindingSource;

    this.radCheckedDropDownList1.AutoCompleteMode = AutoCompleteMode.Suggest;
    this.radCheckedDropDownList1.CheckedDropDownListElement.AutoCompleteEditableAreaElement.AutoCompleteTextBox.ListElement.CreatingVisualItem 
        += ListElement_CreatingVisualItem;

    this.radCheckedDropDownList1.CheckedDropDownListElement.AutoCompleteEditableAreaElement.AutoCompleteTextBox.AutoCompleteDropDown.PopupClosing 
        += AutoCompleteDropDown_PopupClosing;
    this.radCheckedDropDownList1.CheckedDropDownListElement.AutoCompleteEditableAreaElement.AutoCompleteTextBox.AutoCompleteDropDown.PopupClosed 
        += AutoCompleteDropDown_PopupClosed;
}

private void AutoCompleteDropDown_PopupClosed(object sender, RadPopupClosedEventArgs args)
{
    foreach (RadCheckedListDataItem item in this.radCheckedDropDownList1.Items)
    {
        if (checkedItems.Contains(item.Text) && item.Checked == false)
        {
            item.Checked = true;
        }
    }
}

private void AutoCompleteDropDown_PopupClosing(object sender, RadPopupClosingEventArgs args)
{
    if (this.radCheckedDropDownList1.CheckedDropDownListElement.AutoCompleteEditableAreaElement.AutoCompleteTextBox.AutoCompleteDropDown.Bounds.Contains(Cursor.Position))
    {
        args.Cancel = true;
    }
}

private void ListElement_CreatingVisualItem(object sender, Telerik.WinControls.UI.CreatingVisualListItemEventArgs args)
{
    args.VisualItem = new CustomRadCheckedListVisualItem();
}

public class CustomRadCheckedListVisualItem : RadListVisualItem
{
    public CustomRadCheckedListVisualItem()
    {
    }

    protected override Type ThemeEffectiveType    
    {
        get   
        {
            return typeof(RadListVisualItem);    
        }
    }

    protected virtual RadLabelElement CreateLabelElement()
    {
        return new RadLabelElement();
    }

    protected virtual RadToggleButtonElement CreateCheckBoxElement()
    {
        return new RadCheckBoxElement();
    }

    private RadLabelElement label;
    private RadToggleButtonElement checkBox;
    private StackLayoutPanel stackLayoutPanel;

    protected override void CreateChildElements()
    {
        base.CreateChildElements();

        this.checkBox = this.CreateCheckBoxElement();
        this.label = this.CreateLabelElement();

        this.checkBox.ToggleStateChanging += checkBox_ToggleStateChanging;
        this.label.StretchHorizontally = true;
        this.label.Margin = new System.Windows.Forms.Padding(1, 0, 0, 0);
        this.label.NotifyParentOnMouseInput = false;
        this.label.ShouldHandleMouseInput = false;
        this.label.TextAlignment = System.Drawing.ContentAlignment.MiddleLeft;

        this.stackLayoutPanel = new StackLayoutPanel();
        this.stackLayoutPanel.Orientation = Orientation.Horizontal;
        this.stackLayoutPanel.Children.Add(checkBox);           
        this.stackLayoutPanel.Children.Add(label);
        this.Children.Add(this.stackLayoutPanel);
    }

    private void checkBox_ToggleStateChanging(object sender, StateChangingEventArgs args)
    {
        if (args.NewValue == Telerik.WinControls.Enumerations.ToggleState.On &&
            !checkedItems.Contains(this.Data.Text))
        {
            checkedItems.Add(this.Data.Text);
        }
        else if (checkedItems.Contains(this.Data.Text))
        {
            checkedItems.Remove(this.Data.Text);
        }
    }

    protected override void SynchronizeProperties()
    {
        base.SynchronizeProperties();

        if (!(this.Data is RadListDataItem))
        {
            return;
        }

        this.DrawText = false;
        this.label.Text = this.Data.Text;
    }
}

The achieved behavior is illustrated below:

custom-items-in-checkeddropdownlist-autocomplete-popup 004