Files
netch/SearchComboBox/SearchComboBox.cs
2021-02-19 17:33:07 +08:00

179 lines
4.5 KiB
C#

using System.Linq;
namespace System.Windows.Forms
{
[System.ComponentModel.DesignerCategory(@"Code")]
public class SearchComboBox : ComboBox
{
public SearchComboBox()
{
AutoCompleteMode = AutoCompleteMode.Suggest;
}
private string prevKeyword;
private string Keyword
{
get => _keyword;
set
{
prevKeyword = _keyword;
if (value == null)
{
_keyword = null;
return;
}
if (_keyword == value)
{
return;
}
_keyword = value;
ReevaluateCompletionList();
}
}
protected override void OnTextChanged(EventArgs e)
{
try
{
if (string.IsNullOrEmpty(Text))
{
if (!IsOriginalItems)
ResetCompletionList();
Keyword = null;
}
else
{
if (AutoFillTag.All(o => o.ToString() != Text))
{
Keyword = Text;
}
}
}
finally
{
base.OnTextChanged(e);
}
}
private object[] AutoFillTag
{
get
{
if (Tag == null)
{
Tag = Items.Cast<object>().ToArray();
}
return (object[]) Tag;
}
}
private bool IsOriginalItems => Items.Count == AutoFillTag.Length;
public void ResetCompletionList()
{
Keyword = null;
try
{
SuspendLayout();
if (IsOriginalItems)
return;
Items.Clear();
Items.AddRange(AutoFillTag);
}
finally
{
ResumeLayout(true);
}
}
private static int findFirstDifIndex(string s1, string s2)
{
for (var i = 0; i < Math.Min(s1.Length, s2.Length); i++)
if (s1[i] != s2[i])
return i;
return -1;
}
private object[] _newList;
private string _keyword;
private void ReevaluateCompletionList()
{
SuspendLayout();
var keyword = Keyword.ToLowerInvariant().Trim();
var selectionStart = SelectionStart;
if (selectionStart == Text.Length)
{
selectionStart = -1;
}
else
{
selectionStart = findFirstDifIndex(prevKeyword, Keyword);
}
try
{
var originalList = AutoFillTag;
if (originalList == null)
{
Tag = originalList = Items.Cast<object>().ToArray();
}
if (string.IsNullOrEmpty(Keyword))
{
ResetCompletionList();
return;
}
else
{
_newList = originalList.Where(x => x.ToString().ToLowerInvariant().Contains(keyword)).ToArray();
}
if (_newList.Any())
{
Items.Clear();
Items.AddRange(_newList.ToArray());
if (!DroppedDown)
{
DroppedDown = true;
}
else
{
// TODO 预期下拉框高度变长则重新打开下拉框
}
Cursor.Current = Cursors.Default;
}
else
{
DroppedDown = false;
Items.Clear();
}
if (selectionStart == -1)
{
Select(Text.Length, 0);
}
else
{
Select(selectionStart + 1, 0);
}
}
finally
{
ResumeLayout(true);
}
}
}
}