AutoCompleteSuggest customised comparer

6 posts, 1 answers
  1. Clive
    Clive avatar
    12 posts
    Member since:
    Sep 2011

    Posted 17 Nov 2011 Link to this post

    Hi,

    I was wondering if the solution I created below is the best way to do what I want.

    I have a list that when the user types in, i'd like the suggestions to pop up, to suggest the items that begin with the text first, but then also include all other items that have that text within it below that.

    i.e.
    if the list is

    aper

    aaper

    ape

    per

    pants per

    aaa per


    and the user types 'p' then I want the list to show

    pants per

    per

    aaa per

    aaper

    ape

    aper


    when the user types 'pe' then i want the list to show

    per

    aaa per

    aaper

    ape

    aper

    pants per



    when the user types 'per' then i want the list to show

    per

    aaa per

    aaper

    aper

    pants per


    My ApplyFilterToDropDown is an almost copy of the Telerik one, but injecting my comparer instead. I had to do this because if I just set the ItemsSortComparer to mine, then called the base.ApplyFilterToDropDown it always got wiped out, so I resorted to this.

    Imports Telerik.WinControls.UI
      
    Public Class Form7
        Inherits System.Windows.Forms.Form
      
        'Form overrides dispose to clean up the component list.
        <System.Diagnostics.DebuggerNonUserCode()> _
        Protected Overrides Sub Dispose(ByVal disposing As Boolean)
            Try
                If disposing AndAlso components IsNot Nothing Then
                    components.Dispose()
                End If
            Finally
                MyBase.Dispose(disposing)
            End Try
        End Sub
      
        'Required by the Windows Form Designer
        Private components As System.ComponentModel.IContainer
      
        'NOTE: The following procedure is required by the Windows Form Designer
        'It can be modified using the Windows Form Designer.  
        'Do not modify it using the code editor.
        <System.Diagnostics.DebuggerStepThrough()> _
        Private Sub InitializeComponent()
            Dim RadListDataItem1 As Telerik.WinControls.UI.RadListDataItem = New Telerik.WinControls.UI.RadListDataItem()
            Dim RadListDataItem2 As Telerik.WinControls.UI.RadListDataItem = New Telerik.WinControls.UI.RadListDataItem()
            Dim RadListDataItem3 As Telerik.WinControls.UI.RadListDataItem = New Telerik.WinControls.UI.RadListDataItem()
            Dim RadListDataItem4 As Telerik.WinControls.UI.RadListDataItem = New Telerik.WinControls.UI.RadListDataItem()
            Dim RadListDataItem5 As Telerik.WinControls.UI.RadListDataItem = New Telerik.WinControls.UI.RadListDataItem()
            Dim RadListDataItem6 As Telerik.WinControls.UI.RadListDataItem = New Telerik.WinControls.UI.RadListDataItem()
            Me.RadDropDownList1 = New Telerik.WinControls.UI.RadDropDownList()
            CType(Me.RadDropDownList1, System.ComponentModel.ISupportInitialize).BeginInit()
            Me.SuspendLayout()
            '
            'RadDropDownList1
            '
            Me.RadDropDownList1.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.SuggestAppend
            Me.RadDropDownList1.DropDownAnimationEnabled = True
            RadListDataItem1.Text = "aper"
            RadListDataItem1.TextWrap = True
            RadListDataItem2.Text = "aaper"
            RadListDataItem2.TextWrap = True
            RadListDataItem3.Text = "ape"
            RadListDataItem3.TextWrap = True
            RadListDataItem4.Text = "per"
            RadListDataItem4.TextWrap = True
            RadListDataItem5.Text = "pants per"
            RadListDataItem5.TextWrap = True
            RadListDataItem6.Text = "aaa per"
            RadListDataItem6.TextWrap = True
            Me.RadDropDownList1.Items.Add(RadListDataItem1)
            Me.RadDropDownList1.Items.Add(RadListDataItem2)
            Me.RadDropDownList1.Items.Add(RadListDataItem3)
            Me.RadDropDownList1.Items.Add(RadListDataItem4)
            Me.RadDropDownList1.Items.Add(RadListDataItem5)
            Me.RadDropDownList1.Items.Add(RadListDataItem6)
            Me.RadDropDownList1.Location = New System.Drawing.Point(93, 126)
            Me.RadDropDownList1.Name = "RadDropDownList1"
            Me.RadDropDownList1.ShowImageInEditorArea = True
            Me.RadDropDownList1.Size = New System.Drawing.Size(106, 20)
            Me.RadDropDownList1.TabIndex = 1
            Me.RadDropDownList1.ThemeName = "ControlDefault"
            '
            'Form7
            '
            Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
            Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
            Me.ClientSize = New System.Drawing.Size(292, 273)
            Me.Controls.Add(Me.RadDropDownList1)
            Me.Name = "Form7"
            Me.Text = "Form7"
            CType(Me.RadDropDownList1, System.ComponentModel.ISupportInitialize).EndInit()
            Me.ResumeLayout(False)
            Me.PerformLayout()
      
        End Sub
        Friend WithEvents RadDropDownList1 As Telerik.WinControls.UI.RadDropDownList
      
      
        Public Class CustomAutoCompleteSuggestHelper
            Inherits AutoCompleteSuggestHelper
            Public Sub New(element As RadDropDownListElement)
                MyBase.New(element)
            End Sub
      
            Protected Overrides Function DefaultFilter(item As RadListDataItem) As Boolean
                Return item.Text.ToLower().Contains(Me.Filter.ToLower())
            End Function
      
            Public Overrides Sub AutoComplete(e As KeyPressEventArgs)
                MyBase.AutoComplete(e)
                If Me.DropDownList.Items.Count > 0 Then
                    'Me.DropDownList.SelectedIndex = Me.DropDownList.FindString(Me.Filter)
                End If
            End Sub
      
            Private mFilter As String = String.Empty
            Protected Overrides ReadOnly Property Filter As String
                Get
                    Return mFilter
                End Get
            End Property
      
            Public Overrides Sub ApplyFilterToDropDown(filter As String)
                Static filterFirstComparer As ListItemFilterAscendingComparer
                mFilter = filter
                If String.IsNullOrEmpty(filter) Then
                    MyBase.ApplyFilterToDropDown(filter)
                    Return
                End If
                With Me.DropDownList.ListElement
                    .SelectionMode = SelectionMode.None
                    .BeginUpdate()
                    .Filter = Nothing
                    .Filter = AddressOf DefaultFilter
                    .SortStyle = Telerik.WinControls.Enumerations.SortStyle.Ascending
                End With
                ' will move all items that begin with the filter, to the top of the list
                If filterFirstComparer Is Nothing Then
                    filterFirstComparer = New ListItemFilterAscendingComparer With {.filter = filter}
                Else
                    filterFirstComparer.filter = filter
                End If
                Me.DropDownList.ListElement.ItemsSortComparer = filterFirstComparer
                Me.DropDownList.ListElement.EndUpdate()
            End Sub
      
            ''' <summary>
            ''' This class is used to compare data items when sorting in ascending order.
            ''' </summary>
            Private Class ListItemFilterAscendingComparer
                Implements System.Collections.Generic.IComparer(Of RadListDataItem)
      
                Public Property filter As String
      
                Public Overridable Function Compare(x As RadListDataItem, y As RadListDataItem) As Integer Implements System.Collections.Generic.IComparer(Of Telerik.WinControls.UI.RadListDataItem).Compare
                    Dim ignoreCase = False
                    If x.Owner IsNot Nothing Then
                        ignoreCase = Not x.Owner.CaseSensitiveSort
                    End If
                    Dim xStart = x.Text.StartsWith(filter, System.StringComparison.InvariantCultureIgnoreCase)
                    Dim yStart = y.Text.StartsWith(filter, System.StringComparison.InvariantCultureIgnoreCase)
                    If xStart AndAlso Not yStart Then
                        Return -1
                    ElseIf yStart AndAlso Not xStart Then
                        Return 1
                    End If
                    Return String.Compare(x.Text, y.Text, ignoreCase)
                End Function
      
            End Class
        End Class
      
        Private Sub Form7_Load(sender As Object, e As System.EventArgs) Handles Me.Load
            RadDropDownList1.AutoCompleteMode = Windows.Forms.AutoCompleteMode.SuggestAppend
            RadDropDownList1.DropDownListElement.AutoCompleteSuggest = New CustomAutoCompleteSuggestHelper(RadDropDownList1.DropDownListElement)
        End Sub
    End Class


  2. Answer
    Peter
    Admin
    Peter avatar
    1148 posts

    Posted 21 Nov 2011 Link to this post

    Hello Clive,

    Thank you for writing.

    This is a not very common scenario and I am afraid that you cannot distinct the items from items that start with a string and from items that contain the text.

    You should implement a custom AutoCompleteSuggestHelper and override the DefaultFilter method.
    I also recommend turning DropDownList's AutoCompleteMode property to Suggest mode only, please refer to the code snipped:

    public class CustomAutoCompleteSuggestHelper : AutoCompleteSuggestHelper
    {
        public CustomAutoCompleteSuggestHelper(RadDropDownListEditorElement element) : base(element)
        {        
        }
        
        protected override bool DefaultFilter(RadListDataItem item)
        {
            return item.Text.ToLower().StartsWith(this.Filter.ToLower()) || item.Text.ToLower().Contains(this.Filter.ToLower());
        }
        
        public override void AutoComplete(KeyPressEventArgs e)
        {
            base.AutoComplete(e);
            if (this.DropDownList.Items.Count > 0)
            {
                this.DropDownList.SelectedIndex = this.DropDownList.FindString(this.Filter);
            }
        }
    }
    //assign the new helper to DropDownList
    radDropDownList.AutoCompleteSuggest = New CustomAutoCompleteSuggestHelper(radDropDownList.DropDownListElement);

    I hope this helps.

    Regards,
    Peter
    the Telerik team

    Q2’11 SP1 of RadControls for WinForms is available for download (see what's new); also available is the Q3'11 Roadmap for Telerik Windows Forms controls.

  3. UI for WinForms is Visual Studio 2017 Ready
  4. Aaron
    Aaron avatar
    3 posts
    Member since:
    Dec 2011

    Posted 06 Jan 2012 Link to this post

    Hello. I am trying to implement the above code sample in the newest version of the telerik RadDropDownList. It looks to me that I have all the correct using statements and included references but I cannot seem to locate the RadDropDownListEditorElement. I can use the RadDropDownListElement in the constructor of the CustomAutoCompleteSuggestHelper, but that does not seem to be exactly what you are indicating in the code.
  5. Peter
    Admin
    Peter avatar
    1148 posts

    Posted 11 Jan 2012 Link to this post

    Hello Aaron,

    The RadDropDownListEditorElement class is located in namespace Telerik.WinControls.UI in Telerik.WinControls.UI.dll assembly.

    namespace Telerik.WinControls.UI
    {
        /// <summary>
        /// Represents a DropDownList element used in RadDropDownListEditor
        /// </summary>
        [RadToolboxItemAttribute(false)]
        public class RadDropDownListEditorElement : ....

    Make sure that you referenced this DLL in your application.

    I hope that you find this information useful. Should you have any other questions, do not hesitate to contact us.

    Greetings,
    Peter
    the Telerik team

    SP1 of Q3’11 of RadControls for WinForms is available for download (see what's new).

  6. Ken
    Ken avatar
    1 posts
    Member since:
    May 2012

    Posted 23 May 2012 Link to this post

    I just wanted to chime in here and say that I was having the same issues as Aaron, and that the RadDropDownListEditorElement  class is not within the Telerik.WinControls.UI.dll assembly as was stated. It actually resides in the Telerik.WinControls.GridView.dll assembly as pointed out here: http://www.telerik.com/help/winforms/t_telerik_wincontrols_ui_raddropdownlisteditorelement.html 

    Furthermore, when attempting to use the solution provided by Peter, I can't get this to work. AutoCompleteSuggest is not a member of a RadDropDownList but it is a member of RadDropDownList.DropDownListElement. And passing a RadDropDownList.DropDownListElement as a RadDropDownListEditorElement does not work: 
    "cannot convert from 'Telerik.WinControls.UI.RadDropDownListElement' to 'Telerik.WinControls.UI.RadDropDownListEditorElement' "



  7. Peter
    Admin
    Peter avatar
    1148 posts

    Posted 28 May 2012 Link to this post

    Hello Ken,

    Thank you for the clarification.

    You are right - the type is located in GridView.dll. The AutoCompleteSuggest inheritor should accept RadDropDownListElement as a parameter.

    public CustomAutoCompleteSuggestHelper(RadDropDownListElement owner) : base(owner){       
    }

    Please accept my apologies for the omission.

    Do not hesitate to contact us if you have other questions.

    Greetings,
    Peter
    the Telerik team
    RadControls for WinForms Q1'12 release is now live! Check out what's new or download a free trial >>
Back to Top
UI for WinForms is Visual Studio 2017 Ready