This is a migrated thread and some comments may be shown as answers.

Help with RadTextboxControl Autocomplete

4 Answers 204 Views
AutoCompleteBox
This is a migrated thread and some comments may be shown as answers.
Randy
Top achievements
Rank 1
Randy asked on 06 Sep 2014, 01:16 AM
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

4 Answers, 1 is accepted

Sort by
0
George
Telerik team
answered on 09 Sep 2014, 02:28 PM
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.
 
0
Randy
Top achievements
Rank 1
answered on 09 Sep 2014, 03:04 PM
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
0
Randy
Top achievements
Rank 1
answered on 09 Sep 2014, 03:52 PM
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
0
George
Telerik team
answered on 12 Sep 2014, 01:02 PM
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.
 
Tags
AutoCompleteBox
Asked by
Randy
Top achievements
Rank 1
Answers by
George
Telerik team
Randy
Top achievements
Rank 1
Share this question
or