locked
Datepicker: Possible to bind to Nullable date value? RRS feed

  • Question

  • User37713 posted

    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?

    Wednesday, July 9, 2014 4:11 AM

Answers

  • User47214 posted

    You can try inheriting from the DatePicker and adding a property that can be bound to DateTime? type. See the code below. In this case you can bind to NullableDate property instead of Date.

    public class MyDatePicker : DatePicker
        {
            private string _format = null;
            public static readonly BindableProperty NullableDateProperty = BindableProperty.Create<MyDatePicker, DateTime?>(p => p.NullableDate, null);
    
            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 == "Date") NullableDate = Date;
            }
        }
    
    • Marked as answer by Anonymous Thursday, June 3, 2021 12:00 AM
    Sunday, August 10, 2014 2:57 AM
  • User40009 posted

    @BrianSnoddy.9247?

    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.

    My guess (and I'm pretty confident of this) is that you're not actually changing the date, so it's not causing the DateSelected to trigger.

    You could do a few things:

    1. You could add a constructor that sets the date to datetime.minvalue but that'll set the picker wrong
    2. You could make it set and reset the Date property every time it changes.. but that's hacky and will get messy
    3. Create your own public event EventHandler<DateChangedEventArgs> NullableDateSelected;
    4. Or add to the event internally for Unfocused.

    Code for #4

    Unfocused += MyDatePicker_Unfocused;    
    void MyDatePicker_Unfocused(object sender, FocusEventArgs e)
    {
        var tmp = Date;
        Date = DateTime.MinValue;
        Date = tmp;
    }
    

    I should add that doing this will never let you cancel selecting something, going against normal UX design

    OOOOORRRRR

    You could forgo that MyDatePicker for another type of override.. You could extend a button to create a DatePicker() hidden away that gets triggered somewhere else.

    Here's my magical code ... it looks hacky but works well (ONLY TESTED ON ANDROID)

    public class DatePickerButton : Button
    {
        private DateTime? _OldDate;
        private DatePicker _Picker;
        private IViewContainer<View> _ParentLayout;
    
        public static readonly BindableProperty DateProperty =
            BindableProperty.Create<DatePickerButton, DateTime?>(p => p.Date, null);
        public DateTime? Date
        {
            get { return (DateTime?)GetValue(DateProperty); }
            set { SetValue(DateProperty, value); }
        }
    
        new private static readonly BindableProperty TextProperty = BindableProperty.Create<DatePickerButton, string>(p => p.Text, "...");
        new public string Text
        {
            get { return (string)GetValue(TextProperty); }
            private set { SetValue(TextProperty, value); }
        }
    
        public static readonly BindableProperty DefaultTextProperty = BindableProperty.Create<DatePickerButton, string>(p => p.DefaultText, "Pick Date...");
        public string DefaultText
        {
            get { return (string)GetValue(DefaultTextProperty); }
            set { SetValue(DefaultTextProperty, value); }
        }
    
        public static readonly BindableProperty TextFormatProperty =
            BindableProperty.Create<DatePickerButton, string>(p => p.TextFormat, "MM'/'dd'/'yyyy");
        public string TextFormat
        {
            get { return (string)GetValue(TextFormatProperty); }
            set { SetValue(TextFormatProperty, value); }
        }
    
        //hide the command so you don't accidentally override it
        new public Command Command
        {
            get { return (Command)GetValue(CommandProperty); }
            private set { SetValue(CommandProperty, value); }
        }
    
        public event EventHandler<DateChangedEventArgs> DateSelected;
    
        public DatePickerButton()
        {
            //create the datepicker, make it invisible on the form.
            _Picker = new DatePicker
            {
                IsVisible = false
            };
    
            //handle the focus/unfocus or rather the showing and hiding of the dateipicker
            _Picker.Focused += _Picker_Focused;
            _Picker.Unfocused += _Picker_Unfocused;
    
            //command for the button
            Command = new Command((obj) =>
            {
                //try to get the parent layout and add the datepicker
                if (_ParentLayout == null)
                {
                    _ParentLayout = _GetParentLayout(ParentView);
                    if (_ParentLayout != null)
                    {
                        //add the picker to the closest layout up the tree
                        _ParentLayout.Children.Add(_Picker);
                    }
                    else
                    {
                        throw new InvalidOperationException("The DatePickerButton needs to be inside an Layout type control that can have other children");
                    }
                }
                //show the picker modal
                _Picker.Focus();
            });
            _UpdateText();
        }
    
        private IViewContainer<View> _GetParentLayout(VisualElement ParentView)
        {
            //StackLayout, RelativeLayout, Grid, and AbsoluteLayout all implement IViewContainer,
            //it would be very rare that this method would return null.
            IViewContainer<View> parent = ParentView as IViewContainer<View>;
            if (ParentView == null)
            {
                return null;
            }
            else if (parent != null)
            {
                return parent;
            }
            else
            {
                return _GetParentLayout(ParentView.ParentView);
            }
        }
    
        void _Picker_Focused(object sender, FocusEventArgs e)
        {
            //default the date to now if Date is empty
            _Picker.Date = Date ?? DateTime.Now;
        }
    
        void _Picker_Unfocused(object sender, FocusEventArgs e)
        {
            //this always sets.. can't cancel the dialog.
            Date = _Picker.Date;
            _UpdateText();
        }
    
        protected override void OnBindingContextChanged()
        {
            base.OnBindingContextChanged();
            _UpdateText();
        }
    
        private void _UpdateText()
        {
            //the button has a default text, use that the first time.
            if (Date != null)
            {
                //default formatting is in the FormatProperty BindableProperty 
                base.Text = Date.Value.ToString(TextFormat);
            }
            else
            {
                base.Text = DefaultText;
            }
        }
    
        protected override void OnPropertyChanging(string propertyName = null)
        {
            //set this so there is an old date for the DateChangedEventArgs
            base.OnPropertyChanging(propertyName);
            _OldDate = Date;
        }
    
        protected override void OnPropertyChanged(string propertyName = null)
        {
            base.OnPropertyChanged(propertyName);
            if (propertyName == DateProperty.PropertyName)
            {
                //if the event isn't null, and the old date isn't null, and the date isn't null ... EVENT!
                if (DateSelected != null && _OldDate != null && Date != null)
                {
                    DateSelected(this, new DateChangedEventArgs((DateTime)_OldDate, (DateTime)Date));
                }
                //if the event isn't null, and the date isn't null ... EVENT!
                else if (DateSelected != null && Date != null)
                {
                    DateSelected(this, new DateChangedEventArgs((DateTime)Date, (DateTime)Date));
                }
                _OldDate = null;
            }
        }
    }
    
    • Marked as answer by Anonymous Thursday, June 3, 2021 12:00 AM
    Wednesday, October 29, 2014 7:35 PM

All replies

  • User1544 posted

    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.

    Sunday, July 13, 2014 2:30 PM
  • User60243 posted

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

    Tuesday, July 15, 2014 9:31 PM
  • User25782 posted

    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.

    Wednesday, July 16, 2014 10:38 AM
  • User55225 posted

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

    Saturday, August 2, 2014 3:40 PM
  • User20820 posted

    +1

    Monday, August 4, 2014 1:52 AM
  • User48152 posted

    +1

    Wednesday, August 6, 2014 3:30 PM
  • User23564 posted

    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.

    Wednesday, August 6, 2014 3:38 PM
  • User47214 posted

    You can try inheriting from the DatePicker and adding a property that can be bound to DateTime? type. See the code below. In this case you can bind to NullableDate property instead of Date.

    public class MyDatePicker : DatePicker
        {
            private string _format = null;
            public static readonly BindableProperty NullableDateProperty = BindableProperty.Create<MyDatePicker, DateTime?>(p => p.NullableDate, null);
    
            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 == "Date") NullableDate = Date;
            }
        }
    
    • Marked as answer by Anonymous Thursday, June 3, 2021 12:00 AM
    Sunday, August 10, 2014 2:57 AM
  • User22838 posted

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

    Monday, September 8, 2014 1:56 AM
  • User37713 posted

    Great, this is the solution for me. Thanks!

    Monday, September 8, 2014 3:34 AM
  • User40038 posted

    @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?

    Tuesday, October 21, 2014 11:56 PM
  • User77647 posted

    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.

    Wednesday, October 29, 2014 2:34 PM
  • User40009 posted

    @BrianSnoddy.9247?

    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.

    My guess (and I'm pretty confident of this) is that you're not actually changing the date, so it's not causing the DateSelected to trigger.

    You could do a few things:

    1. You could add a constructor that sets the date to datetime.minvalue but that'll set the picker wrong
    2. You could make it set and reset the Date property every time it changes.. but that's hacky and will get messy
    3. Create your own public event EventHandler<DateChangedEventArgs> NullableDateSelected;
    4. Or add to the event internally for Unfocused.

    Code for #4

    Unfocused += MyDatePicker_Unfocused;    
    void MyDatePicker_Unfocused(object sender, FocusEventArgs e)
    {
        var tmp = Date;
        Date = DateTime.MinValue;
        Date = tmp;
    }
    

    I should add that doing this will never let you cancel selecting something, going against normal UX design

    OOOOORRRRR

    You could forgo that MyDatePicker for another type of override.. You could extend a button to create a DatePicker() hidden away that gets triggered somewhere else.

    Here's my magical code ... it looks hacky but works well (ONLY TESTED ON ANDROID)

    public class DatePickerButton : Button
    {
        private DateTime? _OldDate;
        private DatePicker _Picker;
        private IViewContainer<View> _ParentLayout;
    
        public static readonly BindableProperty DateProperty =
            BindableProperty.Create<DatePickerButton, DateTime?>(p => p.Date, null);
        public DateTime? Date
        {
            get { return (DateTime?)GetValue(DateProperty); }
            set { SetValue(DateProperty, value); }
        }
    
        new private static readonly BindableProperty TextProperty = BindableProperty.Create<DatePickerButton, string>(p => p.Text, "...");
        new public string Text
        {
            get { return (string)GetValue(TextProperty); }
            private set { SetValue(TextProperty, value); }
        }
    
        public static readonly BindableProperty DefaultTextProperty = BindableProperty.Create<DatePickerButton, string>(p => p.DefaultText, "Pick Date...");
        public string DefaultText
        {
            get { return (string)GetValue(DefaultTextProperty); }
            set { SetValue(DefaultTextProperty, value); }
        }
    
        public static readonly BindableProperty TextFormatProperty =
            BindableProperty.Create<DatePickerButton, string>(p => p.TextFormat, "MM'/'dd'/'yyyy");
        public string TextFormat
        {
            get { return (string)GetValue(TextFormatProperty); }
            set { SetValue(TextFormatProperty, value); }
        }
    
        //hide the command so you don't accidentally override it
        new public Command Command
        {
            get { return (Command)GetValue(CommandProperty); }
            private set { SetValue(CommandProperty, value); }
        }
    
        public event EventHandler<DateChangedEventArgs> DateSelected;
    
        public DatePickerButton()
        {
            //create the datepicker, make it invisible on the form.
            _Picker = new DatePicker
            {
                IsVisible = false
            };
    
            //handle the focus/unfocus or rather the showing and hiding of the dateipicker
            _Picker.Focused += _Picker_Focused;
            _Picker.Unfocused += _Picker_Unfocused;
    
            //command for the button
            Command = new Command((obj) =>
            {
                //try to get the parent layout and add the datepicker
                if (_ParentLayout == null)
                {
                    _ParentLayout = _GetParentLayout(ParentView);
                    if (_ParentLayout != null)
                    {
                        //add the picker to the closest layout up the tree
                        _ParentLayout.Children.Add(_Picker);
                    }
                    else
                    {
                        throw new InvalidOperationException("The DatePickerButton needs to be inside an Layout type control that can have other children");
                    }
                }
                //show the picker modal
                _Picker.Focus();
            });
            _UpdateText();
        }
    
        private IViewContainer<View> _GetParentLayout(VisualElement ParentView)
        {
            //StackLayout, RelativeLayout, Grid, and AbsoluteLayout all implement IViewContainer,
            //it would be very rare that this method would return null.
            IViewContainer<View> parent = ParentView as IViewContainer<View>;
            if (ParentView == null)
            {
                return null;
            }
            else if (parent != null)
            {
                return parent;
            }
            else
            {
                return _GetParentLayout(ParentView.ParentView);
            }
        }
    
        void _Picker_Focused(object sender, FocusEventArgs e)
        {
            //default the date to now if Date is empty
            _Picker.Date = Date ?? DateTime.Now;
        }
    
        void _Picker_Unfocused(object sender, FocusEventArgs e)
        {
            //this always sets.. can't cancel the dialog.
            Date = _Picker.Date;
            _UpdateText();
        }
    
        protected override void OnBindingContextChanged()
        {
            base.OnBindingContextChanged();
            _UpdateText();
        }
    
        private void _UpdateText()
        {
            //the button has a default text, use that the first time.
            if (Date != null)
            {
                //default formatting is in the FormatProperty BindableProperty 
                base.Text = Date.Value.ToString(TextFormat);
            }
            else
            {
                base.Text = DefaultText;
            }
        }
    
        protected override void OnPropertyChanging(string propertyName = null)
        {
            //set this so there is an old date for the DateChangedEventArgs
            base.OnPropertyChanging(propertyName);
            _OldDate = Date;
        }
    
        protected override void OnPropertyChanged(string propertyName = null)
        {
            base.OnPropertyChanged(propertyName);
            if (propertyName == DateProperty.PropertyName)
            {
                //if the event isn't null, and the old date isn't null, and the date isn't null ... EVENT!
                if (DateSelected != null && _OldDate != null && Date != null)
                {
                    DateSelected(this, new DateChangedEventArgs((DateTime)_OldDate, (DateTime)Date));
                }
                //if the event isn't null, and the date isn't null ... EVENT!
                else if (DateSelected != null && Date != null)
                {
                    DateSelected(this, new DateChangedEventArgs((DateTime)Date, (DateTime)Date));
                }
                _OldDate = null;
            }
        }
    }
    
    • Marked as answer by Anonymous Thursday, June 3, 2021 12:00 AM
    Wednesday, October 29, 2014 7:35 PM
  • User24774 posted

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

    Thursday, October 30, 2014 5:43 PM
  • User77647 posted

    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?

    Thursday, November 6, 2014 3:14 PM
  • User763 posted

    @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!

    Thursday, November 13, 2014 4:05 PM
  • User763 posted

    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.."

    Thursday, November 13, 2014 6:00 PM
  • User40009 posted

    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

    Thursday, November 13, 2014 10:03 PM
  • User73114 posted

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

    Wednesday, January 28, 2015 7:58 PM
  • User102552 posted

    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?

    Thursday, January 29, 2015 6:10 AM
  • User87600 posted

    @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..!!

    Monday, May 18, 2015 10:01 AM
  • User101501 posted

    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(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;
        }        
    }
    
    Wednesday, October 28, 2015 9:51 PM
  • User149139 posted

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

    Monday, November 23, 2015 11:24 PM
  • User172849 posted

    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.

    Tuesday, November 24, 2015 3:11 AM
  • User121720 posted

    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;
                        }
                    }
                }
            }
        }
    
    Monday, August 1, 2016 1:16 PM
  • User189749 posted

    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!

    Friday, September 9, 2016 7:46 AM
  • User173389 posted

    @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) (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?

    Monday, October 31, 2016 8:38 PM
  • User20859 posted

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

    Thursday, March 16, 2017 5:58 AM
  • User20859 posted

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

    Thursday, March 16, 2017 6:31 AM
  • User393 posted

    @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.

    Tuesday, March 21, 2017 3:30 AM
  • User227972 posted

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

    Monday, April 3, 2017 12:41 PM
  • User227972 posted

    @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

    Monday, April 3, 2017 12:55 PM
  • User311026 posted

    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

    Tuesday, June 27, 2017 11:06 AM
  • User293529 posted

    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();
                };
            }
        }
    }
    
    Thursday, June 29, 2017 9:40 AM
  • User248484 posted

    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.

    Sunday, July 23, 2017 5:44 PM
  • User97480 posted

    Someone can say if this will be implemented?

    Monday, August 7, 2017 8:07 PM
  • User120838 posted

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

    Thursday, August 24, 2017 3:39 PM
  • User77720 posted

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

    Monday, October 30, 2017 9:17 PM
  • User328707 posted

    @TonyGray you just need to escape your date format string PlaceHolder = "\"whatever you want\"";

    Thursday, February 8, 2018 8:07 AM
  • User77720 posted

    @krispenner My comment is redundant as the latest version of GIT repo no longer has this issue!

    Wednesday, February 14, 2018 10:50 PM
  • User216512 posted

    I'm trying this myself right now but running into strange problems with bindings.

    With a BindableProperty of type string it works, e.g.

    Placeholder="PlaceholderText"

    and with bindable properties of types Datetime and Datetime? it works like so:

    Placeholder="{x:Static system:DateTime.Now}"

    so finally I try it by binding to properties in my ViewModel, which loads data from Sqlite:

    Placeholder="{Binding Todo.ReminderDate}"

    and I get an error message with "Property does not exist, or is not assignable, or mismatching type between value and property.

    I've tried using string to datetime converters but no dice. What am I doing wrong here?

    Wednesday, July 25, 2018 3:54 PM
  • User89714 posted

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

    Has anybody extended this to support UWP as well? If so, would it be possible to share the code please?

    Wednesday, July 25, 2018 4:19 PM
  • User330867 posted

    I am also looking for the UWP version

    Friday, February 28, 2020 12:02 PM
  • User365180 posted

    I'm a little late to the party here, but I needed to solve this for UWP as well. Hope this helps someone else out (Disclaimer: this is not a complete solution, but it was complete enough for my needs - feel free to expand as necessary)

    ``` public class NullableDatePickerRenderer : ViewRenderer { private CalendarDatePicker datePicker; private Windows.UI.Xaml.Controls.Button cancelButton; private Windows.UI.Xaml.Controls.Grid calendarView;

        protected override void OnElementChanged(ElementChangedEventArgs<NullableDatePicker> e)
        {
            base.OnElementChanged(e);
    
            if (e.NewElement != null && Control == null)
            {
                this.datePicker = new CalendarDatePicker();
                this.datePicker.MinDate = this.Element.MinimumDate;
                this.datePicker.MaxDate = this.Element.MaximumDate;
                this.datePicker.Date = this.Element.NullableDate;
                this.datePicker.DateChanged += DatePicker_DateChanged;
    
                this.cancelButton = new Windows.UI.Xaml.Controls.Button()
                {
                    Content = "Clear",
                    Margin = new Windows.UI.Xaml.Thickness(5),
                    Command = new Command(
                        () => this.datePicker.Date = null,
                        () => this.datePicker.Date != null)
                };
    
                this.calendarView = new Windows.UI.Xaml.Controls.Grid();
                this.calendarView.SizeChanged += CalendarView_SizeChanged;
    
                this.calendarView.ColumnDefinitions.Add(new Windows.UI.Xaml.Controls.ColumnDefinition()
                {
                    Width = new Windows.UI.Xaml.GridLength(0, Windows.UI.Xaml.GridUnitType.Auto)
                });
    
                this.calendarView.ColumnDefinitions.Add(new Windows.UI.Xaml.Controls.ColumnDefinition()
                {
                    Width = new Windows.UI.Xaml.GridLength(0, Windows.UI.Xaml.GridUnitType.Auto)
                });
    
                this.calendarView.Children.Add(this.datePicker);
                Windows.UI.Xaml.Controls.Grid.SetColumn(this.datePicker, 0);
    
                this.calendarView.Children.Add(this.cancelButton);
                Windows.UI.Xaml.Controls.Grid.SetColumn(this.cancelButton, 1);
    
                this.SetNativeControl(this.calendarView);
            }
        }
    
        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == NullableDatePicker.NullableDateProperty.PropertyName || e.PropertyName == Xamarin.Forms.DatePicker.FormatProperty.PropertyName)
            {
                var entry = (NullableDatePicker)this.Element;
                ((Command)cancelButton.Command).ChangeCanExecute();
    
                if (this.Element.Format == entry.PlaceHolder)
                {
                    this.datePicker.PlaceholderText = entry.PlaceHolder;
                    return;
                }
            }
    
            base.OnElementPropertyChanged(sender, e);
        }
    
        private void DatePicker_DateChanged(CalendarDatePicker sender, CalendarDatePickerDateChangedEventArgs args)
        {
            if (this.Element != null)
            {
                this.Element.NullableDate = args.NewDate?.Date;
            }
        }
    
        private void CalendarView_SizeChanged(object sender, Windows.UI.Xaml.SizeChangedEventArgs e)
        {
            if (this.Element != null)
            {
                // NOTE: Depending on the placeholder text, the width needed for the calendar view may be different
                this.Element.WidthRequest = e.NewSize.Width;
            }
        }
    
        protected override void Dispose(bool disposing)
        {
            if (Control != null)
            {
                this.datePicker.DateChanged -= DatePicker_DateChanged;
                this.datePicker = null;
                this.cancelButton = null;
                this.calendarView = null;
            }
    
            base.Dispose(disposing);
        }
    }
    

    ```

    Wednesday, March 11, 2020 7:25 PM
  • User366776 posted

    how we bind the hidden filed with DatePicker? I want hidden value in on selected date method? please help me as soon as possible

    Sunday, July 26, 2020 9:20 AM
  • User390623 posted

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

    This is a great resource for making a nullable datepicker. One thing I ran into, however, is that on Android, the custom picker will not automatically have its text color set. So you have to add the following to the Android renderer, inside OnElementChanged:

    var color = entry.TextColor.ToAndroid(); Control.SetTextColor(color);

    Friday, September 4, 2020 5:49 PM