3

I'm trying to determine which control (days, months, years) is selected (highlighted) in a DateTimePicker (WinForms) application. Is there a property, which indicates which control is selected? If so, can I programmatically change just that controls value from another control?

Is there a way to get the focused control of a DateTimePicker?

David Pivovar
  • 115
  • 1
  • 10
  • What is your end goal? Are you able to accomplish what you want by updating the Value property? I seem to recall a way to determine which control has focus within a composite control, but I'm drawing a blank, as it's been several years since I've touched anything in WinForms. – senfo Jul 14 '16 at 22:04
  • The goal is to change DateTime single values (same as I select one column in DateTimePicker and type new value on keyboard). However, I don't want to use system keyboard. I've hoped there would be some property referring to focused child control of DateTimePicker, but there is not as described bellow by @Erikest – David Pivovar Jul 15 '16 at 00:20
  • The way to determine which control has focus within a composite control, do you mean something as IMessageFilter? – David Pivovar Jul 15 '16 at 00:53

2 Answers2

5

Short answer: No, not easily.

DateTimePicker is basically a wrapper around SysDateTimePick32 and doesn't expose any easy to use properties for determining which child window is selected when ShowUpDown is set to true. It doesn't even have private members in its source code that it uses - it's basically just forwarding things on to the underlying com control, ala UnsafeNativeMethods.SendMessage

One way is to send an up then a down and check which part changes. Here's a sample. Create a new winforms application, then add a DateTimePicker, Label and Button. After that, copy the code below into your form1.cs after the using statements:

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public enum DatePart
        {
            YEAR,
            MONTH,
            DAY
        }

        public DatePart part { get; set; }
        private DateTime previous { get; set; }
        private bool checkSelectedPart { get; set; }


        public Form1()
        {
            InitializeComponent();


            dateTimePicker1.ValueChanged += DateTimePicker1_ValueChanged;
            dateTimePicker1.KeyPress += DateTimePicker1_KeyPress;
            previous = dateTimePicker1.Value;

        }

        private void DateTimePicker1_KeyPress(object sender, KeyPressEventArgs e)
        {

        }

        private void DateTimePicker1_ValueChanged(object sender, EventArgs e)
        {
            if (checkSelectedPart)
            {
                var dtp = sender as DateTimePicker;
                TimeSpan change = (dtp.Value - previous);
                var dayChange = Math.Abs(change.Days);
                if (dayChange == 1)
                    part = DatePart.DAY;
                else if (dayChange >= 365)
                    part = DatePart.YEAR;
                else
                    part = DatePart.MONTH;

                previous = dtp.Value;

                label1.Text = part.ToString();
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            checkSelectedPart = true;
            dateTimePicker1.Focus();
            SendKeys.SendWait("{UP}");
            SendKeys.SendWait("{DOWN}");
            checkSelectedPart = false;
            button1.Focus();
        }
    }
}
Erikest
  • 4,997
  • 2
  • 25
  • 37
  • I was worry that it is made this way. Thanks for your answer. – David Pivovar Jul 15 '16 at 00:29
  • One thing you could do is track the change in the date by sending a key up followed by a key down and checking the ValueChanged event to see which part of the date has changed by looking at Timespan from subtracting previousDate from currentDate. I've modified my answer to include a sample of how to do this – Erikest Jul 15 '16 at 21:03
  • Really nice solution, saved me from creating messagefilter or make a mess in UI. Many thanks – David Pivovar Jul 15 '16 at 21:46
  • Works for me inside a UserControl. [code](https://stackoverflow.com/a/61511828/3519108) – gridtrak Apr 29 '20 at 21:19
0

Very clever solution. Had a little strange behavior when the day rolls over. I changed the logic to compare the Year,Month, and Day properties of the values instead of using the timespan.

HAL
  • 1
  • 1
    As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Feb 02 '23 at 06:53