|
Great solution! Easy to understand and works perfectly! Converted it to VB to make sense to my 70 year old brain.
-Thank you!
|
|
|
|
|
|
Chào Mr Trí,
Mình dùng control thấy rất hay nhưng có 1 chổ mình cần giúp.
Khi sử dụng Customer Format thì Control không hiểu.
Mr Trí có thể giúp mình chổ này không?
Thanks,
DoCaoTri
|
|
|
|
|
Hi Tri,
It seem does not work in .NET 4.0 forward ?
|
|
|
|
|
If this control is used with a tab control and you don't view the tab with the Nullable DTP, the DTP value/nullvalue is NULL. If you then save your record, any date that was there is overwritten with NULL.
I understand that the BINDING COMPLETE event of a BindingSource is not called until a control is visible. But, the original DTP receives a value before the Binding Complete event.
How can I get the Nullable DTP to populate the .NullableValue like the original DTP populates the .Value without being visible?
|
|
|
|
|
|
Hello There,
I am trying to download the source files, however I am not able to. When I clicked on the "Download Source Files" link, it routed me to the download page below. When I click on Nullable DateTimePicker link, it did not prompt me to save the file or anything. Do you know if the Souce Files are still available for download? If so, would you please show me how to download them? Any help is greatly appreciated!
File Download
Downloading Nullable_DateTimePicker_src.zip from the article Nullable DateTimePicker.
Note: If someone knows the answer, please put it in a new post as I don't have access to my email account from where I am right now.
Thanks much!!!!!
modified 31-Oct-12 11:42am.
|
|
|
|
|
I have spent half a day trying to determine why my search functionality was not working... I was trying to bind a null date to a datetimepicker... Interesting how this does not work...
Unless you have this excellent little control
Thank you for the Nullable Datetimepicker 
|
|
|
|
|
This is exactly the way I would like it to work.
I tweaked it a bit to be a nullable DateTime.
|
|
|
|
|
gemini_dk wrote:
This is exactly the way I would like it to
work. I tweaked it a bit to be a nullable DateTime.
... then you should post your tweak for others...
Regards
|
|
|
|
|
It works!!! Thank's a lot.
If you don't want hour into your sql server field, add this and set datetimepicker format to 'short'
Public Shadows Property Value() As Object
Get
If MyBase.Checked Then
If MyBase.Format = DateTimePickerFormat.Short Then
Return MyBase.Value.Date
Else
Return MyBase.Value
End If
Else
Return System.DBNull.Value
End If
End Get
Set(ByVal Value)
If System.Convert.IsDBNull(Value) Then
MyBase.Checked = False
Else
MyBase.Value = Value
MyBase.Checked = True
End If
End Set
End Property
|
|
|
|
|
Hi Guys,
I would like to thank to Pham Minh Tri, for this great work, and all the guys contibuted to fixing some issues. I would like to add a "small" fix to this. The problem is when you change the value its fireing the validators if you are using validators.
So as you can see i have added "IsInternalValueChanging", in your validator function just check this is true if its true, dont validate. Else you will get wrong value in your validator function.
public class DateTimePicker : System.Windows.Forms.DateTimePicker
{
private DateTimePickerFormat oldFormat = DateTimePickerFormat.Long;
private string oldCustomFormat = null;
private bool bIsNull = false;
private bool _valueChanging;
public bool IsInternalValueChanging
{
get { return _valueChanging; }
}
public DateTimePicker()
: base()
{
}
public new DateTime Value
{
get
{
if (bIsNull)
return DateTime.MinValue;
else
return base.Value;
}
set
{
if (value == DateTime.MinValue)
{
if (bIsNull == false)
{
oldFormat = this.Format;
oldCustomFormat = this.CustomFormat;
bIsNull = true;
}
this.Format = DateTimePickerFormat.Custom;
this.CustomFormat = " ";
base.OnValueChanged(new EventArgs());
}
else
{
if (bIsNull)
{
this.Format = oldFormat;
this.CustomFormat = oldCustomFormat;
bIsNull = false;
}
if (value < this.MaxDate && value > this.MinDate)
{ base.Value = value; }
else if (value > this.MaxDate)
{ value = this.MaxDate; }
else if (value < this.MinDate)
{ value = this.MinDate; }
}
}
}
protected override void OnCloseUp(EventArgs eventargs)
{
base.OnCloseUp(eventargs);
if (Control.MouseButtons == MouseButtons.None)
{
if (bIsNull)
{
_valueChanging = true;
this.Format = oldFormat;
this.CustomFormat = oldCustomFormat;
bIsNull = false;
_valueChanging = false;
}
}
}
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if (e.KeyCode == Keys.Delete)
{
this.Value = DateTime.MinValue;
}
else if (this.Value == DateTime.MinValue || this.Value == null)
{
_valueChanging = true;
if (e.KeyCode == Keys.Space || e.KeyCode == Keys.Up || e.KeyCode == Keys.Down || e.KeyCode == Keys.Right || e.KeyCode == Keys.Left)
{
this.Value = DateTime.Today;
}
else if ((Char.IsNumber((char)e.KeyValue) && e.KeyValue != 48)
//<-- "0" correction
|| (e.KeyValue >= 97 && e.KeyValue <= 105)) //<-- NumPad1 - NumPad9
{
int typedDigit = 1;
if (e.KeyValue >= 97 && e.KeyValue <= 105) //<-- NumPad1 - NumPad9 must be calculated to numeric KeyValues
{
typedDigit = int.Parse(((char)(e.KeyValue - 48)).ToString());
}
else //if (Char.IsNumber((char)e.KeyValue))
{
typedDigit = int.Parse(((char)e.KeyValue).ToString());
}
this.Value = new DateTime(DateTime.Today.Year, DateTime.Today.Month, typedDigit); //<-- this allows international format of the datetimepicker
SendKeys.Send(typedDigit.ToString()); //<-- this allows typing two digits at once without typing it again as example "12" or "27"
}
_valueChanging = false;
}
}
}
Regards,
Premson.
|
|
|
|
|
 Hi,
I added a NullableValue property that allows data binding. I also added some code
to show the user when the control has the focus when the date is null (Nothing in
VB) by showing a "|" which looks almost like a cursor. I also improved the behavior
when the user starts typing in the empty field.
public class NullableDateTimePicker : DateTimePicker
{
private DateTimePickerFormat _oldFormat = DateTimePickerFormat.Long;
private string _oldCustomFormat;
private bool _dateIsNull;
private bool _isInternalValueChanging;
public bool IsInternalValueChanging { get { return _isInternalValueChanging; } }
public NullableDateTimePicker()
: base()
{
}
[Bindable(true)]
[Category("Behavior")]
[Description("The current nullable date/time value for this control")]
public DateTime? NullableValue
{
get
{
if (_dateIsNull) {
return null;
}
return base.Value;
}
set
{
if (value.HasValue) {
Value = value.Value;
} else {
Value = DateTime.MinValue;
}
}
}
public new DateTime Value
{
get
{
if (_dateIsNull)
return DateTime.MinValue;
else
return base.Value;
}
set
{
if (value == DateTime.MinValue) {
if (!_dateIsNull) {
_oldFormat = this.Format;
_oldCustomFormat = this.CustomFormat;
_dateIsNull = true;
}
this.Format = DateTimePickerFormat.Custom;
this.CustomFormat = this.Focused ? "|" : " ";
base.OnValueChanged(new EventArgs());
} else {
if (_dateIsNull) {
this.Format = _oldFormat;
this.CustomFormat = _oldCustomFormat;
_dateIsNull = false;
}
if (value < this.MaxDate && value > this.MinDate) {
base.Value = value;
} else if (value > this.MaxDate) {
value = this.MaxDate;
} else if (value < this.MinDate) {
value = this.MinDate;
}
}
}
}
protected override void OnCloseUp(EventArgs eventargs)
{
base.OnCloseUp(eventargs);
if (Control.MouseButtons == MouseButtons.None) {
if (_dateIsNull) {
_isInternalValueChanging = true;
this.Format = _oldFormat;
this.CustomFormat = _oldCustomFormat;
_dateIsNull = false;
_isInternalValueChanging = false;
}
}
}
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if (e.KeyCode == Keys.Delete) {
this.Value = DateTime.MinValue;
} else if (_dateIsNull) {
_isInternalValueChanging = true;
if (e.KeyCode == Keys.Space || e.KeyCode == Keys.Up || e.KeyCode == Keys.Down || e.KeyCode == Keys.Right || e.KeyCode == Keys.Left) {
this.Value = DateTime.Today;
} else if ((Char.IsNumber((char)e.KeyValue) && e.KeyValue != 48) || (e.KeyValue >= 97 && e.KeyValue <= 105)) {
int typedDigit = 1;
if (e.KeyValue >= 97 && e.KeyValue <= 105) {
typedDigit = int.Parse(((char)(e.KeyValue - 48)).ToString());
} else {
typedDigit = int.Parse(((char)e.KeyValue).ToString());
}
this.Value = DateTime.Now;
SendKeys.SendWait("{RIGHT}");
SendKeys.Send(typedDigit.ToString());
}
_isInternalValueChanging = false;
}
}
protected override void OnGotFocus(EventArgs e)
{
base.OnGotFocus(e);
if (_dateIsNull) {
CustomFormat = "|";
}
}
protected override void OnLostFocus(EventArgs e)
{
if (_dateIsNull) {
CustomFormat = " ";
}
}
}
|
|
|
|
|
thanks a lot to the original creator, and you two modifiers. logged in just to say that. This control being bindable is very helpful. note to others, remember to bind your datasource field/column to the "NullableValue" as opposed to the "Value"
[found under Data>(DataBindings) section in the "Properties Pane"]
|
|
|
|
|
|
You can set NullFormat to [00/00/0000]
string _NullFormat = "00/00/0000";<br />
public string NullFormat<br />
{<br />
get { return this._NullFormat; }<br />
set { this._NullFormat = value; }<br />
}<br />
protected override void OnKeyDown(KeyEventArgs e)<br />
{<br />
base.OnKeyDown (e);<br />
<br />
if (e.KeyCode == Keys.Delete)<br />
{<br />
this.Value = DateTime.MinValue;<br />
this.ValueNullable = null;<br />
if (this.CustomFormat != _NullFormat) this._OldCustomFormat = this.CustomFormat;<br />
this.CustomFormat = _NullFormat;<br />
}<br />
else<br />
{<br />
this.CustomFormat = this._OldCustomFormat;
}<br />
}<br />
protected override void OnValueChanged(EventArgs e)<br />
{<br />
base.OnValueChanged(e);<br />
this.ValueNullable = base.Value;<br />
}<br />
http://www.sendspace.com/file/8qtjdj[Download Sample]
tinhleduc@gmail.com
|
|
|
|
|
Hello,
I use your code, because it is elegant, simple and efficient, as Phil Raevsky said.
I have used all remarks from the forum and found some new upgrades.
public class NullableDateTimePicker : System.Windows.Forms.DateTimePicker
{
DateTimePickerFormat _Format;
string _CustomFormat;
private DateTime? _ValueNullable;
public NullableDateTimePicker()
: base()
{
_Format = base.Format;
_CustomFormat = base.CustomFormat;
}
public new DateTimePickerFormat Format
{
get { return base.Format; }
set { this._Format = value; base.Format = value; }
}
public new string CustomFormat
{
get { return base.CustomFormat; }
set { this._CustomFormat = value; base.CustomFormat = value; }
}
public DateTime? ValueNullable
{
get
{
return _ValueNullable;
}
set
{
_ValueNullable = value;
if(!_ValueNullable.HasValue || value <= this.MinDate || value >= this.MaxDate)
{
base.Format = DateTimePickerFormat.Custom;
base.CustomFormat = " ";
base.OnValueChanged(EventArgs.Empty);
}
else
{
base.Format = _Format;
base.CustomFormat = _CustomFormat;
base.Value = _ValueNullable.Value;
}
}
}
public new DateTime Value
{
get
{
if(!_ValueNullable.HasValue)
return this.MinDate;
return ValueNullable.Value;
}
set
{
this.ValueNullable = value;
}
}
protected override void OnKeyDown(KeyEventArgs e)
{
...
}
protected override void OnCloseUp(EventArgs eventargs)
{
...
}
}
Hope that could help.
Romain TAILLANDIER
www.romaintaillandier.blogspot.com
romaintaillandier.free.fr
www.maintag.fr
|
|
|
|
|
Simple, elegant, and almost perfect
|
|
|
|
|
Imports System
Imports System.Windows.Forms
Namespace Controls
Public Class DateTimePicker
Inherits System.Windows.Forms.DateTimePicker
Private bIsNull As Boolean = False
Private mBackColor As Color = SystemColors.Window
Public Sub New()
MyBase.New()
End Sub
Public Shadows Property Value() As DateTime
Get
If bIsNull Then
Return DateTime.MinValue
Else
Return MyBase.Value
End If
End Get
Set(ByVal value As DateTime)
If value = DateTime.MinValue Or value.Date = "01/01/1905" Or value.Date = "01/01/1900" Then
If bIsNull = False Then bIsNull = True
MakePinkFormat()
Else
MakeWhiteFormat()
bIsNull = False
MyBase.Value = value
End If
End Set
End Property
' Protected Overloads Overrides Sub OnCloseUp(ByVal eventargs As EventArgs)
Protected Overrides Sub OnCloseUp(ByVal eventargs As EventArgs)
If Control.MouseButtons = MouseButtons.None Or Control.MouseButtons = Windows.Forms.MouseButtons.Left Then
Me.Value = MyBase.Value
End If
MyBase.OnCloseUp(eventargs)
End Sub
Protected Overloads Overrides Sub OnKeyDown(ByVal e As KeyEventArgs)
MyBase.OnKeyDown(e)
If e.KeyCode = Keys.Delete Then
Me.Value = DateTime.MinValue
MyBase.Value = "01/01/1905"
End If
End Sub
Private Sub MakePinkFormat()
Me.Format = DateTimePickerFormat.[Custom]
Me.BackColor = Color.Pink
Me.CustomFormat = " "
MyBase.Value = "01/01/1905"
End Sub
Private Sub MakeWhiteFormat()
Me.Format = DateTimePickerFormat.Short
Me.BackColor = Color.White
Me.CustomFormat = Nothing
End Sub
'The BackColor property we will be calling
Public Overrides Property BackColor() As Color
Get
Return mBackColor
End Get
Set(ByVal Value As Color)
mBackColor = Value
'After the BackColor has been set, Invalidate the control
'This will force it to be redrawn
'Me.Invalidate()
End Set
End Property
'WndProc fires durring the painting of the control
Protected Overrides Sub WndProc(ByRef m As Message)
'Check to see if message being send is WM_ERASEBKGND.
'The hex value of this message is &H14.
'This message is sent when the background of the
'object needs to be erased. In our case though, instead of
'erasing it, we will paint a rectangle over it
If m.Msg = CInt(&H14) Then ' WM_ERASEBKGND
Dim g As Graphics = Graphics.FromHdc(m.WParam)
g.FillRectangle(New SolidBrush(mBackColor), ClientRectangle)
g.Dispose()
Return
End If
MyBase.WndProc(m)
End Sub
Private Sub DateTimePicker_EnabledChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.EnabledChanged
Me.CalendarForeColor = Color.Black
End Sub
End Class
End Namespace
|
|
|
|
|
This is an edit because I realized, like the previous poster, than you can simply shadow the Value property of the base DateTimePicker to allow Nullable Dates. That means that it works exactly like you would want/expect it to, in databinding situations and everything.
Public Class NullableDateTimeControl
Inherits System.Windows.Forms.DateTimePicker
Private oldFormat As DateTimePickerFormat = DateTimePickerFormat.Short
Private oldCustomFormat As String = Nothing
Private _IsNull As Boolean = False
Public Sub New()
MyBase.New()
End Sub
''' <summary>
''' The Date Value of the control (is Nullable, can be set to Nothing).
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Shadows Property Value() As Date?
Get
If Me._IsNull Then
Return Nothing
Else
Return MyBase.Value
End If
End Get
Set(ByVal newValue As Date?)
If Not newValue.HasValue Then
If Not Me._IsNull Then
Me.oldFormat = Me.Format
Me.oldCustomFormat = Me.CustomFormat
Me._IsNull = True
End If
Me.Format = DateTimePickerFormat.Custom
Me.CustomFormat = " "
Else
If Me._IsNull Then
Me.Format = Me.oldFormat
Me.CustomFormat = Me.oldCustomFormat
Me._IsNull = False
End If
MyBase.Value = newValue.Value
End If
End Set
End Property
''' <summary>
''' Allows the user to select a new date if the control is already null.
''' </summary>
''' <param name="eventargs"></param>
''' <remarks></remarks>
Protected Overrides Sub OnCloseUp(ByVal eventargs As System.EventArgs)
If Control.MouseButtons = Windows.Forms.MouseButtons.None Then
If Me._IsNull Then
Me.Format = Me.oldFormat
Me.CustomFormat = Me.oldCustomFormat
Me._IsNull = False
End If
End If
MyBase.OnCloseUp(eventargs)
End Sub
''' <summary>
''' Overrides the base class implementation to allow the user to create a Null value by pressing the Delete key.
''' </summary>
''' <param name="e"></param>
''' <remarks></remarks>
Protected Overrides Sub OnKeyUp(ByVal e As System.Windows.Forms.KeyEventArgs)
MyBase.OnKeyUp(e)
If e.KeyCode = Keys.Delete Then
Me.Value = DateTime.MinValue
End If
End Sub
End Class
modified on Wednesday, February 11, 2009 10:51 AM
|
|
|
|
|
Hi, i wanna know if this code can be used in visual studio 2008 (visual basic) or i need to make some changes to use them.
|
|
|
|
|
Thanks for this fine code Jeromeyers. I had to make a small modification to make the NullablePicker work. I changed OnKeyUp to set the _IsNull flag to True. (I also made the code responsive to the backspace key.)
Protected Overrides Sub OnKeyUp(ByVal e As System.Windows.Forms.KeyEventArgs)
MyBase.OnKeyUp(e)
If e.KeyCode = Keys.Delete OrElse e.KeyCode = Keys.Back Then
Me._IsNull = True
Me.Value = Nothing
End If
End Sub
|
|
|
|
|
This way you can actually have a null value for the control.
public new DateTime ? Value
{
get
{
if (bIsNull)
return null;
else
return base.Value;
}
set
{
if (value == null)
{
if (bIsNull == false)
{
oldFormat = this.Format;
oldCustomFormat = this.CustomFormat;
bIsNull = true;
}
this.Format = DateTimePickerFormat.Custom;
this.CustomFormat = " ";
}
else
{
if (bIsNull)
{
this.Format = oldFormat;
this.CustomFormat = oldCustomFormat;
bIsNull = false;
}
base.Value = value.Value;
}
}
}
protected override void OnCloseUp(EventArgs eventargs)
{
if (Control.MouseButtons == MouseButtons.None)
{
if (bIsNull)
{
this.Format = oldFormat;
this.CustomFormat = oldCustomFormat;
bIsNull = false;
}
}
base.OnCloseUp (eventargs);
}
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown (e);
if (e.KeyCode == Keys.Delete)
this.Value = null;
}
|
|
|
|
|
|
When used out-of-the-box, the user must use the mouse to enter a date once the value has been set to DateTime.MinValue.
Change the KeyUp override as follows:
protected override void OnKeyUp(KeyEventArgs e)
{
base.OnKeyUp(e);
if (e.KeyCode == Keys.Delete)
this.Value = DateTime.MinValue;
else if (this.Value == DateTime.MinValue
&& (e.KeyCode == Keys.Space || Char.IsNumber((char)e.KeyValue)
|| e.KeyCode == Keys.Up || e.KeyCode == Keys.Down
|| e.KeyCode == Keys.Right || e.KeyCode == Keys.Left))
this.Value = DateTime.Today;
}
This allows the user to get the "normal" date in the box after pressing a space, any arrow key, or any number.
Comments?
|
|
|
|