@@ -25,8 +25,9 @@ public class TimePicker : Control
2525 private Popup _popup ;
2626 private Button _dropDownButton ;
2727 private bool _disablePopupReopen ;
28+ private DateTime ? _lastValidTime ;
2829
29- static TimePicker ( )
30+ static TimePicker ( )
3031 {
3132 DefaultStyleKeyProperty . OverrideMetadata ( typeof ( TimePicker ) , new FrameworkPropertyMetadata ( typeof ( TimePicker ) ) ) ;
3233 }
@@ -67,10 +68,11 @@ public string Text
6768 private static void SelectedTimePropertyChangedCallback ( DependencyObject dependencyObject , DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs )
6869 {
6970 var timePicker = ( TimePicker ) dependencyObject ;
70- timePicker . SetCurrentValue ( TextProperty , timePicker . DateTimeToString ( timePicker . SelectedTime ) ) ;
71- }
71+ timePicker . SetCurrentValue ( TextProperty , timePicker . DateTimeToString ( timePicker . SelectedTime ) ) ;
72+ timePicker . _lastValidTime = timePicker . SelectedTime ;
73+ }
7274
73- public DateTime ? SelectedTime
75+ public DateTime ? SelectedTime
7476 {
7577 get { return ( DateTime ? ) GetValue ( SelectedTimeProperty ) ; }
7678 set { SetValue ( SelectedTimeProperty , value ) ; }
@@ -212,10 +214,36 @@ public override void OnApplyTemplate()
212214
213215 private void TextBoxOnLostFocus ( object sender , RoutedEventArgs routedEventArgs )
214216 {
215- SetSelectedTime ( ) ;
216- }
217+ if ( _textBox == null ) return ;
218+
219+ if ( ! string . IsNullOrEmpty ( _textBox . Text ) )
220+ {
221+ DateTime time ;
222+ if ( IsTimeValid ( _textBox . Text , out time ) )
223+ SetCurrentValue ( SelectedTimeProperty , time ) ;
224+
225+ else // Invalid time, jump back to previous good time
226+ SetInvalidTime ( ) ;
227+ }
228+ }
229+
230+ private void SetInvalidTime ( )
231+ {
232+ if ( _lastValidTime != null )
233+ {
234+ SetCurrentValue ( SelectedTimeProperty , ( DateTime ) _lastValidTime ) ;
235+ _textBox . Text = SelectedTime . Value . ToString ( SelectedTime . Value . Hour % 12 > 9 ? "hh:mm tt" : "h:mm tt" ) ;
236+ }
237+
238+ else
239+ {
240+ SetCurrentValue ( SelectedTimeProperty , null ) ;
241+ _textBox . Text = "" ;
242+ }
217243
218- private void TextBoxOnKeyDown ( object sender , KeyEventArgs keyEventArgs )
244+ }
245+
246+ private void TextBoxOnKeyDown ( object sender , KeyEventArgs keyEventArgs )
219247 {
220248 keyEventArgs . Handled = ProcessKey ( keyEventArgs ) || keyEventArgs . Handled ;
221249 }
@@ -255,8 +283,9 @@ private bool ProcessKey(KeyEventArgs keyEventArgs)
255283
256284 private void TextBoxOnTextChanged ( object sender , TextChangedEventArgs textChangedEventArgs )
257285 {
258- SetCurrentValue ( TextProperty , _textBox . Text ) ;
259- }
286+ if ( _popup ? . IsOpen == true )
287+ SetCurrentValue ( TextProperty , _textBox . Text ) ;
288+ }
260289
261290 private void SetSelectedTime ( )
262291 {
@@ -268,18 +297,24 @@ private void SetSelectedTime()
268297 }
269298 }
270299
271- private static void ParseTime ( string s , Action < DateTime > successContinuation )
300+ private void ParseTime ( string s , Action < DateTime > successContinuation )
272301 {
273302 var dtfi = CultureInfo . CurrentCulture . GetDateFormat ( ) ;
274303
275304 DateTime time ;
276- if ( DateTime . TryParseExact (
277- s , new [ ] { dtfi . ShortTimePattern , dtfi . LongTimePattern } ,
278- CultureInfo . CurrentCulture , DateTimeStyles . None , out time ) )
305+ if ( IsTimeValid ( s , out time ) )
279306 successContinuation ( time ) ;
280307 }
281308
282- private string DateTimeToString ( DateTime ? d )
309+ private bool IsTimeValid ( string s , out DateTime time )
310+ {
311+ return DateTime . TryParse ( s ,
312+ CultureInfo . CurrentCulture ,
313+ DateTimeStyles . AssumeLocal | DateTimeStyles . AllowWhiteSpaces ,
314+ out time ) ;
315+ }
316+
317+ private string DateTimeToString ( DateTime ? d )
283318 {
284319 return d . HasValue ? DateTimeToString ( d . Value ) : null ;
285320 }
0 commit comments