Datepicker: Possible to bind to Nullable date value?

RonaldKasperRonaldKasper ATMember ✭✭

Hi everybody!

I have a nullable date field in my object and I want to bind a date picker to it. When the value is null, I would just want to show no value in the picker. Is this possible?

I tried

datepicker.SetBinding (DatePicker.DateProperty, vm => vm.DueDate, BindingMode.TwoWay);

but this results in a NullValueException when the view is shown.

Any ideas?

Best Answers

Answers

  • ChWoChWo DEMember

    Same problem here.
    I tried to pass DateTime.MinValue instead of null. But I don't know how to set the displayed text in the Entry component to an empty string.

  • MiniyahilArekewMiniyahilArekew USMember ✭✭

    I face the same problem too. I want my date value to be blank until the user click the button/tap the image.

  • JotharryDevelopmentJotharryDevelopment USMember ✭✭

    Yeah, I'd like this feature too. Trying to work with the DatePicker for my Windows Phone app at the moment. I think the custom renderer for it allows you to pass an empty string to the format to blank it out. When I try this in the Xamarin Forms sample I just get an exception being thrown.

  • AnthonyRamirezAnthonyRamirez USUniversity ✭✭✭

    I too would like to have ability to use null DateTime? on DatePicker and TimePicker.

  • InsulaInsula AUMember ✭✭

    +1

  • XammyXammy USMember

    +1

  • RobertAlmalakRobertAlmalak USMember ✭✭

    You could add a switch beside the datepicker which hides and shows the datepicker. If the switch is off you just ignore the value of the datepicker.

  • Thank you GeorgeGeorgiev, i was issuing the same problem but that code get it solved.

  • RonaldKasperRonaldKasper ATMember ✭✭

    Great, this is the solution for me. Thanks!

  • DanVanderboomDanVanderboom USUniversity ✭✭

    @GeorgeGeorgiev I like this control, but when I set NullableDate to {x:Null} in XAML, I get a NullReferenceException.

    How do you set this control to not have a Date value?

  • Brian_SnoddyBrian_Snoddy USUniversity

    Ok this works great. However I have one issue. When using this control I can set the nullabledate to null and it will display pick... on the control. When I select 'pick...' it shows today's date and lets say I want to pick today. When I click 'done' on the date picker it doesn't trigger MyDatePicker.DateSelected. Is there a way around this? I would like DateSelected to trigger every time the 'done' button is pressed.

  • Brian_SnoddyBrian_Snoddy USUniversity

    Thanks for the code it will take some time to review. I have noticed one other oddity with the default datepicker in forms. With WP and Android I can select the month and day and year in the date picker and the dateselected event is not fired until I click the done button in the datepicker. With iOS it fires as soon as I change the day, month or year not giving me a chance to select the entire date. Is there a way around this on the iPhone?

  • DarrellBookerDarrellBooker USMember ✭✭

    @RyanHatfield your solution does indeed work perfectly for iOS & Android. The only caveat is that I had to explicitly set the BindingMode to TwoWay. Without that it wasn't updating my view model.

    Nice work!

  • DarrellBookerDarrellBooker USMember ✭✭

    Here's further enhancements to @RyanHatfield‌ solution:

    Since there is no way to clear out a date, I added a button like so to my forms:

    var clearpicker= new Button {<br /> Command=new Command ( () => {<br /> picker.Date=null;<br /> })<br /> };<br />

    That will update the date to null and send null back to your view model but unfortunately it still leaves the date on the picker but if you add _UpdateText (); to the last line of the OnPropertyChanged from Ryan's solution this will cause the picker to revert back to your DefaultText i.e.; "Pick a date.."

  • RyanHatfieldOldRyanHatfieldOld USMember, Insider ✭✭✭

    Hey thanks @DarrellBrooker.6697 for finishing this out, change looks good.

    I'd say that's a good "use case" modification,

    one that everyone might not need .. but certainly one a bunch of people would want.

    Ryan

  • ThomasHagstrmThomasHagstrm SEMember ✭✭

    Anyone tried with third party controls? Xamarin Labs nuget pack maybe?

  • JonathanZunigaJonathanZuniga USMember ✭✭

    Hi, I am trying to put the stored date like default text with format MMMM dd. I have the following code:

    var birthdayDate = new DatePickerButton ();
    birthdayDate.SetBinding (DatePickerButton.DateProperty, "Birthday");
    birthdayDate.DefaultText = Convert.ToDateTime(birthdayDate.Date).ToString("MMMM d", CultureInfo.InvariantCulture);

    But return different value (January 1). What am I doing wrong?

  • Bikash.4523Bikash.4523 USMember

    @RyanHatfield When i click for selecting date after clicking on cancel button or clicking outside datepicker popup, the datepicker popup does not use to come. Thanks in advance..!!

  • XavierMaurinXavierMaurin FRMember

    I made a little change to @GeorgeGeorgiev solution.
    To avoid the "Pick..." problem, I added a DateFormat property which allows to define the date format inside the text box.

    Here is the source code... And everything works fine (at least on Android, not tested on iOS or WP):

    public class CustomDatePicker : DatePicker
    {
    private string _format = null;
    public static readonly BindableProperty NullableDateProperty = BindableProperty.Create<CustomDatePicker, DateTime?>(p => p.NullableDate, null);

        public DateTime? NullableDate
        {
            get { return (DateTime?)GetValue(NullableDateProperty); }
            set { SetValue(NullableDateProperty, value); UpdateDate(); }
        }
    
        public static readonly BindableProperty DateFormatProperty = BindableProperty.Create<CustomDatePicker, string>(p => p.DateFormat,
                defaultValue: default(string),
                defaultBindingMode: BindingMode.OneWay,
                propertyChanging: (bindable, oldValue, newValue) =>
                {
                    var ctrl = (CustomDatePicker)bindable;
                    ctrl.DateFormat = newValue;
                });
    
        public string DateFormat
        {
            get { return (string)GetValue(DateFormatProperty); }
            set { SetValue(DateFormatProperty, value); }
        }
    
        private void UpdateDate()
        {
            if (NullableDate.HasValue) 
            { 
                Format = DateFormat; 
                Date = NullableDate.Value; 
            }
            else 
            { 
                _format = Format; 
                Format = "..."; 
            }
        }
        protected override void OnBindingContextChanged()
        {
            base.OnBindingContextChanged();
            UpdateDate();
        }
    
        protected override void OnPropertyChanged(string propertyName = null)
        {
            base.OnPropertyChanged(propertyName);
            if (propertyName == "Date") 
                NullableDate = Date;
        }        
    }
    
  • Hello everyone ... how can I use in XAML, as do the binding?

  • MercifulGiraffeMercifulGiraffe USMember ✭✭

    Please note, that the solutions above work just fine (in my experience) for WinPhone (I cant speak for iOS or Android), but they do not work for WinRT (Windows 8.1) solutions.

  • My solution

    Custom control:

    public class NullableDatePicker : DatePicker
        {
            public static readonly BindableProperty NullableDateProperty = BindableProperty.Create(
                "NullableDate", typeof (DateTime?), typeof (NullableDatePicker), null, BindingMode.TwoWay);
    
            public static readonly BindableProperty EmptyStateTextProperty = BindableProperty.Create(
                "EmptyStateText", typeof (string), typeof (NullableDatePicker), string.Empty, BindingMode.OneWay);
    
            public DateTime? NullableDate
            {
                get { return (DateTime?) GetValue(NullableDateProperty); }
                set
                {
                    if (value != NullableDate)
                    {
                        SetValue(NullableDateProperty, value);
                        UpdateDate();
                    }
                }
            }
    
            public string EmptyStateText
            {
                get { return (string) GetValue(EmptyStateTextProperty); }
                set { SetValue(EmptyStateTextProperty, value); }
            }
    
            protected override void OnBindingContextChanged()
            {
                base.OnBindingContextChanged();
                UpdateDate();
            }
    
            protected override void OnPropertyChanged(string propertyName = null)
            {
                base.OnPropertyChanged(propertyName);
    
                Device.OnPlatform(() =>
                {
                    if (propertyName == IsFocusedProperty.PropertyName)
                    {
                        if (IsFocused)
                        {
                            if (!NullableDate.HasValue)
                            {
                                Date = (DateTime) DateProperty.DefaultValue;
                            }
                        }
                        else
                        {
                            OnPropertyChanged(DateProperty.PropertyName);
                        }
                    }
                });
    
                if (propertyName == DateProperty.PropertyName)
                {
                    NullableDate = Date;
                }
    
                if (propertyName == NullableDateProperty.PropertyName)
                {
                    if (NullableDate.HasValue)
                    {
                        Date = NullableDate.Value;
                    }
                }
            }
    
            private void UpdateDate()
            {
                if (NullableDate.HasValue)
                {
                    Date = NullableDate.Value;
                }
                else
                {
                    Date = (DateTime) DateProperty.DefaultValue;
                }
            }
        }
    

    iOS renderer:

        [assembly: ExportRenderer(typeof (NullableDatePicker), typeof (NullableDatePickerRenderer))]
        namespace Your.Namespace
        {
            public class NullableDatePickerRenderer : DatePickerRenderer
            {
                protected override void OnElementChanged(ElementChangedEventArgs<DatePicker> e)
                {
                    base.OnElementChanged(e);
    
                    TryShowEmptyState();
                }
    
                protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
                {
                    base.OnElementPropertyChanged(sender, e);
    
                    if (e.PropertyName == NullableDatePicker.NullableDateProperty.PropertyName ||
                        e.PropertyName == NullableDatePicker.EmptyStateTextProperty.PropertyName)
                    {
                        TryShowEmptyState();
                    }
                }
    
                private void TryShowEmptyState()
                {
                    var el = Element as NullableDatePicker;
                    if (el != null)
                    {
                        if (el.NullableDate == null)
                        {
                            Control.Text = el.EmptyStateText;
                        }
                    }
                }
            }
        }
    

    Android renderer:

        [assembly: ExportRenderer(typeof (NullableDatePicker), typeof (NullableDatePickerRenderer))]
        namespace Your.Namespace
        {
            internal class NullableDatePickerRenderer : DatePickerRenderer
            {
                protected override void OnElementChanged(ElementChangedEventArgs<DatePicker> e)
                {
                    base.OnElementChanged(e);
    
                    TryShowEmptyState();
                }
    
                protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
                {
                    base.OnElementPropertyChanged(sender, e);
    
                    if (e.PropertyName == NullableDatePicker.NullableDateProperty.PropertyName ||
                        e.PropertyName == NullableDatePicker.EmptyStateTextProperty.PropertyName)
                    {
                        TryShowEmptyState();
                    }
                }
    
                private void TryShowEmptyState()
                {
                    var el = Element as NullableDatePicker;
                    if (el != null)
                    {
                        if (el.NullableDate == null)
                        {
                            Control.Text = el.EmptyStateText;
                        }
                    }
                }
            }
        }
    
  • TonyMykhaylovskyTonyMykhaylovsky USMember
    edited October 2016

    @jrogalan said:
    Hi there,

    I post my current solution on gist. Based mainly on:

    • Aliaksandr Rastarhuyeu solution (for Nullable idea)
    • ExtendedEntry from Xamarin Labs (for real placeholders and colors, not Control.Text, aligns, etc)
    • Entry and DatePicker from Xamarin Core (for type conversions and ios color extensions)

    ExtendedDatePicker for Nullable values

    I continue working on it.

    Thank you all for your contributions!

    Thank you for pulling all the code together. It works great. When a null DateTime comes in, the textbox displays the placeholder. When you select a date and click Done or tap out of the picker, it selects a date. Now, what IF I want to clear the date? There's no way of doing that.

    There are two options:
    (1) Modify the Picker view to include a Clear button (I don't know how to do this customization)
    image
    (2) Create a button next to the datepicker. Once clicked, it clears the text property and sets the value to null, which would then bind back to model.

    What do you guys think?

  • DorababuDorababu USMember ✭✭

    Hi @jrogalan , can you please post code for UWP renderer for nullable DatePicker.

  • DorababuDorababu USMember ✭✭

    Hi @GeorgeGeorgiev , the ExtendedDatePicker is not working on UWP.

  • RyanWatsonRyanWatson USMember ✭✭✭

    @RonaldKasper said:
    Hi everybody!

    I have a nullable date field in my object and I want to bind a date picker to it. When the value is null, I would just want to show no value in the picker. Is this possible?

    I tried

    datepicker.SetBinding (DatePicker.DateProperty, vm => vm.DueDate, BindingMode.TwoWay);

    but this results in a NullValueException when the view is shown.

    Any ideas?

    @RonaldKasper Did you ever find a solution for this? I am having the same issue where if you select Today's Date when the field is null, then the values aren't set.

  • SivaShankarArumugamSivaShankarArumugam USMember ✭✭✭
    edited April 3

    @jrogalan Could you be please share the sample for uwp renderer

  • SivaShankarArumugamSivaShankarArumugam USMember ✭✭✭

    @RyanHatfieldOld your sample code is working fine for android & iOS, but not in UWP, do I have to add any code for UWP separately. if you so please share the sample code

  • SianRogers.3931SianRogers.3931 USMember ✭✭
    edited June 27

    Please could you elaborate on point 4 of @RyanHatfieldOld post regarding raising public event EventHandler NullableDateSelected;? An example of what can be done would be great. I have tried creating an event handler in the usual way but I cannot get it to work. Thank you

  • elores77elores77 USMember
    edited June 29

    My solution using CustomDatePicker from @GeorgeGeorgiev and a custom renderer which captures a long press into the DatePicker to set NullableDate to null:

    public class CustomDatePicker : DatePicker
        {
            private string _format = null;
    
            public static readonly BindableProperty NullableDateProperty =
              BindableProperty.Create(nameof(NullableDate), typeof(DateTime?), typeof(CustomDatePicker), null);
    
    
            public CustomDatePicker()
            {
    
            }
    
            public DateTime? NullableDate
            {
                get { return (DateTime?)GetValue(NullableDateProperty); }
                set { SetValue(NullableDateProperty, value); UpdateDate(); }
            }
    
    
            private void UpdateDate()
            {
                if (NullableDate.HasValue) { if (null != _format) Format = _format; Date = NullableDate.Value; }
                else { _format = Format; Format = "pick ..."; }
            }
            protected override void OnBindingContextChanged()
            {
                base.OnBindingContextChanged();
                UpdateDate();
            }
    
            protected override void OnPropertyChanged(string propertyName = null)
            {
                base.OnPropertyChanged(propertyName);
                if (propertyName == nameof(IsFocused) && !IsFocused) NullableDate = Date; 
            }
    
            // declare an event if you need a custom action on long press
            //public event EventHandler LongPressed;
    
            public virtual void OnLongPressed()
            {
                NullableDate = null;
    
                // use event if you need a custom action on long press
                //LongPressed?.Invoke(this, EventArgs.Empty);
            }
        }
    

    This is the Android renderer. (Similar for IOS)

    [assembly: ExportRenderer(typeof(Xamarin.Forms.DatePicker), typeof(CustomDatePickerRenderer))]
    namespace YourNameSpace
    {
        class CustomDatePickerRenderer : DatePickerRenderer
        {
            protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.DatePicker> e)
            {
                base.OnElementChanged(e);
    
                var customButton = e.NewElement as CustomDatePicker;
    
                var thisButton = Control as Android.Widget.EditText;
                thisButton.LongClick += (object sender, LongClickEventArgs args) =>
                {
                    customButton.OnLongPressed();
                };
            }
        }
    }
    
  • ShimmyWeitzhandlerShimmyWeitzhandler USMember ✭✭✭
    edited July 23
    Why is everything so limited with the controls in XF.
    They can definitely learn from the WPF set of events and customizations provided by each control. For someone coming from the WPF/UWP world, XF can be totally depressing.
  • marciosouzajuniormarciosouzajunior BRMember ✭✭

    Someone can say if this will be implemented?

  • CharlinCharlin DOUniversity ✭✭

    Just wrote an article about Clearable Date Picker, hope it helps:
    https://xamgirl.com/clearable-datepicker-in-xamarin-forms/

  • TonyGrayTonyGray USMember ✭✭
    edited October 30

    @Charlin Nice null date picker.
    Placeholder only seems to take in date formats though else it crashes.

Sign In or Register to comment.