Last active
August 26, 2022 00:05
-
-
Save matthewrdev/3fb0b4645b3c14fd7f8a56326d821519 to your computer and use it in GitHub Desktop.
A Xamarin.Forms time picker implementation that allows for a nullable TimeSpan values.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Windows.Input; | |
using Xamarin.Forms; | |
namespace MyApp.Controls | |
{ | |
public class NullableTimeChangedEventArgs : EventArgs | |
{ | |
public NullableTimeChangedEventArgs(TimeSpan? newValue, TimeSpan? oldValue) | |
{ | |
NewValue = newValue; | |
OldValue = oldValue; | |
} | |
public TimeSpan? NewValue { get; } | |
public TimeSpan? OldValue { get; } | |
} | |
public class NullableTimePicker : TimePicker | |
{ | |
const string defaultTimeFormat = "hh:mm tt"; | |
const string defaultPlaceholderLabel = "'Select Time'"; | |
public static readonly BindableProperty PlaceholderProperty = BindableProperty.Create(nameof(Placeholder), typeof(string), typeof(NullableTimePicker), defaultPlaceholderLabel, propertyChanged: OnPlaceholderChanged); | |
private static void OnPlaceholderChanged(BindableObject bindable, object oldValue, object newValue) | |
{ | |
var control = bindable as NullableTimePicker; | |
if (control is null) | |
{ | |
return; | |
} | |
control.Apply(control.TimeValue, control.TimeFormat, newValue as string); | |
} | |
public string Placeholder | |
{ | |
get => (string)GetValue(PlaceholderProperty); | |
set => SetValue(PlaceholderProperty, value); | |
} | |
public static readonly BindableProperty TimeFormatProperty = BindableProperty.Create(nameof(TimeFormat), typeof(string), typeof(NullableTimePicker), defaultTimeFormat, propertyChanged: OnTimeFormatChanged); | |
private static void OnTimeFormatChanged(BindableObject bindable, object oldValue, object newValue) | |
{ | |
var control = bindable as NullableTimePicker; | |
if (control is null) | |
{ | |
return; | |
} | |
control.Apply(control.TimeValue, newValue as string, control.Placeholder); | |
} | |
public string TimeFormat | |
{ | |
get => (string)GetValue(TimeFormatProperty); | |
set => SetValue(TimeFormatProperty, value); | |
} | |
public static readonly BindableProperty TimeValueProperty = BindableProperty.Create(nameof(TimeValue), typeof(TimeSpan?), typeof(NullableTimePicker), default(TimeSpan?), BindingMode.TwoWay, propertyChanged: OnTimeValueChanged); | |
private static void OnTimeValueChanged(BindableObject bindable, object oldValue, object newValue) | |
{ | |
var control = bindable as NullableTimePicker; | |
if (control is null) | |
{ | |
return; | |
} | |
control.Apply(newValue as TimeSpan?, control.TimeFormat, control.Placeholder); | |
} | |
public TimeSpan? TimeValue | |
{ | |
get => (TimeSpan?)GetValue(TimeValueProperty); | |
set => SetValue(TimeValueProperty, value); | |
} | |
public event EventHandler<NullableTimeChangedEventArgs> OnNullableTimeChanged; | |
public NullableTimePicker() | |
{ | |
BindEvents(); | |
Apply(TimeValue, TimeFormat, Placeholder); | |
} | |
~NullableTimePicker() | |
{ | |
UnbindEvents(); | |
} | |
private void BindEvents() | |
{ | |
UnbindEvents(); | |
this.PropertyChanged += NullableTimePicker_PropertyChanged; | |
this.Unfocused += NullableTimePicker_Unfocused; | |
} | |
private void UnbindEvents() | |
{ | |
this.PropertyChanged -= NullableTimePicker_PropertyChanged; | |
this.Unfocused -= NullableTimePicker_Unfocused; | |
} | |
private void NullableTimePicker_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) | |
{ | |
if (e.PropertyName != TimeProperty.PropertyName) | |
{ | |
return; | |
} | |
var timePicker = sender as TimePicker; | |
if (timePicker is null) | |
{ | |
return; | |
} | |
NotifyTimeValueChanged(TimeValue, timePicker.Time); | |
} | |
private void Apply(TimeSpan? timeValue, string dateTimeFormat, string placeholder) | |
{ | |
try | |
{ | |
UnbindEvents(); | |
if (timeValue.HasValue) | |
{ | |
this.Time = timeValue.Value; | |
Format = dateTimeFormat; | |
} | |
else | |
{ | |
this.Time = TimeSpan.Zero; | |
Format = string.IsNullOrEmpty(placeholder) ? defaultPlaceholderLabel : placeholder; | |
} | |
} | |
finally | |
{ | |
BindEvents(); | |
} | |
} | |
private void NullableTimePicker_Unfocused(object sender, FocusEventArgs e) | |
{ | |
if (!this.TimeValue.HasValue) | |
{ | |
TimeValue = this.Time; | |
NotifyTimeValueChanged(null, TimeValue); | |
} | |
} | |
private void NotifyTimeValueChanged(TimeSpan? oldDateValue, TimeSpan? newDateValue) | |
{ | |
OnNullableTimeChanged?.Invoke(this, new NullableTimeChangedEventArgs(newDateValue, oldDateValue)); | |
TimeValue = newDateValue; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment