Reputation: 111
I have found a custom renderer online but there is an error. Does anyone know how can I make a date time control? Currently I am using separate date picker and time picker but I want it to be combined.
I will post the code below that I have found from another post. This is the link to the post Xamarin Forms date and time picker
using System;
using Foundation;
using Test;
using Test.Droid;
using UIKit;
using ObjCRuntime;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly:ExportRenderer(typeof(MyPicker), typeof(MyPickerRenderer))]
namespace Test.Droid
{
public class MyPickerRenderer : PickerRenderer
{
string SelectedValue;
[Obsolete]
public MyPickerRenderer()
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
{
base.OnElementChanged(e);
if (Control != null)
{
SetTimePicker();
}
}
void SetTimePicker()
{
UIDatePicker picker = new UIDatePicker
{
Mode = UIDatePickerMode.DateAndTime
};
picker.SetDate(NSDate.Now, true);
picker.AddTarget(this, new Selector("DateChange:"), UIControlEvent.ValueChanged);
Control.InputView = picker;
UIToolbar toolbar = (UIToolbar)Control.InputAccessoryView;
UIBarButtonItem done = new UIBarButtonItem("Done", UIBarButtonItemStyle.Done, (object sender, EventArgs click) =>
{
Control.Text = SelectedValue;
toolbar.RemoveFromSuperview();
picker.RemoveFromSuperview();
Control.ResignFirstResponder();
MessagingCenter.Send<Object, string>(this, "pickerSelected", SelectedValue);
});
UIBarButtonItem empty = new UIBarButtonItem(UIBarButtonSystemItem.FlexibleSpace, null);
toolbar.Items = new UIBarButtonItem[] { empty, done };
}
[Export("DateChange:")]
void DateChange(UIDatePicker picker)
{
NSDateFormatter formatter = new NSDateFormatter();
formatter.DateFormat = "MM-dd HH:mm aa"; //you can set the format as you want
Control.Text = formatter.ToString(picker.Date);
SelectedValue = formatter.ToString(picker.Date);
MessagingCenter.Send<Object, string>(this, "pickerSelected", SelectedValue);
}
}
}
Upvotes: 1
Views: 11033
Reputation: 187
To make it easier for anyone wanting to use the DateTimePicker with XAML integration (with a Binding), I merged answers from the original post of Wendy Zhang, the comments below it and the question (Custom control not being set to content width) from csharpdude77.
Code:
public class DateTimePicker : ContentView, INotifyPropertyChanged
{
private Entry _entry { get; set; } = new Entry() { WidthRequest = 300 };
private DatePicker _datePicker { get; set; } = new DatePicker() { MinimumDate = DateTime.Today, IsVisible = false };
private TimePicker _timePicker { get; set; } = new TimePicker() { IsVisible = false };
private string _stringFormat { get; set; }
private TimeSpan _time
{
get { return TimeSpan.FromTicks(DateTime.Ticks); }
set { DateTime = new DateTime(DateTime.Date.Ticks).AddTicks(value.Ticks); }
}
private DateTime _date
{
get { return DateTime.Date; }
set { DateTime = new DateTime(DateTime.TimeOfDay.Ticks).AddTicks(value.Ticks); }
}
public string StringFormat { get { return _stringFormat ?? "dd/MM/yyyy HH:mm"; } set { _stringFormat = value; } }
public DateTime DateTime
{
get { return (DateTime)GetValue(DateTimeProperty); }
set { SetValue(DateTimeProperty, value); OnPropertyChanged(nameof(DateTime)); }
}
public static BindableProperty DateTimeProperty = BindableProperty.Create(nameof(DateTime), typeof(DateTime), typeof(DateTimePicker), DateTime.Now, BindingMode.TwoWay, propertyChanged: DTPropertyChanged);
public DateTimePicker()
{
Content = new StackLayout()
{
Children =
{
_datePicker,
_timePicker,
_entry
}
};
_datePicker.SetBinding(DatePicker.DateProperty, nameof(_date));
_timePicker.SetBinding(TimePicker.TimeProperty, nameof(_time));
_timePicker.Unfocused += (sender, args) => _time = _timePicker.Time;
_datePicker.Focused += (s, a) => UpdateEntryText();
GestureRecognizers.Add(new TapGestureRecognizer()
{
Command = new Command(() => _datePicker.Focus())
});
_entry.Focused += (sender, args) =>
{
Device.BeginInvokeOnMainThread(() => _datePicker.Focus());
};
_datePicker.Unfocused += (sender, args) =>
{
Device.BeginInvokeOnMainThread(() =>
{
_timePicker.Focus();
_date = _datePicker.Date;
UpdateEntryText();
});
};
}
private void UpdateEntryText()
{
_entry.Text = DateTime.ToString(StringFormat);
}
private static void DTPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
var timePicker = bindable as DateTimePicker;
timePicker.UpdateEntryText();
}
}
Sample XAML usage:
<StackLayout>
<local:DateTimePicker DateTime="{Binding Source={RelativeSource AncestorType={x:Type class:NewRitViewModel}}, Path=DateTime}" StringFormat="dd-MM-yyyy HH:mm"></local:DateTimePicker>
</StackLayout>
Upvotes: 2
Reputation: 85
This is my Code Behind
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
void OnDateSelected(object sender, DateChangedEventArgs args)
{
Recalculate();
}
void OnSwitchToggled(object sender, ToggledEventArgs args)
{
Recalculate();
}
void Recalculate()
{
TimeSpan timeSpan = endDatePicker.Date - startDatePicker.Date +
(includeSwitch.IsToggled ? TimeSpan.FromDays(1) : TimeSpan.Zero);
resultLabel.Text = String.Format("{0} day{1} between dates",
timeSpan.Days, timeSpan.Days == 1 ? "" : "s");
}
}
Upvotes: 0
Reputation: 10978
Make the DateTimePicker inherit a ContentView
instead of just an Entry, and then creates the Stacklayout which add the Entry and the date and time pickers to content.
See the DateTimePicker2.cs:
public class DateTimePicker2 : ContentView, INotifyPropertyChanged
{
public Entry _entry { get; private set; } = new Entry();
public DatePicker _datePicker { get; private set; } = new DatePicker() { MinimumDate = DateTime.Today, IsVisible = false };
public TimePicker _timePicker { get; private set; } = new TimePicker() { IsVisible = false };
string _stringFormat { get; set; }
public string StringFormat { get { return _stringFormat ?? "dd/MM/yyyy HH:mm"; } set { _stringFormat = value; } }
public DateTime DateTime
{
get { return (DateTime)GetValue(DateTimeProperty); }
set { SetValue(DateTimeProperty, value); OnPropertyChanged("DateTime"); }
}
private TimeSpan _time
{
get
{
return TimeSpan.FromTicks(DateTime.Ticks);
}
set
{
DateTime = new DateTime(DateTime.Date.Ticks).AddTicks(value.Ticks);
}
}
private DateTime _date
{
get
{
return DateTime.Date;
}
set
{
DateTime = new DateTime(DateTime.TimeOfDay.Ticks).AddTicks(value.Ticks);
}
}
BindableProperty DateTimeProperty = BindableProperty.Create("DateTime", typeof(DateTime), typeof(DateTimePicker2), DateTime.Now, BindingMode.TwoWay, propertyChanged: DTPropertyChanged);
public DateTimePicker2()
{
BindingContext = this;
Content = new StackLayout()
{
Children =
{
_datePicker,
_timePicker,
_entry
}
};
_datePicker.SetBinding<DateTimePicker2>(DatePicker.DateProperty, p => p._date);
_timePicker.SetBinding<DateTimePicker2>(TimePicker.TimeProperty, p => p._time);
_timePicker.Unfocused += (sender, args) => _time = _timePicker.Time;
_datePicker.Focused += (s, a) => UpdateEntryText();
GestureRecognizers.Add(new TapGestureRecognizer()
{
Command = new Command(() => _datePicker.Focus())
});
_entry.Focused += (sender, args) =>
{
Device.BeginInvokeOnMainThread(() => _datePicker.Focus());
};
_datePicker.Unfocused += (sender, args) =>
{
Device.BeginInvokeOnMainThread(() =>
{
_timePicker.Focus();
_date = _datePicker.Date;
UpdateEntryText();
});
};
}
private void UpdateEntryText()
{
_entry.Text = DateTime.ToString(StringFormat);
}
static void DTPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
var timePicker = (bindable as DateTimePicker2);
timePicker.UpdateEntryText();
}
}
Usage in Xaml:
<StackLayout>
<local:DateTimePicker2></local:DateTimePicker2>
</StackLayout>
Upvotes: 11
Reputation: 10978
On Xamarin.forms Android, you could try the code below.
Create a DateTimePicker.cs class.
public class DateTimePicker : Entry, INotifyPropertyChanged
{
public DatePicker _datePicker { get; private set; } = new DatePicker() { MinimumDate = DateTime.Today, IsVisible = false };
public TimePicker _timePicker { get; private set; } = new TimePicker() { IsVisible = false };
string _stringFormat { get; set; }
public string StringFormat { get { return _stringFormat ?? "dd/MM/yyyy HH:mm"; } set { _stringFormat = value; } }
public DateTime DateTime
{
get { return (DateTime)GetValue(DateTimeProperty); }
set { SetValue(DateTimeProperty, value); OnPropertyChanged("DateTime"); }
}
private TimeSpan _time
{
get
{
return TimeSpan.FromTicks(DateTime.Ticks);
}
set
{
DateTime = new DateTime(DateTime.Date.Ticks).AddTicks(value.Ticks);
}
}
private DateTime _date
{
get
{
return DateTime.Date;
}
set
{
DateTime = new DateTime(DateTime.TimeOfDay.Ticks).AddTicks(value.Ticks);
}
}
BindableProperty DateTimeProperty = BindableProperty.Create("DateTime", typeof(DateTime), typeof(DateTimePicker), DateTime.Now, BindingMode.TwoWay, propertyChanged: DTPropertyChanged);
public DateTimePicker()
{
BindingContext = this;
_datePicker.SetBinding<DateTimePicker>(DatePicker.DateProperty, p => p._date);
_timePicker.SetBinding<DateTimePicker>(TimePicker.TimeProperty, p => p._time);
_timePicker.Unfocused += (sender, args) => _time = _timePicker.Time;
_datePicker.Focused += (s, a) => UpdateEntryText();
GestureRecognizers.Add(new TapGestureRecognizer()
{
Command = new Command(() => _datePicker.Focus())
});
Focused += (sender, args) =>
{
Device.BeginInvokeOnMainThread(() => _datePicker.Focus());
};
_datePicker.Unfocused += (sender, args) =>
{
Device.BeginInvokeOnMainThread(() =>
{
_timePicker.Focus();
_date = _datePicker.Date;
UpdateEntryText();
});
};
}
private void UpdateEntryText()
{
Text = DateTime.ToString(StringFormat);
}
static void DTPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
var timePicker = (bindable as DateTimePicker);
timePicker.UpdateEntryText();
}
}
Uasge in App.xaml.cs
var dtPicker = new DateTimePicker()
{
VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand,
StringFormat = "HH:mm dd/MM/yyyy"
};
MainPage = new ContentPage
{
Content = new StackLayout
{
VerticalOptions = LayoutOptions.Center,
Children = {
dtPicker._datePicker,
dtPicker._timePicker,
dtPicker
},
BackgroundColor = Color.Aqua
}
};
Upvotes: 1
Reputation: 85
I have attached code for date time picker
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DaysBetweenDates"
x:Class="DaysBetweenDates.MainPage">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS" Value="0, 20, 0, 0" />
</OnPlatform>
</ContentPage.Padding>
<StackLayout Margin="10">
<Label Text="Days Between Dates"
Style="{DynamicResource TitleStyle}"
Margin="0, 20"
HorizontalTextAlignment="Center" />
<Label Text="Start Date:" />
<DatePicker x:Name="startDatePicker"
Format="D"
Margin="30, 0, 0, 30"
DateSelected="OnDateSelected" />
<Label Text="End Date:" />
<DatePicker x:Name="endDatePicker"
MinimumDate="{Binding Source={x:Reference startDatePicker},
Path=Date}"
Format="D"
Margin="30, 0, 0, 30"
DateSelected="OnDateSelected" />
<StackLayout Orientation="Horizontal"
Margin="0, 0, 0, 30">
<Label Text="Include both days in total: "
VerticalOptions="Center" />
<Switch x:Name="includeSwitch"
Toggled="OnSwitchToggled" />
</StackLayout>
<Label x:Name="resultLabel"
FontAttributes="Bold"
HorizontalTextAlignment="Center" />
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DaysBetweenDates"
x:Class="DaysBetweenDates.MainPage">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS" Value="0, 20, 0, 0" />
</OnPlatform>
</ContentPage.Padding>
<StackLayout Margin="10">
<Label Text="Days Between Dates"
Style="{DynamicResource TitleStyle}"
Margin="0, 20"
HorizontalTextAlignment="Center" />
<Label Text="Start Date:" />
<DatePicker x:Name="startDatePicker"
Format="D"
Margin="30, 0, 0, 30"
DateSelected="OnDateSelected" />
<Label Text="End Date:" />
<DatePicker x:Name="endDatePicker"
MinimumDate="{Binding Source={x:Reference startDatePicker},
Path=Date}"
Format="D"
Margin="30, 0, 0, 30"
DateSelected="OnDateSelected" />
<StackLayout Orientation="Horizontal"
Margin="0, 0, 0, 30">
<Label Text="Include both days in total: "
VerticalOptions="Center" />
<Switch x:Name="includeSwitch"
Toggled="OnSwitchToggled" />
</StackLayout>
<Label x:Name="resultLabel"
FontAttributes="Bold"
HorizontalTextAlignment="Center" />
</StackLayout>
Upvotes: -2