Autocomplete Textbox Control

AutoComplete TextBox Control

This might not be the best way to do things, but should work:

 this.textBox1.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
this.textBox1.AutoCompleteSource = AutoCompleteSource.CustomSource;

private void textBox1_TextChanged(object sender, EventArgs e)
{
TextBox t = sender as TextBox;
if (t != null)
{
//say you want to do a search when user types 3 or more chars
if (t.Text.Length >= 3)
{
//SuggestStrings will have the logic to return array of strings either from cache/db
string[] arr = SuggestStrings(t.Text);

AutoCompleteStringCollection collection = new AutoCompleteStringCollection();
collection.AddRange(arr);

this.textBox1.AutoCompleteCustomSource = collection;
}
}
}

Customize TextBox autocomplete

Looking at your code you have everything you need but 1 line of code. That line is:

This will only work if the start of a string is entered

//Suggestion only
textBoxName.AutoCompleteMode = AutoCompleteMode.Suggest;
//Suggest and autocomplete
textBoxName.AutoCompleteMode = AutoCompleteMode.SuggestAppend;

This will work as a contains method but works with a custom control

You can also make a custom textbox control that fits your needs.

Custom textbox class:

public class AutoCompleteTextBox : TextBox
{
private ListBox _listBox;
private bool _isAdded;
private String[] _values;
private String _formerValue = String.Empty;

public AutoCompleteTextBox()
{
InitializeComponent();
ResetListBox();
}

private void InitializeComponent()
{
_listBox = new ListBox();
this.KeyDown += this_KeyDown;
this.KeyUp += this_KeyUp;
}

private void ShowListBox()
{
if (!_isAdded)
{
Parent.Controls.Add(_listBox);
_listBox.Left = Left;
_listBox.Top = Top + Height;
_isAdded = true;
}
_listBox.Visible = true;
_listBox.BringToFront();
}

private void ResetListBox()
{
_listBox.Visible = false;
}

private void this_KeyUp(object sender, KeyEventArgs e)
{
UpdateListBox();
}

private void this_KeyDown(object sender, KeyEventArgs e)
{
switch (e.KeyCode)
{
case Keys.Enter:
case Keys.Tab:
{
if (_listBox.Visible)
{
Text = _listBox.SelectedItem.ToString();
ResetListBox();
_formerValue = Text;
this.Select(this.Text.Length, 0);
e.Handled = true;
}
break;
}
case Keys.Down:
{
if ((_listBox.Visible) && (_listBox.SelectedIndex < _listBox.Items.Count - 1))
_listBox.SelectedIndex++;
e.Handled = true;
break;
}
case Keys.Up:
{
if ((_listBox.Visible) && (_listBox.SelectedIndex > 0))
_listBox.SelectedIndex--;
e.Handled = true;
break;
}

}
}

protected override bool IsInputKey(Keys keyData)
{
switch (keyData)
{
case Keys.Tab:
if (_listBox.Visible)
return true;
else
return false;
default:
return base.IsInputKey(keyData);
}
}

private void UpdateListBox()
{
if (Text == _formerValue)
return;

_formerValue = this.Text;
string word = this.Text;

if (_values != null && word.Length > 0)
{
string[] matches = Array.FindAll(_values,
x => (x.ToLower().Contains(word.ToLower())));
if (matches.Length > 0)
{
ShowListBox();
_listBox.BeginUpdate();
_listBox.Items.Clear();
Array.ForEach(matches, x => _listBox.Items.Add(x));
_listBox.SelectedIndex = 0;
_listBox.Height = 0;
_listBox.Width = 0;
Focus();
using (Graphics graphics = _listBox.CreateGraphics())
{
for (int i = 0; i < _listBox.Items.Count; i++)
{
if (i < 20)
_listBox.Height += _listBox.GetItemHeight(i);
// it item width is larger than the current one
// set it to the new max item width
// GetItemRectangle does not work for me
// we add a little extra space by using '_'
int itemWidth = (int)graphics.MeasureString(((string)_listBox.Items[i]) + "_", _listBox.Font).Width;
_listBox.Width = (_listBox.Width < itemWidth) ? itemWidth : this.Width; ;
}
}
_listBox.EndUpdate();
}
else
{
ResetListBox();
}
}
else
{
ResetListBox();
}
}

public String[] Values
{
get
{
return _values;
}
set
{
_values = value;
}
}

public List<String> SelectedValues
{
get
{
String[] result = Text.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
return new List<String>(result);
}
}
}

Usage:

string[] nameArray = { "name1", "name2", "name3", "bla name" };
AutoCompleteTextBox tb = new AutoCompleteTextBox();
tb.Values = nameArray;
tb.Location = new Point(10,10);
tb.Size = new Size(25,75);
this.Controls.Add( tb );

I got the code for the custom control from: SO Question - Autocomplete contains

AutoComplete on a TextBox ignoring accentuation

There's still improvements to be done, but this code implements the solution for this, it "appends" a listBox to the textBox, there will be issues when multiple of these exist due to naming, but this should be a good starting point/reference for someone looking for something similar.

public class ExTextBox : TextBox
{
private bool alreadyRun = false;
ListBox suggestions = new ListBox();
int maxSize = 10;
string[] source;
public string Hint

public int MaxSuggestionBoxSize
{
get { return maxSize; }
set { maxSize = value; this.Invalidate(); }
}

protected override void OnCreateControl()
{
if (alreadyRun == false) // This is only supposed to be run once, but in some situations depending on the design of the main form,
{// this might need to be somewhere that gets called multiple times, this variable makes so this code is only run once even in those situations
suggestions.Name = "suggList_" + this.Name;
suggestions.Location = new Point(this.Location.X, (this.Location.Y + this.Size.Height));
suggestions.Size = new Size(this.Size.Width, this.Size.Height);
this.Parent.Controls.Add(suggestions);
this.Parent.Controls["suggList_" + this.Name].MouseDoubleClick += suggList_MouseDoubleClick;
this.Parent.Controls["suggList_" + this.Name].Hide();
alreadyRun = true;
}
base.OnCreateControl();
}

private void suggList_MouseDoubleClick(object sender, System.EventArgs e)
{
this.Text = this.Parent.Controls["suggList_" + this.Name].Text;
}

protected override void OnLeave(EventArgs e)
{
base.OnLeave(e);
if(source != null) // Makes sure this code is only executed when the suggestion box is being used, by checking the existance of the source
{
try
{
if (this.Parent.Controls["suggList_" + this.Name].Focused == false)
{
this.Parent.Controls["suggList_" + this.Name].Hide();
}
}
catch
{

}
}
}

protected override void OnTextChanged(EventArgs e)
{
base.OnTextChanged(e);
AutoCompleteSmart();
}

public void AutoCompleteSmart()
{
if (source != null)
{
suggestions.Items.Clear();
if (this.Text != "")
{
foreach (string a in source)
{
if (RemoveDiacritics(a.ToLower()).Contains(RemoveDiacritics(this.Text.ToLower())))
{
suggestions.Items.Add(a);
}
}
this.Parent.Controls.Remove(suggestions);
if (suggestions.Items.Count < maxSize) // Optional code, defines a limit size for the suggestion box
{
suggestions.Size = new Size(this.Size.Width, ((suggestions.ItemHeight * suggestions.Items.Count) + suggestions.ItemHeight));
}
else
{
suggestions.Size = new Size(this.Size.Width, ((suggestions.ItemHeight * maxSize) + suggestions.ItemHeight));
}

this.Parent.Controls.Add(suggestions);
this.Parent.Controls["suggList_" + this.Name].BringToFront();
this.Parent.Controls["suggList_" + this.Name].Show();
}
else
{
this.Parent.Controls["suggList_" + this.Name].Hide();
}
}
}

public void AutoCompleteSmartSource(string[] _source)
{
source = _source;
}

private static string RemoveDiacritics(string text)
{
var normalizedString = text.Normalize(NormalizationForm.FormD);
var stringBuilder = new StringBuilder();

foreach (var c in normalizedString)
{
var unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c);
if (unicodeCategory != UnicodeCategory.NonSpacingMark)
{
stringBuilder.Append(c);
}
}

return stringBuilder.ToString().Normalize(NormalizationForm.FormC);
}
}

Bind TextBox Controls From Autocomplete TextBox Using ASP.Net core mvc Visual Studio 2017

I've got it working.

To do that, I've slightly modified my controller method:

[HttpGet]
public JsonResult GetProvinceOfBirth(string fetch)
{
var query = (from c in _listaCIcontext.Listacomuniitaliani
where c.Comune == fetch
select c.Provincia).ToList();

return Json(query);
}

querying down to the provincia property.

Additionally, and this is the core of the solution, I've used the .on('focusout') method like that:

$("#searchCityOfBirth").on('focusout', function () {
$.ajax({
url: "/Criminals/GetProvinceOfBirth",
type: "GET",
dataType: "json",
data: { fetch: $("#searchCityOfBirth").val()},
success: function (query) {
$("#searchProvinceOfBirth").val(query[0]);
},
});
});

For sure I will add some error handling to complete the code .... and invest more time for my knowledge in jQuery & AJAX

How to get autocomplete text box value when post in ASP.NET with DevExtreme

Are you going to submit the form and bind the field value to the Account model in the httpost action? If so, you should add the Name attribute to the Autocomplete widget.

Maybe you can refer to the below codes:

Model:

public class TestModel
{
public Account Account { get; set; }
}

public class Account
{
public string FullName { get; set; }
}

View:

@model TestModel

<h2>Home</h2>

<form asp-action="Test">
<div class="form-group">
<label asp-for="@Model.Account.FullName" class="control-label"></label>

@(Html.DevExtreme().Autocomplete()
.DataSource(d => d.Mvc().Controller("Offer").LoadAction("GetFullNames"))
.ShowClearButton(true)
.Placeholder("Type name")
.Name("FullName")
)

<input type="submit" value="submit" class="btn btn-primary" />
</div>
</form>

OfferController:

public class OfferController : Controller
{

[HttpGet]
public object GetFullNames(DataSourceLoadOptions loadOptions)
{
List<string> names = new List<string>
{
"aa", "ab", "bb", "bc", "cc", "cd"
};

return DataSourceLoader.Load(names, loadOptions);
}
}

HomeController:

[HttpPost]
public IActionResult Test(Account account)
{

return Ok(account);
}

Result:

Sample Image

How to Invoke autocomplete jquery function when textbox clicked in ASP.net

Try adding the [PageMethod] or [WebMethod] Annotations above the

Public Function GetClientName() As List(Of String)

End Function


Related Topics



Leave a reply



Submit