简体   繁体   中英

Nullable TimePicker in Xamarin.Forms

I'm using TimePicker for displaying time in my app. When time is already set then it displays correctly, but when time is not set, then it display default 12 : 00 AM time. So I just want display null value when time is not set. Is it possible to set nullable value to TimePicker in Xamarin Forms?

You can create one custom View with a TimePicker and Label . If no time is selected then "hh:mm" will appear otherwise the time will appear on the label. To show the timepicker dialog there is a tapGestureRecognizer which will set the focus to timepicker when label is tapped.

public class NullableTimePicker : ContentView
{
    private const string NullTimeLabel = "hh : mm";
    private readonly TimePicker _timePicker;
    private readonly Label _label;                

    public static readonly BindableProperty TimeProperty = BindableProperty.Create<NullableTimePicker, TimeSpan?>(t => t.Time, null, BindingMode.TwoWay, propertyChanged: OnTimeChanged);

    public NullableTimePicker()
    {
         _label = new Label
         {
              Text = NullTimeLabel,
              HorizontalOptions = LayoutOptions.FillAndExpand,
              VerticalOptions = LayoutOptions.Fill,
              HorizontalTextAlignment = TextAlignment.Start,
              VerticalTextAlignment = TextAlignment.Center,
              TextColor = Color.Black,
              FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label))
         };

         _timePicker = new TimePicker
         {
              IsVisible = false,
              HorizontalOptions = LayoutOptions.FillAndExpand,
              VerticalOptions = LayoutOptions.Fill
         };

         Content = new StackLayout
         {
              Children =
              {
                   _label,
                   _timePicker
              },
              Padding = 0,
              Spacing = 0,
              Margin = 0
         };

         Padding = 0;
         Margin = 0;

         var tapGestureRecognizer = new TapGestureRecognizer();
         tapGestureRecognizer.Tapped += TapGestureRecognizer_Tapped;
         GestureRecognizers.Add(tapGestureRecognizer);

         _timePicker.PropertyChanged += timePicker_PropertyChanged;

         PropertyChanged += NullableTimePicker_PropertyChanged;
   }

  private void NullableTimePicker_PropertyChanged(object sender, PropertyChangedEventArgs e)
  {
         if (_label != null && e.PropertyName == IsEnabledProperty.PropertyName)
         {
               _label.TextColor = IsEnabled ? Color.Black : Color.Gray;
         }
  }

  private void timePicker_PropertyChanged(object sender, PropertyChangedEventArgs e)
  {
         if (e.PropertyName == TimePicker.TimeProperty.PropertyName && _timePicker != null)
         {
                    Time = _timePicker.Time;
         }
   }

   private void TapGestureRecognizer_Tapped(object sender, EventArgs e)
   {
          if (IsEnabled == false)
          {
               return;
          }

          if (_timePicker.IsFocused)
          {
              _timePicker.Unfocus();
          }

          _timePicker.Focus();
     }

     private static void OnTimeChanged(BindableObject bindable, TimeSpan? oldvalue, TimeSpan? newvalue)
     {
           var nullableTimePicker = bindable as NullableTimePicker;
           if (nullableTimePicker != null && oldvalue != newvalue)
           {
               nullableTimePicker.Time = newvalue;
           }
     }

     public TimeSpan? Time
     {
          get
          {
               return GetValue(TimeProperty) as TimeSpan?;
          }
          set
          {
               SetValue(TimeProperty, value);

               if (value.HasValue && _timePicker.Time != value)
               {
                   _timePicker.Time = value.Value;
               }
               SetLabelText(value);
           }
      }

      private void SetLabelText(TimeSpan? value)
      {
           _label.Text = value.HasValue ? ConvertTimeSpanToString(value.Value) : NullTimeLabel;
      }          
}

I use this

/// <summary>
/// DatePicker der null Werte erlaubt
/// </summary>
public class CustomDatePicker : DatePicker
{
    /// <summary>
    /// PropertyName für die <c>NullableDate</c> Property
    /// </summary>
    public const string NullableDatePropertyName = "NullableDate";
    /// <summary>
    /// Die BinableProperty
    /// </summary>
    public static readonly BindableProperty NullableDateProperty = BindableProperty.Create<CustomDatePicker, DateTime?>(i => i.NullableDate, null, BindingMode.TwoWay, null, NullableDateChanged);
    /// <summary>
    /// Datumswert welches null Werte akzeptiert
    /// </summary>
    public DateTime? NullableDate
    {
        get
        {
            return (DateTime?)this.GetValue(NullableDateProperty);
        }
        set
        {
            this.SetValue(NullableDateProperty, value);
        }
    }
    /// <summary>
    /// Der Name der <c>NullText</c> Property
    /// </summary>
    public const string NullTextPropertyName = "NullText";
    /// <summary>
    /// Die BindableProperty
    /// </summary>
    public static readonly BindableProperty NullTextProperty = BindableProperty.Create<CustomDatePicker, string>(i => i.NullText, default(string), BindingMode.TwoWay);
    /// <summary>
    /// Der Text der angezeigt wird wenn <c>NullableDate</c> keinen Wert hat
    /// </summary>
    public string NullText
    {
        get
        {
            return (string)this.GetValue(NullTextProperty);
        }
        set
        {
            this.SetValue(NullTextProperty, value);
        }
    }
    /// <summary>
    /// Der Name der <c>DisplayBorder</c> Property
    /// </summary>
    public const string DisplayBorderPropertyName = "DisplayBorder";
    /// <summary>
    /// Die BindableProperty
    /// </summary>
    public static readonly BindableProperty DisplayBorderProperty = BindableProperty.Create<CustomDatePicker, bool>(i => i.DisplayBorder, default(bool), BindingMode.TwoWay);
    /// <summary>
    /// Gibt an ob eine Umrandung angezeigt werden soll oder nicht
    /// </summary>
    public bool DisplayBorder
    {
        get
        {
            return (bool)this.GetValue(DisplayBorderProperty);
        }
        set
        {
            this.SetValue(DisplayBorderProperty, value);
        }
    }

    /// <summary>
    /// Erstellt eine neue Instanz von <c>CustomDatePicker</c>
    /// </summary>
    public CustomDatePicker()
    {
        this.DateSelected += CustomDatePicker_DateSelected;

        this.Format = "dd.MM.yyyy";
    }
    /// <summary>
    /// Wird gefeuert wenn ein neues Datum selektiert wurde
    /// </summary>
    /// <param name="sender">Der Sender</param>
    /// <param name="e">Event Argumente</param>
    void CustomDatePicker_DateSelected(object sender, DateChangedEventArgs e)
    {
        this.NullableDate = new DateTime(
            e.NewDate.Year, 
            e.NewDate.Month, 
            e.NewDate.Day, 
            this.NullableDate.HasValue ? this.NullableDate.Value.Hour : 0,
            this.NullableDate.HasValue ? this.NullableDate.Value.Minute : 0,
            this.NullableDate.HasValue ? this.NullableDate.Value.Second : 0);
    }

    /// <summary>
    /// Gefeuert wenn sich <c>NullableDate</c> ändert
    /// </summary>
    /// <param name="obj">Der Sender</param>
    /// <param name="oldValue">Der alte Wert</param>
    /// <param name="newValue">Der neue Wert</param>
    private static void NullableDateChanged(BindableObject obj, DateTime? oldValue, DateTime? newValue)
    {
        var customDatePicker = obj as CustomDatePicker;

        if (customDatePicker != null)
        {
            if (newValue.HasValue)
            {
                customDatePicker.Date = newValue.Value;
            }
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM