You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
887 lines
26 KiB
887 lines
26 KiB
/*************************************************************************************
|
|
|
|
Extended WPF Toolkit
|
|
|
|
Copyright (C) 2007-2013 Xceed Software Inc.
|
|
|
|
This program is provided to you under the terms of the Microsoft Public
|
|
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|
|
|
For more features, controls, and fast professional support,
|
|
pick up the Plus Edition at http://xceed.com/wpf_toolkit
|
|
|
|
Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids
|
|
|
|
***********************************************************************************/
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Windows;
|
|
using System.Windows.Data;
|
|
using System.Windows.Input;
|
|
using Xceed.Wpf.Toolkit.Primitives;
|
|
using System.Windows.Controls;
|
|
using System.Linq;
|
|
using Xceed.Wpf.Toolkit.Core.Utilities;
|
|
|
|
namespace Xceed.Wpf.Toolkit
|
|
{
|
|
public class DateTimeUpDown : DateTimeUpDownBase<DateTime?>
|
|
{
|
|
#region Members
|
|
|
|
private DateTime? _lastValidDate; //null
|
|
private bool _setKindInternal = false;
|
|
|
|
#endregion
|
|
|
|
#region Properties
|
|
|
|
#region Format
|
|
|
|
public static readonly DependencyProperty FormatProperty = DependencyProperty.Register( "Format", typeof( DateTimeFormat ), typeof( DateTimeUpDown ), new UIPropertyMetadata( DateTimeFormat.FullDateTime, OnFormatChanged ) );
|
|
public DateTimeFormat Format
|
|
{
|
|
get
|
|
{
|
|
return ( DateTimeFormat )GetValue( FormatProperty );
|
|
}
|
|
set
|
|
{
|
|
SetValue( FormatProperty, value );
|
|
}
|
|
}
|
|
|
|
private static void OnFormatChanged( DependencyObject o, DependencyPropertyChangedEventArgs e )
|
|
{
|
|
DateTimeUpDown dateTimeUpDown = o as DateTimeUpDown;
|
|
if( dateTimeUpDown != null )
|
|
dateTimeUpDown.OnFormatChanged( ( DateTimeFormat )e.OldValue, ( DateTimeFormat )e.NewValue );
|
|
}
|
|
|
|
protected virtual void OnFormatChanged( DateTimeFormat oldValue, DateTimeFormat newValue )
|
|
{
|
|
FormatUpdated();
|
|
}
|
|
|
|
#endregion //Format
|
|
|
|
#region FormatString
|
|
|
|
public static readonly DependencyProperty FormatStringProperty = DependencyProperty.Register( "FormatString", typeof( string ), typeof( DateTimeUpDown ), new UIPropertyMetadata( default( String ), OnFormatStringChanged ), IsFormatStringValid );
|
|
public string FormatString
|
|
{
|
|
get
|
|
{
|
|
return ( string )GetValue( FormatStringProperty );
|
|
}
|
|
set
|
|
{
|
|
SetValue( FormatStringProperty, value );
|
|
}
|
|
}
|
|
|
|
internal static bool IsFormatStringValid( object value )
|
|
{
|
|
try
|
|
{
|
|
// Test the format string if it is used.
|
|
DateTime.MinValue.ToString( ( string )value, CultureInfo.CurrentCulture );
|
|
}
|
|
catch
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private static void OnFormatStringChanged( DependencyObject o, DependencyPropertyChangedEventArgs e )
|
|
{
|
|
DateTimeUpDown dateTimeUpDown = o as DateTimeUpDown;
|
|
if( dateTimeUpDown != null )
|
|
dateTimeUpDown.OnFormatStringChanged( ( string )e.OldValue, ( string )e.NewValue );
|
|
}
|
|
|
|
protected virtual void OnFormatStringChanged( string oldValue, string newValue )
|
|
{
|
|
FormatUpdated();
|
|
}
|
|
|
|
#endregion //FormatString
|
|
|
|
#region Kind
|
|
|
|
public static readonly DependencyProperty KindProperty = DependencyProperty.Register( "Kind", typeof( DateTimeKind ), typeof( DateTimeUpDown ),
|
|
new FrameworkPropertyMetadata( DateTimeKind.Unspecified, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnKindChanged ) );
|
|
public DateTimeKind Kind
|
|
{
|
|
get
|
|
{
|
|
return ( DateTimeKind )GetValue( KindProperty );
|
|
}
|
|
set
|
|
{
|
|
SetValue( KindProperty, value );
|
|
}
|
|
}
|
|
|
|
private static void OnKindChanged( DependencyObject o, DependencyPropertyChangedEventArgs e )
|
|
{
|
|
DateTimeUpDown dateTimeUpDown = o as DateTimeUpDown;
|
|
if( dateTimeUpDown != null )
|
|
dateTimeUpDown.OnKindChanged( ( DateTimeKind )e.OldValue, ( DateTimeKind )e.NewValue );
|
|
}
|
|
|
|
protected virtual void OnKindChanged( DateTimeKind oldValue, DateTimeKind newValue )
|
|
{
|
|
//Upate the value based on kind. (Postpone to EndInit if not yet initialized)
|
|
if( !_setKindInternal
|
|
&& this.Value != null
|
|
&& this.IsInitialized )
|
|
{
|
|
this.Value = this.ConvertToKind( this.Value.Value, newValue );
|
|
}
|
|
}
|
|
|
|
private void SetKindInternal( DateTimeKind kind )
|
|
{
|
|
_setKindInternal = true;
|
|
try
|
|
{
|
|
#if VS2008
|
|
// Warning : Binding could be lost
|
|
this.Kind = kind;
|
|
#else
|
|
//We use SetCurrentValue to not erase the possible underlying
|
|
//OneWay Binding. (This will also update correctly any
|
|
//possible TwoWay bindings).
|
|
this.SetCurrentValue( DateTimeUpDown.KindProperty, kind );
|
|
#endif
|
|
}
|
|
finally
|
|
{
|
|
_setKindInternal = false;
|
|
}
|
|
}
|
|
|
|
#endregion //Kind
|
|
|
|
#region ContextNow (Private)
|
|
|
|
internal DateTime ContextNow
|
|
{
|
|
get
|
|
{
|
|
return DateTimeUtilities.GetContextNow( this.Kind );
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion //Properties
|
|
|
|
#region Constructors
|
|
|
|
static DateTimeUpDown()
|
|
{
|
|
DefaultStyleKeyProperty.OverrideMetadata( typeof( DateTimeUpDown ), new FrameworkPropertyMetadata( typeof( DateTimeUpDown ) ) );
|
|
MaximumProperty.OverrideMetadata( typeof( DateTimeUpDown ), new FrameworkPropertyMetadata( DateTime.MaxValue ) );
|
|
MinimumProperty.OverrideMetadata( typeof( DateTimeUpDown ), new FrameworkPropertyMetadata( DateTime.MinValue ) );
|
|
}
|
|
|
|
public DateTimeUpDown()
|
|
{
|
|
}
|
|
|
|
#endregion //Constructors
|
|
|
|
#region Base Class Overrides
|
|
|
|
public override bool CommitInput()
|
|
{
|
|
bool isSyncValid = this.SyncTextAndValueProperties( true, Text );
|
|
_lastValidDate = this.Value;
|
|
return isSyncValid;
|
|
}
|
|
|
|
protected override void OnCultureInfoChanged( CultureInfo oldValue, CultureInfo newValue )
|
|
{
|
|
FormatUpdated();
|
|
}
|
|
|
|
protected override void OnIncrement()
|
|
{
|
|
if( this.IsCurrentValueValid() )
|
|
{
|
|
if( Value.HasValue )
|
|
UpdateDateTime( 1 );
|
|
else
|
|
Value = DefaultValue ?? this.ContextNow;
|
|
}
|
|
}
|
|
|
|
protected override void OnDecrement()
|
|
{
|
|
if( this.IsCurrentValueValid() )
|
|
{
|
|
if( Value.HasValue )
|
|
UpdateDateTime( -1 );
|
|
else
|
|
Value = DefaultValue ?? this.ContextNow;
|
|
}
|
|
}
|
|
|
|
protected override void OnTextChanged( string previousValue, string currentValue )
|
|
{
|
|
if( !_processTextChanged )
|
|
return;
|
|
|
|
base.OnTextChanged( previousValue, currentValue );
|
|
}
|
|
|
|
protected override DateTime? ConvertTextToValue( string text )
|
|
{
|
|
if( string.IsNullOrEmpty( text ) )
|
|
return null;
|
|
|
|
DateTime result;
|
|
this.TryParseDateTime( text, out result );
|
|
|
|
//Do not force "unspecified" to a time-zone specific
|
|
//parsed text value. This would result in a lost of precision and
|
|
//corrupt data. Let the value impose the Kind to the
|
|
//DateTimePicker.
|
|
if( this.Kind != DateTimeKind.Unspecified )
|
|
{
|
|
|
|
//Keep the current kind (Local or Utc)
|
|
//by imposing it to the parsed text value.
|
|
//
|
|
//Note: A parsed UTC text value may be
|
|
// adjusted with a Local kind and time.
|
|
result = this.ConvertToKind( result, this.Kind );
|
|
}
|
|
|
|
if( this.ClipValueToMinMax )
|
|
{
|
|
return this.GetClippedMinMaxValue( result );
|
|
}
|
|
|
|
this.ValidateDefaultMinMax( result );
|
|
|
|
return result;
|
|
}
|
|
|
|
protected override string ConvertValueToText()
|
|
{
|
|
if( Value == null )
|
|
return string.Empty;
|
|
|
|
return Value.Value.ToString( GetFormatString( Format ), CultureInfo );
|
|
}
|
|
|
|
protected override void SetValidSpinDirection()
|
|
{
|
|
ValidSpinDirections validDirections = ValidSpinDirections.None;
|
|
|
|
if( !IsReadOnly )
|
|
{
|
|
if( this.IsLowerThan( this.Value, this.Maximum ) || !this.Value.HasValue || !this.Maximum.HasValue )
|
|
validDirections = validDirections | ValidSpinDirections.Increase;
|
|
|
|
if( this.IsGreaterThan( this.Value, this.Minimum ) || !this.Value.HasValue || !this.Minimum.HasValue )
|
|
validDirections = validDirections | ValidSpinDirections.Decrease;
|
|
}
|
|
|
|
if( this.Spinner != null )
|
|
this.Spinner.ValidSpinDirection = validDirections;
|
|
}
|
|
|
|
protected override object OnCoerceValue( object newValue )
|
|
{
|
|
//Since only changing the "kind" of a date
|
|
//Ex. "2001-01-01 12:00 AM, Kind=Utc" to "2001-01-01 12:00 AM Kind=Local"
|
|
//by setting the "Value" property won't trigger a property changed,
|
|
//but will call this callback (coerce), we update the Kind here.
|
|
DateTime? value = ( DateTime? )base.OnCoerceValue( newValue );
|
|
|
|
//Let the initialized determine the final "kind" value.
|
|
if(value != null && this.IsInitialized)
|
|
{
|
|
//Update kind based on value kind
|
|
this.SetKindInternal( value.Value.Kind );
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
protected override void OnValueChanged( DateTime? oldValue, DateTime? newValue )
|
|
{
|
|
//whenever the value changes we need to parse out the value into out DateTimeInfo segments so we can keep track of the individual pieces
|
|
//but only if it is not null
|
|
if( newValue != null )
|
|
ParseValueIntoDateTimeInfo();
|
|
|
|
base.OnValueChanged( oldValue, newValue );
|
|
|
|
if( !_isTextChangedFromUI )
|
|
{
|
|
_lastValidDate = newValue;
|
|
}
|
|
}
|
|
|
|
protected override void RaiseValueChangedEvent( DateTime? oldValue, DateTime? newValue )
|
|
{
|
|
if( ( this.TemplatedParent is TimePicker )
|
|
&& ( ( TimePicker )this.TemplatedParent ).TemplatedParent is DateTimePicker )
|
|
return;
|
|
|
|
base.RaiseValueChangedEvent( oldValue, newValue );
|
|
}
|
|
|
|
protected override bool IsCurrentValueValid()
|
|
{
|
|
DateTime result;
|
|
|
|
if( string.IsNullOrEmpty( this.TextBox.Text ) )
|
|
return true;
|
|
|
|
return this.TryParseDateTime( this.TextBox.Text, out result );
|
|
}
|
|
|
|
protected override void OnInitialized( EventArgs e )
|
|
{
|
|
base.OnInitialized( e );
|
|
if( this.Value != null )
|
|
{
|
|
DateTimeKind valueKind = this.Value.Value.Kind;
|
|
|
|
if( valueKind != this.Kind )
|
|
{
|
|
//Conflit between "Kind" property and the "Value.Kind" value.
|
|
//Priority to the one that is not "Unspecified".
|
|
if( this.Kind == DateTimeKind.Unspecified )
|
|
{
|
|
this.SetKindInternal( valueKind );
|
|
}
|
|
else
|
|
{
|
|
this.Value = this.ConvertToKind( this.Value.Value, this.Kind );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion //Base Class Overrides
|
|
|
|
#region Methods
|
|
|
|
public void SelectAll()
|
|
{
|
|
_fireSelectionChangedEvent = false;
|
|
TextBox.SelectAll();
|
|
_fireSelectionChangedEvent = true;
|
|
}
|
|
|
|
private void FormatUpdated()
|
|
{
|
|
InitializeDateTimeInfoList();
|
|
if( Value != null )
|
|
ParseValueIntoDateTimeInfo();
|
|
|
|
// Update the Text representation of the value.
|
|
_processTextChanged = false;
|
|
|
|
this.SyncTextAndValueProperties( false, null );
|
|
|
|
_processTextChanged = true;
|
|
|
|
}
|
|
|
|
protected override void InitializeDateTimeInfoList()
|
|
{
|
|
_dateTimeInfoList.Clear();
|
|
_selectedDateTimeInfo = null;
|
|
|
|
string format = GetFormatString( Format );
|
|
|
|
if( string.IsNullOrEmpty( format ) )
|
|
return;
|
|
|
|
while( format.Length > 0 )
|
|
{
|
|
int elementLength = GetElementLengthByFormat( format );
|
|
DateTimeInfo info = null;
|
|
|
|
switch( format[ 0 ] )
|
|
{
|
|
case '"':
|
|
case '\'':
|
|
{
|
|
int closingQuotePosition = format.IndexOf( format[ 0 ], 1 );
|
|
info = new DateTimeInfo
|
|
{
|
|
IsReadOnly = true,
|
|
Type = DateTimePart.Other,
|
|
Length = 1,
|
|
Content = format.Substring( 1, Math.Max( 1, closingQuotePosition - 1 ) )
|
|
};
|
|
elementLength = Math.Max( 1, closingQuotePosition + 1 );
|
|
break;
|
|
}
|
|
case 'D':
|
|
case 'd':
|
|
{
|
|
string d = format.Substring( 0, elementLength );
|
|
if( elementLength == 1 )
|
|
d = "%" + d;
|
|
|
|
if( elementLength > 2 )
|
|
info = new DateTimeInfo
|
|
{
|
|
IsReadOnly = true,
|
|
Type = DateTimePart.DayName,
|
|
Format = d
|
|
};
|
|
else
|
|
info = new DateTimeInfo
|
|
{
|
|
IsReadOnly = false,
|
|
Type = DateTimePart.Day,
|
|
Format = d
|
|
};
|
|
break;
|
|
}
|
|
case 'F':
|
|
case 'f':
|
|
{
|
|
string f = format.Substring( 0, elementLength );
|
|
if( elementLength == 1 )
|
|
f = "%" + f;
|
|
|
|
info = new DateTimeInfo
|
|
{
|
|
IsReadOnly = false,
|
|
Type = DateTimePart.Millisecond,
|
|
Format = f
|
|
};
|
|
break;
|
|
}
|
|
case 'h':
|
|
{
|
|
string h = format.Substring( 0, elementLength );
|
|
if( elementLength == 1 )
|
|
h = "%" + h;
|
|
|
|
info = new DateTimeInfo
|
|
{
|
|
IsReadOnly = false,
|
|
Type = DateTimePart.Hour12,
|
|
Format = h
|
|
};
|
|
break;
|
|
}
|
|
case 'H':
|
|
{
|
|
string H = format.Substring( 0, elementLength );
|
|
if( elementLength == 1 )
|
|
H = "%" + H;
|
|
|
|
info = new DateTimeInfo
|
|
{
|
|
IsReadOnly = false,
|
|
Type = DateTimePart.Hour24,
|
|
Format = H
|
|
};
|
|
break;
|
|
}
|
|
case 'M':
|
|
{
|
|
string M = format.Substring( 0, elementLength );
|
|
if( elementLength == 1 )
|
|
M = "%" + M;
|
|
|
|
if( elementLength >= 3 )
|
|
info = new DateTimeInfo
|
|
{
|
|
IsReadOnly = false,
|
|
Type = DateTimePart.MonthName,
|
|
Format = M
|
|
};
|
|
else
|
|
info = new DateTimeInfo
|
|
{
|
|
IsReadOnly = false,
|
|
Type = DateTimePart.Month,
|
|
Format = M
|
|
};
|
|
break;
|
|
}
|
|
case 'S':
|
|
case 's':
|
|
{
|
|
string s = format.Substring( 0, elementLength );
|
|
if( elementLength == 1 )
|
|
s = "%" + s;
|
|
|
|
info = new DateTimeInfo
|
|
{
|
|
IsReadOnly = false,
|
|
Type = DateTimePart.Second,
|
|
Format = s
|
|
};
|
|
break;
|
|
}
|
|
case 'T':
|
|
case 't':
|
|
{
|
|
string t = format.Substring( 0, elementLength );
|
|
if( elementLength == 1 )
|
|
t = "%" + t;
|
|
|
|
info = new DateTimeInfo
|
|
{
|
|
IsReadOnly = false,
|
|
Type = DateTimePart.AmPmDesignator,
|
|
Format = t
|
|
};
|
|
break;
|
|
}
|
|
case 'Y':
|
|
case 'y':
|
|
{
|
|
string y = format.Substring( 0, elementLength );
|
|
if( elementLength == 1 )
|
|
y = "%" + y;
|
|
|
|
info = new DateTimeInfo
|
|
{
|
|
IsReadOnly = false,
|
|
Type = DateTimePart.Year,
|
|
Format = y
|
|
};
|
|
break;
|
|
}
|
|
case '\\':
|
|
{
|
|
if( format.Length >= 2 )
|
|
{
|
|
info = new DateTimeInfo
|
|
{
|
|
IsReadOnly = true,
|
|
Content = format.Substring( 1, 1 ),
|
|
Length = 1,
|
|
Type = DateTimePart.Other
|
|
};
|
|
elementLength = 2;
|
|
}
|
|
break;
|
|
}
|
|
case 'g':
|
|
{
|
|
string g = format.Substring( 0, elementLength );
|
|
if( elementLength == 1 )
|
|
g = "%" + g;
|
|
|
|
info = new DateTimeInfo
|
|
{
|
|
IsReadOnly = true,
|
|
Type = DateTimePart.Period,
|
|
Format = format.Substring( 0, elementLength )
|
|
};
|
|
break;
|
|
}
|
|
case 'm':
|
|
{
|
|
string m = format.Substring( 0, elementLength );
|
|
if( elementLength == 1 )
|
|
m = "%" + m;
|
|
|
|
info = new DateTimeInfo
|
|
{
|
|
IsReadOnly = false,
|
|
Type = DateTimePart.Minute,
|
|
Format = m
|
|
};
|
|
break;
|
|
}
|
|
case 'z':
|
|
{
|
|
string z = format.Substring( 0, elementLength );
|
|
if( elementLength == 1 )
|
|
z = "%" + z;
|
|
|
|
info = new DateTimeInfo
|
|
{
|
|
IsReadOnly = true,
|
|
Type = DateTimePart.TimeZone,
|
|
Format = z
|
|
};
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
elementLength = 1;
|
|
info = new DateTimeInfo
|
|
{
|
|
IsReadOnly = true,
|
|
Length = 1,
|
|
Content = format[ 0 ].ToString(),
|
|
Type = DateTimePart.Other
|
|
};
|
|
break;
|
|
}
|
|
}
|
|
|
|
_dateTimeInfoList.Add( info );
|
|
format = format.Substring( elementLength );
|
|
}
|
|
}
|
|
|
|
protected override bool IsLowerThan( DateTime? value1, DateTime? value2 )
|
|
{
|
|
if( value1 == null || value2 == null )
|
|
return false;
|
|
|
|
return ( value1.Value < value2.Value );
|
|
}
|
|
|
|
protected override bool IsGreaterThan( DateTime? value1, DateTime? value2 )
|
|
{
|
|
if( value1 == null || value2 == null )
|
|
return false;
|
|
|
|
return ( value1.Value > value2.Value );
|
|
}
|
|
|
|
private static int GetElementLengthByFormat( string format )
|
|
{
|
|
for( int i = 1; i < format.Length; i++ )
|
|
{
|
|
if( String.Compare( format[ i ].ToString(), format[ 0 ].ToString(), false ) != 0 )
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
return format.Length;
|
|
}
|
|
|
|
private void ParseValueIntoDateTimeInfo()
|
|
{
|
|
string text = string.Empty;
|
|
|
|
_dateTimeInfoList.ForEach( info =>
|
|
{
|
|
if( info.Format == null )
|
|
{
|
|
info.StartPosition = text.Length;
|
|
info.Length = info.Content.Length;
|
|
text += info.Content;
|
|
}
|
|
else
|
|
{
|
|
DateTime date = Value.Value;
|
|
info.StartPosition = text.Length;
|
|
info.Content = date.ToString( info.Format, CultureInfo.DateTimeFormat );
|
|
info.Length = info.Content.Length;
|
|
text += info.Content;
|
|
}
|
|
} );
|
|
}
|
|
|
|
internal string GetFormatString( DateTimeFormat dateTimeFormat )
|
|
{
|
|
switch( dateTimeFormat )
|
|
{
|
|
case DateTimeFormat.ShortDate:
|
|
return CultureInfo.DateTimeFormat.ShortDatePattern;
|
|
case DateTimeFormat.LongDate:
|
|
return CultureInfo.DateTimeFormat.LongDatePattern;
|
|
case DateTimeFormat.ShortTime:
|
|
return CultureInfo.DateTimeFormat.ShortTimePattern;
|
|
case DateTimeFormat.LongTime:
|
|
return CultureInfo.DateTimeFormat.LongTimePattern;
|
|
case DateTimeFormat.FullDateTime:
|
|
return CultureInfo.DateTimeFormat.FullDateTimePattern;
|
|
case DateTimeFormat.MonthDay:
|
|
return CultureInfo.DateTimeFormat.MonthDayPattern;
|
|
case DateTimeFormat.RFC1123:
|
|
return CultureInfo.DateTimeFormat.RFC1123Pattern;
|
|
case DateTimeFormat.SortableDateTime:
|
|
return CultureInfo.DateTimeFormat.SortableDateTimePattern;
|
|
case DateTimeFormat.UniversalSortableDateTime:
|
|
return CultureInfo.DateTimeFormat.UniversalSortableDateTimePattern;
|
|
case DateTimeFormat.YearMonth:
|
|
return CultureInfo.DateTimeFormat.YearMonthPattern;
|
|
case DateTimeFormat.Custom:
|
|
{
|
|
switch( this.FormatString )
|
|
{
|
|
case "d":
|
|
return CultureInfo.DateTimeFormat.ShortDatePattern;
|
|
case "t":
|
|
return CultureInfo.DateTimeFormat.ShortTimePattern;
|
|
case "T":
|
|
return CultureInfo.DateTimeFormat.LongTimePattern;
|
|
case "D":
|
|
return CultureInfo.DateTimeFormat.LongDatePattern;
|
|
case "f":
|
|
return CultureInfo.DateTimeFormat.LongDatePattern + " " + CultureInfo.DateTimeFormat.ShortTimePattern;
|
|
case "F":
|
|
return CultureInfo.DateTimeFormat.FullDateTimePattern;
|
|
case "g":
|
|
return CultureInfo.DateTimeFormat.ShortDatePattern + " " + CultureInfo.DateTimeFormat.ShortTimePattern;
|
|
case "G":
|
|
return CultureInfo.DateTimeFormat.ShortDatePattern + " " + CultureInfo.DateTimeFormat.LongTimePattern;
|
|
case "m":
|
|
return CultureInfo.DateTimeFormat.MonthDayPattern;
|
|
case "y":
|
|
return CultureInfo.DateTimeFormat.YearMonthPattern;
|
|
case "r":
|
|
return CultureInfo.DateTimeFormat.RFC1123Pattern;
|
|
case "s":
|
|
return CultureInfo.DateTimeFormat.SortableDateTimePattern;
|
|
case "u":
|
|
return CultureInfo.DateTimeFormat.UniversalSortableDateTimePattern;
|
|
default:
|
|
return FormatString;
|
|
}
|
|
}
|
|
default:
|
|
throw new ArgumentException( "Not a supported format" );
|
|
}
|
|
}
|
|
|
|
private void UpdateDateTime( int value )
|
|
{
|
|
_fireSelectionChangedEvent = false;
|
|
DateTimeInfo info = _selectedDateTimeInfo;
|
|
|
|
//this only occurs when the user manually type in a value for the Value Property
|
|
if( info == null )
|
|
info = _dateTimeInfoList[ 0 ];
|
|
|
|
DateTime? result = null;
|
|
|
|
try
|
|
{
|
|
switch( info.Type )
|
|
{
|
|
case DateTimePart.Year:
|
|
{
|
|
result = ( ( DateTime )Value ).AddYears( value );
|
|
break;
|
|
}
|
|
case DateTimePart.Month:
|
|
case DateTimePart.MonthName:
|
|
{
|
|
result = ( ( DateTime )Value ).AddMonths( value );
|
|
break;
|
|
}
|
|
case DateTimePart.Day:
|
|
case DateTimePart.DayName:
|
|
{
|
|
result = ( ( DateTime )Value ).AddDays( value );
|
|
break;
|
|
}
|
|
case DateTimePart.Hour12:
|
|
case DateTimePart.Hour24:
|
|
{
|
|
result = ( ( DateTime )Value ).AddHours( value );
|
|
break;
|
|
}
|
|
case DateTimePart.Minute:
|
|
{
|
|
result = ( ( DateTime )Value ).AddMinutes( value );
|
|
break;
|
|
}
|
|
case DateTimePart.Second:
|
|
{
|
|
result = ( ( DateTime )Value ).AddSeconds( value );
|
|
break;
|
|
}
|
|
case DateTimePart.Millisecond:
|
|
{
|
|
result = ( ( DateTime )Value ).AddMilliseconds( value );
|
|
break;
|
|
}
|
|
case DateTimePart.AmPmDesignator:
|
|
{
|
|
result = ( ( DateTime )Value ).AddHours( value * 12 );
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
//this can occur if the date/time = 1/1/0001 12:00:00 AM which is the smallest date allowed.
|
|
//I could write code that would validate the date each and everytime but I think that it would be more
|
|
//efficient if I just handle the edge case and allow an exeption to occur and swallow it instead.
|
|
}
|
|
|
|
this.Value = this.CoerceValueMinMax( result );
|
|
|
|
//we loose our selection when the Value is set so we need to reselect it without firing the selection changed event
|
|
TextBox.Select( info.StartPosition, info.Length );
|
|
_fireSelectionChangedEvent = true;
|
|
}
|
|
|
|
private bool TryParseDateTime( string text, out DateTime result )
|
|
{
|
|
bool isValid = false;
|
|
result = this.ContextNow;
|
|
|
|
DateTime current = this.ContextNow;
|
|
try
|
|
{
|
|
current = (this.Value.HasValue)
|
|
? this.Value.Value
|
|
: DateTime.Parse( this.ContextNow.ToString(), this.CultureInfo.DateTimeFormat );
|
|
|
|
isValid = DateTimeParser.TryParse( text, this.GetFormatString( Format ), current, this.CultureInfo, out result );
|
|
}
|
|
catch( FormatException )
|
|
{
|
|
isValid = false;
|
|
}
|
|
|
|
if( !isValid )
|
|
{
|
|
isValid = DateTime.TryParseExact( text, this.GetFormatString( this.Format ), this.CultureInfo, DateTimeStyles.None, out result );
|
|
}
|
|
|
|
if( !isValid )
|
|
{
|
|
result = ( _lastValidDate != null ) ? _lastValidDate.Value : current;
|
|
}
|
|
|
|
return isValid;
|
|
}
|
|
|
|
private DateTime ConvertToKind( DateTime dateTime, DateTimeKind kind )
|
|
{
|
|
//Same kind, just return same value.
|
|
if( kind == dateTime.Kind )
|
|
return dateTime;
|
|
|
|
//"ToLocalTime()" from an unspecified will assume
|
|
// That the time was originaly Utc and affect the datetime value.
|
|
// Just "Force" the "Kind" instead.
|
|
if( dateTime.Kind == DateTimeKind.Unspecified
|
|
|| kind == DateTimeKind.Unspecified )
|
|
return DateTime.SpecifyKind( dateTime, kind );
|
|
|
|
return ( kind == DateTimeKind.Local )
|
|
? dateTime.ToLocalTime()
|
|
: dateTime.ToUniversalTime();
|
|
}
|
|
|
|
#endregion //Methods
|
|
}
|
|
}
|
|
|