【问题标题】:Nullable TimePicker in Xamarin.FormsXamarin.Forms 中的可为空的 TimePicker
【发布时间】:2015-11-07 08:51:11
【问题描述】:

我正在使用TimePicker 在我的应用中显示时间。当时间已经设置时,它会正确显示,但是当时间没有设置时,它会显示默认的 12 : 00 AM 时间。所以我只想在未设置时间时显示null 值。 是否可以在 Xamarin Forms 中将 nullable 值设置为 TimePicker

【问题讨论】:

    标签: c# xamarin xamarin.forms nullable timepicker


    【解决方案1】:

    您可以使用TimePickerLabel 创建一个自定义View。如果未选择时间,则会出现“hh:mm”,否则时间将出现在标签上。要显示时间选择器对话框,有一个tapGestureRecognizer,它会在点击标签时将焦点设置为时间选择器。

    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;
          }          
    }
    

    【讨论】:

    • 此解决方案存在多个缺陷。首先,它需要对BindableProperty.Create()OnTimeChanged() 进行一些更新。其次,它应该使用Entry 而不是Label。但最大的问题是:如果已经设置了值(设置为null),则无法取消(您需要额外的按钮或类似的东西)。并且您不能在开始时将时间设置为00:00,因为属性没有更改。但不错的尝试。
    【解决方案2】:

    我用这个

    /// <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;
                }
            }
        }
    }
    

    【讨论】:

    • 这段代码中的变量和方法命名良好,但文档标签使其可读性降低。特别是因为它们是德语。
    • @Alessandro 感谢您的回复,但我正在寻找 Nullable 时间选择器,TimePicker 使用 TimeSpan 类作为时间间隔。
    • 你应该提到source。这不是你的代码,它只是复制和粘贴。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-08-07
    • 1970-01-01
    • 1970-01-01
    • 2020-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多