简体   繁体   中英

How can I programmatically close the dropdown calendar of a datetimepicker or update the dropdown calendar to reflect the .Value property?

HELP, Please?! The issue is because I have an old usercontrol that makes use of a datetimepicker control. If there is no date to be displayed in the textbox of the datetimepicker then the .Value property is set to DateTimePicker.MinimumDateTime. OnValueChanged will update the CustomFormat to " " if the .Value is DateTimePicker.MinimumDateTime. Otherwise, the CustomFormat is "yyy-MM-dd hh:mm:ss tt".

Problem ==> In the DropDown event I check for the minimum datetime. If the .Value is equal to that then I update the .Value to be DateTime.Now. When the dropdown calendar is shown the the calendar is set for 1753-01-01, while the textbox (.Value) shows DateTime.Now.

How do I get the calendar to show the date that corresponds to the .Value property that was updated in the DropDown event? Even if there were a way to 'cancel' the first DropDown event on of the DateTimePicker when the value is changed from DateTimePicker.MinimumDateTime to DateTime.Now I think that could work, because the 2nd time (and subsequent times) the drop-down calendar is displayed the calendar correctly matches the date displayed in the textbox (DateTimePicker.Value).

Here is the code for the events that I have wired up to the DateTimePicker in question :

    private void ValueDatetimePickerOnKeyUp(Object sender, KeyEventArgs e)
    {
        if (e.KeyCode != Keys.Delete && e.KeyCode != Keys.Back)
            return;
        var dp = (DateTimePicker)sender;
        if (dp == null)
            return;
        dp.Value = DateTimePicker.MinimumDateTime;
    }

    private void ValueDatetimePickerDropDown(Object sender, EventArgs e)
    {
        var dp = (DateTimePicker)sender;
        if (dp == null)
            return;
        if (dp.Value == DateTimePicker.MinimumDateTime)
            dp.Value = DateTime.Now;
    }

    private void ValueDatetimePickerValueChanged(Object sender, EventArgs e)
    {
        var dp = (DateTimePicker)sender;
        if (dp == null)
            return;
        dp.CustomFormat = dp.Value == DateTimePicker.MinimumDateTime ? " " : "yyyy-MM-dd hh:mm:ss tt";
    }

I've had some time to figure this out. It's a bit hacky, but basically in the DropDown event handler of the datetimepicker set the ShowUpDown to true and then invoke the Closeup event handler to have ShowUpDown set back to false. This will close the dropdown calendar and force the user to open it again which will then have the correct date shown on the calendar instead of 1/1/1753. The OnKeyUp event handler just allows the user to blank out the textbox value of the datetimepicker if they hit the DEL or Backspace key.

    private void ValueDatetimePickerOnKeyUp(Object sender, KeyEventArgs e)
    {
        //if user presses backspace or delete key then clear the date/time
        if (e.KeyCode != Keys.Delete && e.KeyCode != Keys.Back)
            return;
        var dp = (DateTimePicker)sender;
        if (dp == null)
            return;
        dp.Value = DateTimePicker.MinimumDateTime;
    }

    private void ValueDatetimePickerCloseUp(Object sender, EventArgs e)
    {
        var dp = (DateTimePicker) sender;
        if(dp == null)
            return;
        dp.ShowUpDown = false;
    }

    private void ValueDatetimePickerDropDown(Object sender, EventArgs e)
    {
        var dp = (DateTimePicker)sender;
        if (dp == null)
            return;
        if (dp.Value == DateTimePicker.MinimumDateTime)
        {
            dp.Value = DateTime.Now;
            dp.ShowUpDown = true;
            Invoke((MethodInvoker) (() => ValueDatetimePickerCloseUp(dp, new EventArgs())));
        }
    }

    private void ValueDatetimePickerValueChanged(Object sender, EventArgs e)
    {
        var dp = (DateTimePicker)sender;
        if (dp == null)
            return;
        dp.CustomFormat = dp.Value == DateTimePicker.MinimumDateTime ? " " : "yyyy-MM-dd HH:mm:ss tt";
    }

create your own control and add this:

#region IsInputKey(Keys keyData)
        protected override bool IsInputKey(Keys keyData)
        {
            if (keyData == Keys.Tab
                //|| keyData.Equals(Keys.Up)
                //|| keyData.Equals(Keys.Down)
                //|| keyData.Equals(Keys.Left)
                //|| keyData.Equals(Keys.Right)
                || keyData.Equals(Keys.Enter)
                || keyData.Equals(Keys.Escape)
                || keyData.Equals(Keys.Space)
                )
                return true;

            return base.IsInputKey(keyData);
        }
        #endregion

this will allow all keys that you want to pass on KeyDown Event. ;D hf!!! AND WORKS WITH ANOTHER CONTROLS TOO, like TextBox, DataGridView, etc.

If in need only to forbid drop down menu to be open, you might use simpler version of the solution.

Just switch ShowUpDown property in DropDown event. Change this to your control name.

private void MyDropDown(object sender, EventArgs e)
{
    bool value = this.ShowUpDown;
    this.SuspendLayout();
    this.ShowUpDown = !value;
    this.ShowUpDown = value;
    this.ResumeLayout();
}

Add event handler.

this.DropDown += MyDropDown;

It might be handy to set DoubleBuffered property to true to avoid flickering.

Type type = this.GetType();
System.Reflection.PropertyInfo property;
property = type.GetProperty("DoubleBuffered", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
property.SetValue(control, true, null);

Alternatively you might check if ShowUpDown property is already false, so it will only work for calendar drop down.

private void MyDropDown(object sender, EventArgs e)
{
    if (this.ShowUpDown == false)
    {
        this.SuspendLayout();
        this.ShowUpDown = true;
        this.ShowUpDown = false;
        this.ResumeLayout();
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM