/****************************************************************************** * SunnyUI 开源控件库、工具类库、扩展类库、多页面开发框架。 * CopyRight (C) 2012-2024 ShenYongHua(沈永华). * QQ群:56829229 QQ:17612584 EMail:SunnyUI@QQ.Com * * Blog: https://www.cnblogs.com/yhuse * Gitee: https://gitee.com/yhuse/SunnyUI * GitHub: https://github.com/yhuse/SunnyUI * * SunnyUI.dll can be used for free under the GPL-3.0 license. * If you use this code, please keep this note. * 如果您使用此代码,请保留此说明。 ****************************************************************************** * 文件名称: UINumPadTextBox.cs * 文件说明: 模拟数字键盘输入框 * 当前版本: V3.3 * 创建日期: 2023-03-18 * * 2023-03-18: V3.3.3 增加文件说明 * 2023-03-26: V3.3.3 增加默认事件ValueChanged,下键盘Enter事件相应此事件 * 2023-03-26: V3.3.4 增加了最大值、最小值等属性 * 2023-06-11: V3.6.6 下拉框可选放大倍数为2 * 2024-09-03: V3.7.0 增加ShowDropDown()弹窗方法 ******************************************************************************/ using System; using System.ComponentModel; using System.Drawing; using System.Runtime.InteropServices; using System.Windows.Forms; namespace Sunny.UI { [ToolboxItem(true)] [DefaultEvent("ValueChanged")] public class UINumPadTextBox : UIDropControl, IToolTip, IHideDropDown { public UINumPadTextBox() { InitializeComponent(); edit.KeyDown += Edit_KeyDown; edit.CanEmpty = true; fullControlSelect = true; } [Browsable(false)] public override string[] FormTranslatorProperties { get; } public delegate void OnValueChanged(object sender, string value); public event OnValueChanged ValueChanged; private NumPadType numPadType = NumPadType.Text; [DefaultValue(NumPadType.Text)] [Description("小键盘类型"), Category("SunnyUI")] public NumPadType NumPadType { get => numPadType; set { numPadType = value; edit.MaxLength = 32767; switch (numPadType) { case NumPadType.Text: edit.Type = UITextBox.UIEditType.String; break; case NumPadType.Integer: edit.Type = UITextBox.UIEditType.Integer; break; case NumPadType.Double: edit.Type = UITextBox.UIEditType.Double; break; case NumPadType.IDNumber: edit.Type = UITextBox.UIEditType.String; edit.MaxLength = 18; break; default: edit.Type = UITextBox.UIEditType.String; break; } edit.Text = ""; } } private void Edit_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Down || e.KeyCode == Keys.Up) { if (!NumPadForm.Visible) ShowDropDown(); } else if (e.KeyCode == Keys.Escape) { NumPadForm.Close(); } else if (e.KeyCode == Keys.Return) { if (NumPadForm.Visible) { NumPadForm.Close(); } else { ShowDropDown(); } } else { base.OnKeyDown(e); } } public Control ExToolTipControl() { return edit; } private readonly UINumPadItem item = new UINumPadItem(); private UIDropDown numPadForm; private UIDropDown NumPadForm { get { if (numPadForm == null) { numPadForm = new UIDropDown(item); if (numPadForm != null) { numPadForm.VisibleChanged += NumBoardForm_VisibleChanged; numPadForm.ValueChanged += NumBoardForm_ValueChanged; } } return numPadForm; } } [DllImport("user32.dll", EntryPoint = "PostMessageA", SetLastError = true)] public static extern int PostMessage(IntPtr hWnd, int Msg, Keys wParam, int lParam); public const int WM_CHAR = 256; private void NumBoardForm_ValueChanged(object sender, object value) { int start = edit.SelectionStart; switch ((int)value) { case 88: if (Text.Length == 17) { Win32.User.PostMessage(edit.Handle, WM_CHAR, (int)value, 0); edit.SelectionStart = start; edit.Select(start, 0); //this.Focus(); } break; case 13: ValueChanged?.Invoke(this, Text); break; default: Win32.User.PostMessage(edit.Handle, WM_CHAR, (int)value, 0); edit.SelectionStart = start; edit.Select(start, 0); //this.Focus(); break; } } const uint KEYEVENTF_EXTENDEDKEY = 0x1; const uint KEYEVENTF_KEYUP = 0x2; [DllImport("user32.dll")] static extern short GetKeyState(int nVirtKey); [DllImport("user32.dll")] static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, uint dwExtraInfo); public enum VirtualKeys : byte { VK_NUMLOCK = 0x90, //数字锁定键 VK_SCROLL = 0x91, //滚动锁定 VK_CAPITAL = 0x14, //大小写锁定 VK_A = 62 } public bool CapsState; public static bool GetState(VirtualKeys Key) { return (GetKeyState((int)Key) == 1); } public static void SetState(VirtualKeys Key, bool State) { if (State != GetState(Key)) { keybd_event((byte)Key, 0x45, KEYEVENTF_EXTENDEDKEY | 0, 0); keybd_event((byte)Key, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0); } } private void NumBoardForm_VisibleChanged(object sender, System.EventArgs e) { dropSymbol = SymbolNormal; if (NumPadForm.Visible) { dropSymbol = SymbolDropDown; } if (!NumPadForm.Visible) { SetState(VirtualKeys.VK_CAPITAL, CapsState); } Invalidate(); } public void ShowDropDown() { UIKeyBoardTextBox_ButtonClick(this, EventArgs.Empty); } private void UIKeyBoardTextBox_ButtonClick(object sender, System.EventArgs e) { if (NumPadForm.Visible) { NumPadForm.Close(); } else { ShowDropDownEx(); } } private void ShowDropDownEx() { NumPadForm.AutoClose = false; item.NumPadType = NumPadType; item.SetDPIScale(); item.SetStyleColor(UIStyles.ActiveStyleColor); if (numPadType == NumPadType.IDNumber) { CapsState = GetState(VirtualKeys.VK_CAPITAL); SetState(VirtualKeys.VK_CAPITAL, true); } if (!NumPadForm.Visible) { Size size = SizeMultiple == 1 ? new Size(320, 195) : new Size(320, 390); NumPadForm.Show(this, size); } edit.Focus(); } [DefaultValue(1)] [Description("弹窗放大倍数,可以1或者2"), Category("SunnyUI")] public int SizeMultiple { get => item.SizeMultiple; set => item.SizeMultiple = value; } private void InitializeComponent() { SuspendLayout(); // // edit // edit.Leave += edit_Leave; // // UINumPadTextBox // Name = "UINumPadTextBox"; ShowBuiltInResources = true; ButtonClick += UIKeyBoardTextBox_ButtonClick; ResumeLayout(false); PerformLayout(); } /// /// 必需的设计器变量。 /// private System.ComponentModel.IContainer components = null; /// /// 清理所有正在使用的资源。 /// /// 如果应释放托管资源,为 true;否则为 false。 protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } item?.Dispose(); numPadForm?.Dispose(); base.Dispose(disposing); } private void edit_Leave(object sender, EventArgs e) { HideDropDown(); } public void HideDropDown() { try { if (NumPadForm != null && NumPadForm.Visible) NumPadForm.Close(); } catch { } } /// /// 当InputType为数字类型时,能输入的最大值 /// [Description("当InputType为数字类型时,能输入的最大值。"), Category("SunnyUI")] [DefaultValue(2147483647D)] public double Maximum { get => edit.MaxValue; set => edit.MaxValue = value; } /// /// 当InputType为数字类型时,能输入的最小值 /// [Description("当InputType为数字类型时,能输入的最小值。"), Category("SunnyUI")] [DefaultValue(-2147483648D)] public double Minimum { get => edit.MinValue; set => edit.MinValue = value; } [Description("浮点数,显示文字小数位数"), Category("SunnyUI")] [DefaultValue(2)] public int DecimalPlaces { get => edit.DecLength; set => edit.DecLength = Math.Max(value, 0); } } }