用C#编写可空的DateTimePicker

There are many posts on the internet about creating a simple and easy nullable DateTimePicker for use in your .Net applications. However, I have noticed that most have gone far beyond the "simple" aspect of this and ventured into the more "complex" avenues.

互联网上有许多关于创建一个简单的,可为空的DateTimePicker以便在.Net应用程序中使用的文章。 但是,我已经注意到,大多数方法已经超出了此方法的“简单”方面,而进入了更“复杂”的途径。

This brings me to my post on a very simple and basic nullable DateTimePicker object.  It is really easy to modify to suit your needs if the date formats do not match what you need.  It is based on the simple notion that if any date is less than the year 1900, it will treat it as a NULL value.

这使我在一个非常简单且基本为空的DateTimePicker对象上发表文章。 如果日期格式与您的需求不符,那么修改它很容易满足您的需求。 它基于一个简单的概念,即如果任何日期小于1900年,它将被视为NULL值。

The trick to this control however, is NOT using the inherited Value property of the control, but to use the new m_Value property.  It is cast as a DateTime? which allows you a little bit more flexibility.

但是,此控件的窍门不是使用控件的继承的Value属性,而是使用新的m_Value属性。 是否将其转换为DateTime? 这使您更具灵活性。

We start the nullable calendar with inheriting from the DateTimePicker native control, and setting some of our customizable private members.  

我们通过从DateTimePicker本机控件继承来开始可为空的日历,并设置一些可自定义的私有成员。

The mValue variable is used internally to hold the actual date/time that we want to pass along.  CustomDateFormat is the format of the date as it will be displayed in this control -- you can change this to be any compatible date format.  NoDateFormat is the format of the date/text as it will be displayed if the mValue member is null.  Lastly, the "null" date value that we will parse for is set to 1753-01-01.  This will indicate to our control that the date value should appear as NULL.

mValue变量在内部用于保存我们希望传递的实际日期/时间。 CustomDateFormat是日期格式,因为它将在此控件中显示-您可以将其更改为任何兼容的日期格式。 NoDateFormat是日期/文本的格式,如果mValue成员为null,则将显示该日期/文本。 最后,我们将解析的“空”日期值设置为1753-01-01。 这将向我们的控件指示日期值应显示为NULL。

public class SuperCalendar : DateTimePicker
    {
        private DateTime? mValue = null;  
        private string CustomDateFormat = "MMM dd / yyyy";
        private string NoDateFormat = "--- -- / ----";
        private DateTime NullDate = DateTime.Parse("1753-01-01");

        public SuperCalendar() : base() { }

I have used a property called 'm_value' as the actual date property we will use in our application.  You can give this any name you want, I have decided to use 'm_value' for my purposes, but really anything will do.  The premise behind this is quite simple.  We allow a GET and SET on this property.  The GET will simply get the value of our private mValue member.  The SET will accept NULL as a value and will either set the Value property with the NULL date identifier or an actual date.

我已经使用了一个名为“ m_value”的属性作为我们将在应用程序中使用的实际日期属性。 您可以给它取任何您想要的名称,我已经决定使用'm_value'来实现我的目的,但实际上任何事情都可以。 这背后的前提很简单。 我们允许对该属性进行GET和SET设置。 GET只会获取我们的私有mValue成员的值。 SET将接受NULL作为值,并使用NULL日期标识符或实际日期设置Value属性。

        public DateTime? m_value
        {
            get
            {
                return mValue;
            }
            set
            {
                if (value != null)
                {
                    this.Value = value.Value;
                }
                else
                {
                    this.Value = NullDate;
                }
            }
        }

The magic of this control happens by overriding the OnDropDown, OnCloseUp and WndProc events/functions.  Overriding these allows us to set the displayed date on the calendar dropdown and also obtain the selected date (if any).  So this is somewhat the tricky part of the control.  You have to understand that the BASE.VALUE and THIS.VALUE are handled separately.  Knowing this, the calendar dropdown uses the Base.Value property to set the displayed date.  Because the date can be null, we don't want to display 1753-01-01 as the starting date - this can be somewhat irritating for users, so we set the Base.Value to the current date.

通过重写OnDropDown,OnCloseUp和WndProc事件/函数可以实现此控件的魔力。 覆盖这些允许我们在日历下拉菜单上设置显示的日期,并获得选定的日期(如果有)。 因此,这在控件中有些棘手。 您必须了解BASE.VALUE和THIS.VALUE是分开处理的。 知道了这一点,日历下拉菜单使用Base.Value属性设置显示的日期。 由于日期可以为空,因此我们不希望将1753-01-01显示为开始日期-这可能会给用户带来不便,因此我们将Base.Value设置为当前日期。

By overriding the WndProc function, we can capture the moment where a user selects a date from the dates shown.  Trapping this allows us to set the This.Value with the newly selected date from base.Value.

通过重写WndProc函数,我们可以捕获用户从显示的日期中选择日期的时刻。 进行陷印可让我们使用从base.Value中新选择的日期来设置This.Value。

        protected override void OnDropDown(EventArgs eventargs)
        {
            if (Value.Year < 1900)
            {
                base.Value = DateTime.Now;
            } else {
                base.Value = mValue;
            }
            base.OnDropDown(eventargs);
        }

        protected override void OnCloseUp(EventArgs eventargs)
        {
           base.OnCloseUp(eventargs);
        }

        protected override void WndProc(ref Message m)
        {
            if (m.Msg == 0x4e)                        
            {
                NMHDR nm = (NMHDR)m.GetLParam(typeof(NMHDR));
                if (nm.Code == -746 || nm.Code == -722)
                {
                    this.Value = base.Value;
                }
            }
            base.WndProc(ref m);
        }

Now for the last step in our Nullable DateTimePicker.  We have now received our new date or set it from our application.  In any event, we now have to override the Value property so we can control the nullibility of our date.  Basically, in this property, we are returning 1753-01-01 if our mValue member is null and the actual date if we have a real date.  When setting this value, we are checking to see if the date passed in is less than the year 1900.  If so, we are determining that it should be a null date and thereby setting our private mValue member as NULL and the CustomFormat to our NoDateFormat, otherwise, we are setting our mValue with a real date and setting our CustomFormat to be our CustomDateFormat.  

现在进入我们的Nullable DateTimePicker的最后一步。 现在,我们已经收到了新日期或从应用程序中设置了它。 无论如何,现在我们都必须重写Value属性,以便我们可以控制日期的可为空性。 基本上,在此属性中,如果我们的mValue成员为null,则返回1753-01-01;如果我们有实际日期,则返回实际日期。 设置此值时,我们正在检查传入的日期是否小于1900年。如果是,则确定它应该为空日期,从而将我们的私有mValue成员设置为NULL,并将CustomFormat设置为NoDateFormat。 ,否则,我们将为mValue设置一个实际日期,并将CustomFormat设置为CustomDateFormat。

public new DateTime Value
        {
            get
            {
                if (mValue == null)
                {
                    return NullDate;                    
                }
                else
                {
                    return mValue.Value;
                }
            }
            set
            {
                if (value.Year < 1900)
                {
                    mValue = null;
                    CustomFormat = NoDateFormat;
                }
                else
                {
                    mValue = value;
                    base.Value = value;
                    CustomFormat = CustomDateFormat;
                }
            }
        }

This is it! Just a few overridden functions/methods and you now have a fully functional Nullable DateTimePicker - aptly named "SuperCalendar".

就是这个! 仅覆盖了一些重写的​​函数/方法,您现在有了一个功能齐全的Nullable DateTimePicker-恰当地命名为“ SuperCalendar”。

I have provided the full source below for reference.  I hope this post is useful and a good starting point to more complex iterations of this "Super" control.

我在下面提供了完整的源供参考。 我希望这篇文章对这个“超级”控件的更复杂的迭代是有用的,并且是一个很好的起点。

public class SuperCalendar : DateTimePicker
    {
        private DateTime? mValue = null;
        private string CustomDateFormat = "MMM dd / yyyy";
        private string NoDateFormat = "--- -- / ----";
        private DateTime NullDate = DateTime.Parse("1753-01-01");

        public SuperCalendar() : base() { }

        public DateTime? m_value
        {
            get
            {
                return mValue;
            }
            set
            {
                if (value != null)
                {
                    this.Value = value.Value;
                }
                else
                {
                    this.Value = NullDate;
                }
            }
        }

        protected override void OnDropDown(EventArgs eventargs)
        {
            if (Value.Year < 1900)
            {
                
            }
            base.Value = DateTime.Now;
            base.OnDropDown(eventargs);
        }

        protected override void OnCloseUp(EventArgs eventargs)
        {
           base.OnCloseUp(eventargs);
        }

        protected override void WndProc(ref Message m)
        {
            if (m.Msg == 0x4e)                        
            {
                NMHDR nm = (NMHDR)m.GetLParam(typeof(NMHDR));
                if (nm.Code == -746 || nm.Code == -722)
                {
                    this.Value = base.Value;
                }
            }
            base.WndProc(ref m);
        }

        public new DateTime Value
        {
            get
            {
                if (mValue == null)
                {
                    return NullDate;                    
                }
                else
                {
                    return mValue.Value;
                }
            }
            set
            {
                if (value.Year < 1900)
                {
                    mValue = null;
                    CustomFormat = NoDateFormat;
                }
                else
                {
                    mValue = value;
                    base.Value = value;
                    CustomFormat = CustomDateFormat;
                }
            }
        }

        protected override void OnKeyDown(KeyEventArgs e)
        {
            base.OnKeyDown(e);

            if (e.KeyCode == Keys.Delete)
                this.Value = DateTime.Parse("1753-01-01");

        }

        [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
        private struct NMHDR
        {
            public IntPtr HwndFrom;
            public int IdFrom;
            public int Code;
        }
    }

翻译自: https://www.experts-exchange.com/articles/10145/Writing-a-NULLable-DateTimePicker-in-C.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值