DateTimePicker автоматически переходит к следующей части даты

В настоящее время при использовании средства выбора даты и времени после ввода месяца вам нужно либо нажать стрелку вправо, либо клавишу "/", чтобы перейти к дню. Есть ли свойство, которое я могу установить, или способ узнать, что месяц закончен, и перейти к дню и перейти к году после того, как пользователь завершил день? Это то же самое поведение с приложениями, написанными в старые времена FoxPro/Clipper.

3 ответа

Как говорит @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.

  3. Override 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. Override WndProc и поймать WM_REFLECT+WM_NOTIFY сообщение, извлеките NMHDR от 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. Override OnKeyUp и если оба флага установлены, и нажатая клавиша была числом, вызовите вручную base.WndProc с WM_KEYDOWN с последующим WM_KEYUP с 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;
        }
    }
    

Извините за отсутствие пустых строк в коде, но он не будет отображаться правильно с пустыми строками, поэтому я их убрал. Поверьте мне, это более читаемая версия.

Это будет работать на winforms datetimepicker

при изменении значения вставьте следующий код

sendkeys.send(".");

Нет свойства, чтобы заставить его работать так, как вы хотите, я думаю, вы должны обработать событие нажатия клавиши и сделать это с помощью кода.

Другие вопросы по тегам