Datepicker: Possible to bind to Nullable date value?

RonaldKasperRonaldKasper Ronald KasperATMember ✭✭

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 Ch Wo 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 Miniyahil Arekew Arekew 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 Jotharry Development 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 Anthony Ramirez USUniversity ✭✭✭

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

  • InsulaInsula Development Manager AUMember

    +1

  • XammyXammy Xamarin Account USMember

    +1

  • RobertAlmalakRobertAlmalak Robert Almalak 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.

  • diazfrankelydiazfrankely Frankely Diaz USMember

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

  • RonaldKasperRonaldKasper Ronald Kasper ATMember ✭✭

    Great, this is the solution for me. Thanks!

  • DanVanderboomDanVanderboom Dan Vanderboom 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 Brian 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.

  • RafaelMatosRafaelMatos Rafael Matos USMember

    +1, come on xamarin, not all DateTime fields should be marked as "required" (hence the need for a empty DateTime field)

  • Brian_SnoddyBrian_Snoddy Brian 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 Darrell Booker 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 Darrell Booker 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 {
    Command=new Command ( () => {
    picker.Date=null;
    })
    };

    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 Ryan Hatfield 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 Thomas Hagström SEMember ✭✭

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

  • JonathanZunigaJonathanZuniga Jonathan Zúñiga 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 Bikash 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 Xavier Maurin 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;
        }        
    }
    
  • DanieleAlpinoDanieleAlpino Daniele Alpino BRMember

    Hello everyone ... how can I use in XAML, as do the binding?

  • MercifulGiraffeMercifulGiraffe Stacy Henwood 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.

  • AliaksandrRastarhuyeuAliaksandrRastarhuyeu Aliaksandr Rastarhuyeu USUniversity

    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 Tony Mykhaylovsky 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 Dorababu Dodda USMember ✭✭

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

  • DorababuDorababu Dorababu Dodda USMember ✭✭

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

  • RyanWatsonRyanWatson Ryan Watson 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 SivaShankar Arumugam USMember ✭✭✭
    edited April 3

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

  • SivaShankarArumugamSivaShankarArumugam SivaShankar Arumugam 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

Sign In or Register to comment.