6

目前,在使用日期时间选择器时,输入月份后,您必须点击右箭头或“/”才能将其移至当天。是否有我可以设置的属性或知道该月已完成并移至当天并在用户完成当天后移至一年的方法?这与在旧 FoxPro/Clipper 时代编写的应用程序的行为相同。

4

3 回答 3

11

正如@Wael Dalloul 所说,没有财产可以做你想做的事。经过大量的摆弄和 Spy++ 工作,我找到了以下解决方案:

  1. 继承自System.Windows.Forms.DateTimePicker,并为标志声明私有字段:

    public class DPDateTimePicker : DateTimePicker
    {
        private bool selectionComplete = false;
        private bool numberKeyPressed = false;
    
  2. 为 Win API 定义常量和结构:

        private const int WM_KEYUP = 0x0101;
        private const int WM_KEYDOWN = 0x0100;
        private const int WM_REFLECT = 0x2000;
        private const int WM_NOTIFY = 0x004e;
    
        [StructLayout(LayoutKind.Sequential)]
        private struct NMHDR
        {
           public IntPtr hwndFrom;
           public IntPtr idFrom;
           public int Code;
        }    
    

    System.Runtime.InteropServices为了使用 Win API,还需要包含 using 语句。

  3. OnKeyDown根据按下的键是否为数字覆盖并设置或清除标志(并清除下面的第二个标志)。

    protected override void OnKeyDown(KeyEventArgs e)
    {
        numberKeyPressed = (e.Modifiers == Keys.None && ((e.KeyCode >= Keys.D0 && e.KeyCode <= Keys.D9) || (e.KeyCode != Keys.Back && e.KeyCode >= Keys.NumPad0 && e.KeyCode <= Keys.NumPad9)));
        selectionComplete = false;
        base.OnKeyDown(e);
    }
    
  4. 覆盖WndProc并捕获WM_REFLECT+WM_NOTIFY消息,提取NMHDRfrom lParam,然后在代码为 -759 时设置另一个标志(此事件在使用键盘完全填写其中一个字段并选择日期后触发)。

    protected override void WndProc(ref Message m)
    {
        if (m.Msg == WM_REFLECT + WM_NOTIFY)
        {
            var hdr = (NMHDR)m.GetLParam(typeof(NMHDR));
            if (hdr.Code == -759) //date chosen (by keyboard)
                selectionComplete = true;
        }
        base.WndProc(ref m);
    }
    
  5. 覆盖OnKeyUp,如果设置了两个标志并且按下的键是一个数字,手动调用base.WndProcaWM_KEYDOWN后跟 a WM_KEYUPwith Keys.Right,然后清除你的标志。您可以将lParam这些消息的 设置为 0 而不必担心,HWnd当然是this.Handle.

    protected override void OnKeyUp(KeyEventArgs e)
    {
        base.OnKeyUp(e);
        if (numberKeyPressed && selectionComplete &&
            (e.Modifiers == Keys.None && ((e.KeyCode >= Keys.D0 && e.KeyCode <= Keys.D9) || (e.KeyCode != Keys.Back && e.KeyCode >= Keys.NumPad0 && e.KeyCode <= Keys.NumPad9))))
        {
            Message m = new Message();
            m.HWnd = this.Handle;
            m.LParam = IntPtr.Zero;
            m.WParam = new IntPtr((int)Keys.Right); //right arrow key
            m.Msg = WM_KEYDOWN;
            base.WndProc(ref m);
            m.Msg = WM_KEYUP;
            base.WndProc(ref m);
            numberKeyPressed = false;
            selectionComplete = false;
        }
    }
    

对代码中缺少空行表示歉意,但它不会与空行一起显示,所以我把它们拿出来了。相信我,这是更易读的版本。

于 2010-05-20T08:58:21.253 回答
3

它适用于winforms datetimepicker

在值更改事件上粘贴以下代码

sendkeys.send(".");
于 2016-04-12T05:11:53.187 回答
0

没有属性可以让它像你想要的那样工作,我认为你必须处理按键事件并通过代码来完成。

于 2010-03-08T08:30:03.397 回答