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);
}
}