В моем приложении winforms у меня есть настраиваемая экранная клавиатура с десятью клавишами, которая, кажется, отлично работает везде, кроме одного раскрывающегося списка, в котором есть некоторый настраиваемый код фильтрации. Я изо всех сил старался сделать эту клавиатуру неинтерактивной всеми возможными способами. Вот код программной части (numpad0, numpad1 и т. д. — все это метки, если это имеет значение)
public partial class TenKeyForm : Form
{
private const int WM_NCLBUTTONDOWN = 0xA1;
private const int HT_CAPTION = 0x2;
private const int WM_MOUSEACTIVATE = 0x0021, MA_NOACTIVATE = 0x0003;
private const int WS_EX_NOACTIVATE = 0x08000000;
protected override bool ShowWithoutActivation { get { return true; } }
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_MOUSEACTIVATE)
{
m.Result = (IntPtr)MA_NOACTIVATE;
return;
}
base.WndProc(ref m);
}
protected override CreateParams CreateParams
{
get
{
CreateParams createParams = base.CreateParams;
createParams.ExStyle |= WS_EX_NOACTIVATE;
return createParams;
}
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern bool ReleaseCapture();
public TenKeyForm()
{
InitializeComponent();
MouseDown += MouseDownHandler;
numpad0.MouseUp += new MouseEventHandler(delegate (object o, MouseEventArgs e) { SendKeys.Send("0"); });
numpad1.MouseUp += new MouseEventHandler(delegate (object o, MouseEventArgs e) { SendKeys.Send("1"); });
numpad2.MouseUp += new MouseEventHandler(delegate (object o, MouseEventArgs e) { SendKeys.Send("2"); });
numpad3.MouseUp += new MouseEventHandler(delegate (object o, MouseEventArgs e) { SendKeys.Send("3"); });
numpad4.MouseUp += new MouseEventHandler(delegate (object o, MouseEventArgs e) { SendKeys.Send("4"); });
numpad5.MouseUp += new MouseEventHandler(delegate (object o, MouseEventArgs e) { SendKeys.Send("5"); });
numpad6.MouseUp += new MouseEventHandler(delegate (object o, MouseEventArgs e) { SendKeys.Send("6"); });
numpad7.MouseUp += new MouseEventHandler(delegate (object o, MouseEventArgs e) { SendKeys.Send("7"); });
numpad8.MouseUp += new MouseEventHandler(delegate (object o, MouseEventArgs e) { SendKeys.Send("8"); });
numpad9.MouseUp += new MouseEventHandler(delegate (object o, MouseEventArgs e) { SendKeys.Send("9"); });
numpadDot.MouseUp += new MouseEventHandler(delegate (object o, MouseEventArgs e) { SendKeys.Send("."); });
numpadBack.MouseUp += new MouseEventHandler(delegate (object o, MouseEventArgs e) { SendKeys.Send("+{TAB}"); });
numpadForward.MouseUp += new MouseEventHandler(delegate (object o, MouseEventArgs e) { SendKeys.Send("{TAB}"); });
numpadBackspace.MouseUp += new MouseEventHandler(delegate (object o, MouseEventArgs e) { SendKeys.Send("{BS}"); });
SetStyle(ControlStyles.Selectable, false);
}
private void MouseDownHandler(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
ReleaseCapture();
SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
}
}
}
Опять же, это прекрасно работает для различных текстовых полей, маскированных входных данных и т. д., за исключением одного ComboBox. Этот ComboBox имеет дополнительную проверку, чтобы предотвратить ввод недопустимых вариантов. По сути, если в нем есть запись «500» и «550», ввод «5» переходит к «500» в списке и оставляет все, кроме введенного вами «5», выделенным, поэтому следующее нажатие клавиши заменит его, то есть 500
. В этот момент он отклонит все, кроме «5» или «0». Набрав еще 5, выделите 550
и так далее. Вот код для этого бита:
private void ValidateDropDown(object sender, KeyPressEventArgs e)
{
ToolStripComboBox tcb = (ToolStripComboBox)sender;
ComboBox cb = tcb.ComboBox;
cb.DroppedDown = true;
string strFindStr = "";
if (e.KeyChar == (char)8)
{
if (cb.SelectionStart <= 1)
{
cb.Text = "";
return;
}
if (cb.SelectionLength == 0)
strFindStr = cb.Text.Substring(0, cb.Text.Length - 1);
else
strFindStr = cb.Text.Substring(0, cb.SelectionStart - 1);
}
else
{
if (cb.SelectionLength == 0)
strFindStr = cb.Text + e.KeyChar;
else
strFindStr = cb.Text.Substring(0, cb.SelectionStart) + e.KeyChar;
}
int intIdx = -1;
// Search the string in the ComboBox list.
intIdx = cb.FindString(strFindStr);
if (intIdx != -1)
{
cb.SelectedText = "";
cb.SelectedIndex = intIdx;
cb.SelectionStart = strFindStr.Length;
cb.SelectionLength = cb.Text.Length;
e.Handled = true;
}
else
e.Handled = true;
}
Теперь десятиклавишный текст отлично работает везде, кроме этого ComboBox, и этот ComboBox отлично работает, если вы печатаете на настоящей клавиатуре. Экранная клавиатура работает корректно даже при первом нажатии клавиши, но любое последующее событие mousedown в форме с тенкей, кажется, выполняет что-то вроде SelectAll()
в поле со списком, тем самым сводя на нет тщательно установленный выбор. Ввод «55» в приведенном выше примере не приводит к переходу к 550
, а вместо этого дважды переходит к 500
, заменяя весь текст при каждом щелчке.
Что вызывает это странное поведение и как я могу его остановить?
Обновление: похоже, это проблема, связанная с выпадающими списками ToolStrip ComboBox, и ее следовало включить сюда. Также: AutoCompleteMode = AutoCompleteMode.SuggestAppend