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 withnew 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
How to Remove a Table Row with Jquery
JavaScript Request Fullscreen Is Unreliable
Access 'Data-' Attribute Without Jquery
Using the Haversine Formula in JavaScript
Is There a Mechanism to Loop X Times in Es6 (Ecmascript 6) Without Mutable Variables
Why Is Window (And Unsafewindow) Not the Same from a Userscript as from a <Script> Tag
Load "Vanilla" JavaScript Libraries into Node.Js
How to Access Nested JSON Data
Can Jquery Read/Write Cookies to a Browser
Angular 2.1.0 Create Child Component on the Fly, Dynamically
Calling a JavaScript Function Recursively
Create Regexps on the Fly Using String Variables
What's "This" in JavaScript Onclick
With JavaScript, How to Change the Z Index/Layer of an Svg <G> Element
What Is the 'Execution Context' in JavaScript Exactly
Difference Between Obtrusive and Unobtrusive JavaScript