Skip to content

Instantly share code, notes, and snippets.

@matthewrdev
Last active August 26, 2022 00:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save matthewrdev/3fb0b4645b3c14fd7f8a56326d821519 to your computer and use it in GitHub Desktop.
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.
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