Help with RadTextboxControl Autocomplete

5 posts, 0 answers
  1. Randy
    Randy avatar
    12 posts
    Member since:
    Oct 2012

    Posted 05 Sep 2014 Link to this post

    In UI for WinForms, I'm having trouble understanding how to link a RadTextBoxControl to a database containing ~ 60,000 part numbers.  Obviously I don't want to fetch the whole list into RAM, I want to query the db every time the user types a character.  What event do I trigger on to refresh the list, and how do I specify the query itself (search parameters, number of results returned, etc.)?

    I've tried binding the .AutoCompleteDataSource to a List<string> and updating that list via the database every time the TextChanged event fires, but it doesn't work - updating the datasource doesn't re-bind to the control, and setting the property again seems to wipe out any autocomplete in progress.

    private void radPnTextBox_TextChanged(object sender, EventArgs e)
    {
        //populate autocomplete list
        if (VDO != null)
        {
            //fetch updated list from database
            PnDropdownList = VDO.GetAutoCompletePnDescription(radPnTextBox.Text.ToUpper());
     
            //re-bind the this list by re-assigning the datasource
            radPnTextBox.AutoCompleteDataSource = PnDropdownList;
        }
    }


    Are there any code examples of using autocomplete function bound to a database?

    Thanks,
    Randy
  2. George
    Admin
    George avatar
    500 posts

    Posted 09 Sep 2014 Link to this post

    Hello Randy,

    Thank you for writing.

    RadDropDownList without its arrow button will be perfect for this case. You can create a custom AutoCompleteSuggest helper which will take the items from a remote database instead of filtering existing ones, in my example it will take them from a collection. Please, refer to the code below:
    public partial class Form1 : Form
    {
        List<string> serverSideItems = new List<string>();
     
        public Form1()
        {
            InitializeComponent();
     
            Enumerable.Range(0, 5000).ToList().ForEach(x => serverSideItems.Add("Item " + x));
     
            RadDropDownList list = new RadDropDownList
            {
                Parent = this,
                Dock = DockStyle.Top,
            };
     
            list.DropDownListElement.ArrowButton.Visibility = Telerik.WinControls.ElementVisibility.Collapsed;
     
            list.AutoCompleteMode = AutoCompleteMode.Suggest;
            list.DropDownListElement.AutoCompleteSuggest = newServerAutoCompleteSuggestHelper(list.DropDownListElement, serverSideItems);
        }
    }
     
    class ServerAutoCompleteSuggestHelper : AutoCompleteSuggestHelper
    {
        private IList<string> serverSideItems;
        private bool endingUpdate;
     
        public ServerAutoCompleteSuggestHelper(RadDropDownListElement owner, IList<string> serverSideItems)
            :base(owner)
        {
            this.serverSideItems = serverSideItems;
        }
     
        protected override void SyncOwnerElementWithSelectedIndex()
        {
            if (!endingUpdate)
            {
                base.SyncOwnerElementWithSelectedIndex();
            }
            else
            {
                this.endingUpdate = false;
            }
        }
     
        public override void ApplyFilterToDropDown(string filter)
        {
            this.DropDownList.ListElement.BeginUpdate();
            this.DropDownList.ListElement.Items.Clear();
     
            //make sure that this line is synchronous, if it is asynchronous consider using await/async - http://msdn.microsoft.com/en-us/library/hh191443.aspx
            List<string> newItems = serverSideItems.AsParallel().Where(x => x.Contains(filter)).ToList();
     
            newItems.ForEach(x => this.DropDownList.ListElement.Items.Add(newRadListDataItem(x)));
     
            this.endingUpdate = true;
            this.DropDownList.ListElement.EndUpdate();
        }
    }

    Feel free to modify it as you like, since the current implementation is just a mere example.

    As a side note, in order to allow RadDropDownList refresh when its data source changes it should be a BindingList, since a simple List does not support notifications.

    Let me know, should you have other questions.

    Regards,
    George
    Telerik
     
    Check out Telerik Analytics, the service which allows developers to discover app usage patterns, analyze user data, log exceptions, solve problems and profile application performance at run time. Watch the videos and start improving your app based on facts, not hunches.
     
  3. UI for WinForms is Visual Studio 2017 Ready
  4. Randy
    Randy avatar
    12 posts
    Member since:
    Oct 2012

    Posted 09 Sep 2014 in reply to George Link to this post

    George,
    Thanks for your post.  This looks like exactly what I needed.  When I tried to test it, I get an error at "newRadListDataItem" - is that supposed to be defined somewhere?

    Also, as I'm on .NET 3.5, I can't use .AsParallel, but perhaps I can find a way around that, or migrate to .NET 4.0.

    Thanks again,
    Randy
  5. Randy
    Randy avatar
    12 posts
    Member since:
    Oct 2012

    Posted 09 Sep 2014 in reply to Randy Link to this post

    Disregard the question about newRadListDataItem, I see now there should have been a space after the new keyword.  The same with newServerAutoCompleteSuggestHelper.

    Also I understand now that the AsParallel is not necessary, it seems it is only a slight speedup for multi-core systems - I had thought initially it was an asynchronous call.  Since I will be fetching just small lists from the database, there should be no need for this optimization.

    I would like to have the list behave in the SuggestAppend mode though, and as I'm looking through the API documentation I see an AutoCompleteAppendHelper that is fairly different (no ApplyFilterToDropDown method).  I don't see an AutoCompleteSuggestAppendHelper. Is there any example code for implementing SuggestAppend mode?

    Thanks again,
    Randy
  6. George
    Admin
    George avatar
    500 posts

    Posted 12 Sep 2014 Link to this post

    Hello Randy,

    Thank you for writing.

    The AppendHelper is a bit different. Below you can see a sample implementation:
    class ServerAutoCompleteAppendHelper : AutoCompleteAppendHelper
    {
        private IList<string> serverSideItems;
     
        public ServerAutoCompleteAppendHelper(RadDropDownListElement owner, IList<string> serverSideItems)
            : base(owner)
        {
            this.serverSideItems = serverSideItems;
        }
     
        public override void AutoComplete(KeyPressEventArgs e)
        {
            string findString = this.GetFindString(e);
     
            string result = this.serverSideItems.Where(x => x.StartsWith(findString) && x != findString).OrderBy(x => x.Length).FirstOrDefault();
            if (result != null)
            {
                Owner.EditableElementText = result;
                Owner.SelectionStart = findString.Length;
                Owner.SelectionLength = Owner.EditableElementText.Length;
                e.Handled = true;
            }
        }
     
        private Func<KeyPressEventArgs, string> getFindString;
        public Func<KeyPressEventArgs, string> GetFindString
        {
            get
            {
                if (this.getFindString == null)
                {
                    var method = typeof(AutoCompleteAppendHelper).GetMethod("CreateFindString", BindingFlags.Instance | BindingFlags.NonPublic);
                    this.getFindString = (Func<KeyPressEventArgs, string>)Delegate.CreateDelegate(typeof(Func<KeyPressEventArgs, string>), this, method);
                }
     
                return this.getFindString;
            }
        }
    }

    I hope this information is helpful.

    Regards,
    George
    Telerik
     
    Check out Telerik Analytics, the service which allows developers to discover app usage patterns, analyze user data, log exceptions, solve problems and profile application performance at run time. Watch the videos and start improving your app based on facts, not hunches.
     
Back to Top
UI for WinForms is Visual Studio 2017 Ready