How to Create an Auto-Complete Combobox

C# winforms combobox dynamic autocomplete

Here is my final solution. It works fine with a large amount of data. I use Timer to make sure the user want find current value. It looks like complex but it doesn't.
Thanks to Max Lambertini for the idea.

        private bool _canUpdate = true; 

private bool _needUpdate = false;

//If text has been changed then start timer
//If the user doesn't change text while the timer runs then start search
private void combobox1_TextChanged(object sender, EventArgs e)
{
if (_needUpdate)
{
if (_canUpdate)
{
_canUpdate = false;
UpdateData();
}
else
{
RestartTimer();
}
}
}

private void UpdateData()
{
if (combobox1.Text.Length > 1)
{
List<string> searchData = Search.GetData(combobox1.Text);
HandleTextChanged(searchData);
}
}

//If an item was selected don't start new search
private void combobox1_SelectedIndexChanged(object sender, EventArgs e)
{
_needUpdate = false;
}

//Update data only when the user (not program) change something
private void combobox1_TextUpdate(object sender, EventArgs e)
{
_needUpdate = true;
}

//While timer is running don't start search
//timer1.Interval = 1500;
private void RestartTimer()
{
timer1.Stop();
_canUpdate = false;
timer1.Start();
}

//Update data when timer stops
private void timer1_Tick(object sender, EventArgs e)
{
_canUpdate = true;
timer1.Stop();
UpdateData();
}

//Update combobox with new data
private void HandleTextChanged(List<string> dataSource)
{
var text = combobox1.Text;

if (dataSource.Count() > 0)
{
combobox1.DataSource = dataSource;

var sText = combobox1.Items[0].ToString();
combobox1.SelectionStart = text.Length;
combobox1.SelectionLength = sText.Length - text.Length;
combobox1.DroppedDown = true;

return;
}
else
{
combobox1.DroppedDown = false;
combobox1.SelectionStart = text.Length;
}
}

This solution isn't very cool. So if someone has another solution please share it with me.

How to enable auto complete for a list of files in ComboBox

Those files which you added include path and file name, for example C:\Users\R.Aghaei\Desktop\Test.txt. If you need to see only filename, you can use System.IO.Path.GetFileName(x) to get file names only.

Also if you want to show those filenames just for autocomplete, a TextBox would be enough. If you want to use a ComboBox it's better to add those files to Items collection and then set auto complete source to list items.

AutoCompleteSource is different from Items. You should add those file names to Items to be shown when you click on drop down button. To do so, just use comboBox1.Items.AddRange(files_on_desktop);. Then just set AutoCompleteSourceMode to AutoCompleteSource.ListItems. Then you have both items and auto complete. If you click on drop down button, you will see all available items. If you only type in the box, auto-complete will work for you.

string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
var files = System.IO.Directory.GetFiles(desktopPath, "*.txt")
.Select(x => System.IO.Path.GetFileName(x)).ToArray();
comboBox1.Items.AddRange(files);
comboBox1.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
comboBox1.AutoCompleteSource = AutoCompleteSource.ListItems;

AutoComplete ComboBox C#

On your form, you need to set two properties for your ComboBox:

AutoCompleteMode should be Suggest, Append, or SuggestAppend. I recommend SuggestAppend.

AutoCompleteSource should be ListItems.

How to create autocomplete combobox in PyQt4?

To get the same behaviour as in the example, you will need to change the completion mode of the completer for the combobox.

By default, the completion mode is inline (i.e. just selected text, with no alternatives). To get the drop-down list of possible alternatives, do:

    combobox.completer().setCompletionMode(QtGui.QCompleter.PopupCompletion)

How to create an auto-complete combobox?

Here is a jQuery UI Autocomplete binding that I wrote. It is intended to mirror the options, optionsText, optionsValue, value binding paradigm used with select elements with a couple of additions (you can query for options via AJAX and you can differentiate what is displayed in the input box vs. what is displayed in the selection box that pops up.

You do not need to provide all of the options. It will choose defaults for you.

Here is a sample without the AJAX functionality: http://jsfiddle.net/rniemeyer/YNCTY/

Here is the same sample with a button that makes it behave more like a combo box: http://jsfiddle.net/rniemeyer/PPsRC/

Here is a sample with the options retrieved via AJAX: http://jsfiddle.net/rniemeyer/MJQ6g/

//jqAuto -- main binding (should contain additional options to pass to autocomplete)
//jqAutoSource -- the array to populate with choices (needs to be an observableArray)
//jqAutoQuery -- function to return choices (if you need to return via AJAX)
//jqAutoValue -- where to write the selected value
//jqAutoSourceLabel -- the property that should be displayed in the possible choices
//jqAutoSourceInputValue -- the property that should be displayed in the input box
//jqAutoSourceValue -- the property to use for the value
ko.bindingHandlers.jqAuto = {
init: function(element, valueAccessor, allBindingsAccessor, viewModel) {
var options = valueAccessor() || {},
allBindings = allBindingsAccessor(),
unwrap = ko.utils.unwrapObservable,
modelValue = allBindings.jqAutoValue,
source = allBindings.jqAutoSource,
query = allBindings.jqAutoQuery,
valueProp = allBindings.jqAutoSourceValue,
inputValueProp = allBindings.jqAutoSourceInputValue || valueProp,
labelProp = allBindings.jqAutoSourceLabel || inputValueProp;

//function that is shared by both select and change event handlers
function writeValueToModel(valueToWrite) {
if (ko.isWriteableObservable(modelValue)) {
modelValue(valueToWrite );
} else { //write to non-observable
if (allBindings['_ko_property_writers'] && allBindings['_ko_property_writers']['jqAutoValue'])
allBindings['_ko_property_writers']['jqAutoValue'](valueToWrite );
}
}

//on a selection write the proper value to the model
options.select = function(event, ui) {
writeValueToModel(ui.item ? ui.item.actualValue : null);
};

//on a change, make sure that it is a valid value or clear out the model value
options.change = function(event, ui) {
var currentValue = $(element).val();
var matchingItem = ko.utils.arrayFirst(unwrap(source), function(item) {
return unwrap(item[inputValueProp]) === currentValue;
});

if (!matchingItem) {
writeValueToModel(null);
}
}

//hold the autocomplete current response
var currentResponse = null;

//handle the choices being updated in a DO, to decouple value updates from source (options) updates
var mappedSource = ko.dependentObservable({
read: function() {
mapped = ko.utils.arrayMap(unwrap(source), function(item) {
var result = {};
result.label = labelProp ? unwrap(item[labelProp]) : unwrap(item).toString(); //show in pop-up choices
result.value = inputValueProp ? unwrap(item[inputValueProp]) : unwrap(item).toString(); //show in input box
result.actualValue = valueProp ? unwrap(item[valueProp]) : item; //store in model
return result;
});
return mapped;
},
write: function(newValue) {
source(newValue); //update the source observableArray, so our mapped value (above) is correct
if (currentResponse) {
currentResponse(mappedSource());
}
}
});

if (query) {
options.source = function(request, response) {
currentResponse = response;
query.call(this, request.term, mappedSource);
}
} else {
//whenever the items that make up the source are updated, make sure that autocomplete knows it
mappedSource.subscribe(function(newValue) {
$(element).autocomplete("option", "source", newValue);
});

options.source = mappedSource();
}

ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
$(element).autocomplete("destroy");
});

//initialize autocomplete
$(element).autocomplete(options);
},
update: function(element, valueAccessor, allBindingsAccessor, viewModel) {
//update value based on a model change
var allBindings = allBindingsAccessor(),
unwrap = ko.utils.unwrapObservable,
modelValue = unwrap(allBindings.jqAutoValue) || '',
valueProp = allBindings.jqAutoSourceValue,
inputValueProp = allBindings.jqAutoSourceInputValue || valueProp;

//if we are writing a different property to the input than we are writing to the model, then locate the object
if (valueProp && inputValueProp !== valueProp) {
var source = unwrap(allBindings.jqAutoSource) || [];
var modelValue = ko.utils.arrayFirst(source, function(item) {
return unwrap(item[valueProp]) === modelValue;
}) || {};
}

//update the element with the value that should be shown in the input
$(element).val(modelValue && inputValueProp !== valueProp ? unwrap(modelValue[inputValueProp]) : modelValue.toString());
}
};

You would use it like:

<input data-bind="jqAuto: { autoFocus: true }, jqAutoSource: myPeople, jqAutoValue: mySelectedGuid, jqAutoSourceLabel: 'displayName', jqAutoSourceInputValue: 'name', jqAutoSourceValue: 'guid'" />

UPDATE: I am maintaining a version of this binding here: https://github.com/rniemeyer/knockout-jqAutocomplete

c# combobox autocomplete set display text and value

I may be incorrect here, however using your code I simply added the line autoCompleateCombo.AutoCompleteSource = AutoCompleteSource.ListItems; to your code and it worked as expected.

  autoCompleateCombo.DataSource = new BindingSource(comboSource, null);
autoCompleateCombo.DisplayMember = "Value";
autoCompleateCombo.ValueMember = "Key";
autoCompleateCombo.AutoCompleteSource = AutoCompleteSource.ListItems; //<-- Added this line

AutoComplete ComboBox in JavaFX

I found a solution that's working for me:

public class AutoCompleteComboBoxListener<T> implements EventHandler<KeyEvent> {

private ComboBox comboBox;
private StringBuilder sb;
private ObservableList<T> data;
private boolean moveCaretToPos = false;
private int caretPos;

public AutoCompleteComboBoxListener(final ComboBox comboBox) {
this.comboBox = comboBox;
sb = new StringBuilder();
data = comboBox.getItems();

this.comboBox.setEditable(true);
this.comboBox.setOnKeyPressed(new EventHandler<KeyEvent>() {

@Override
public void handle(KeyEvent t) {
comboBox.hide();
}
});
this.comboBox.setOnKeyReleased(AutoCompleteComboBoxListener.this);
}

@Override
public void handle(KeyEvent event) {

if(event.getCode() == KeyCode.UP) {
caretPos = -1;
moveCaret(comboBox.getEditor().getText().length());
return;
} else if(event.getCode() == KeyCode.DOWN) {
if(!comboBox.isShowing()) {
comboBox.show();
}
caretPos = -1;
moveCaret(comboBox.getEditor().getText().length());
return;
} else if(event.getCode() == KeyCode.BACK_SPACE) {
moveCaretToPos = true;
caretPos = comboBox.getEditor().getCaretPosition();
} else if(event.getCode() == KeyCode.DELETE) {
moveCaretToPos = true;
caretPos = comboBox.getEditor().getCaretPosition();
}

if (event.getCode() == KeyCode.RIGHT || event.getCode() == KeyCode.LEFT
|| event.isControlDown() || event.getCode() == KeyCode.HOME
|| event.getCode() == KeyCode.END || event.getCode() == KeyCode.TAB) {
return;
}

ObservableList list = FXCollections.observableArrayList();
for (int i=0; i<data.size(); i++) {
if(data.get(i).toString().toLowerCase().startsWith(
AutoCompleteComboBoxListener.this.comboBox
.getEditor().getText().toLowerCase())) {
list.add(data.get(i));
}
}
String t = comboBox.getEditor().getText();

comboBox.setItems(list);
comboBox.getEditor().setText(t);
if(!moveCaretToPos) {
caretPos = -1;
}
moveCaret(t.length());
if(!list.isEmpty()) {
comboBox.show();
}
}

private void moveCaret(int textLength) {
if(caretPos == -1) {
comboBox.getEditor().positionCaret(textLength);
} else {
comboBox.getEditor().positionCaret(caretPos);
}
moveCaretToPos = false;
}

}

You can call it with

new AutoCompleteComboBoxListener<>(comboBox);

It's based on this and I customized it to fit my needs.

Feel free to use it and if anybody can improve it, tell me.

How to use auto-complete TextBox or a ComboBox in webform

The equivalent control for a ComboBox in ASP.Net is the DropDownList. You can use JQuery for autocomplete style functionality. See this link: http://jqueryui.com/autocomplete/#combobox.



Related Topics



Leave a reply



Submit