Skip to content

Commit 33ffc12

Browse files
committed
feat(datepicker): Added a new [UnoOnly] UseNativeMinMaxDates property on DatePicker & NativeDatePickerFlyout to allow the picker to be restricted to some date instead of just the year. Properties MinYear and MaxYear are still used for that since they are already of type DateTimeOffset.
1 parent 44a9c04 commit 33ffc12

File tree

8 files changed

+137
-19
lines changed

8 files changed

+137
-19
lines changed

src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/DatePicker/DatePicker_Features.xaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
<ComboBoxItem Tag="2020">min 2020</ComboBoxItem>
4242
<ComboBoxItem Tag="2025">min 2025</ComboBoxItem>
4343
<ComboBoxItem Tag="2030">min 2030</ComboBoxItem>
44+
<ComboBoxItem Tag="lastweek">lastweek</ComboBoxItem>
45+
<ComboBoxItem Tag="today">today</ComboBoxItem>
4446
</ComboBox>
4547
<ComboBox x:Name="maxYear">
4648
<ComboBoxItem Tag="1980">max 1980</ComboBoxItem>
@@ -53,6 +55,8 @@
5355
<ComboBoxItem Tag="2035">max 2035</ComboBoxItem>
5456
<ComboBoxItem Tag="2040">max 2040</ComboBoxItem>
5557
<ComboBoxItem Tag="2045">max 2045</ComboBoxItem>
58+
<ComboBoxItem Tag="today">today</ComboBoxItem>
59+
<ComboBoxItem Tag="nextweek">nextweek</ComboBoxItem>
5660
</ComboBox>
5761
</StackPanel>
5862
<TextBlock FontSize="16">DatePicker</TextBlock>
@@ -126,13 +130,15 @@
126130
</StackPanel>
127131
<TextBlock FontSize="16">NativeDatePickerFlyout &amp; (iOS &amp; Android only)</TextBlock>
128132
<StackPanel Orientation="Horizontal" Spacing="7">
133+
<ToggleButton x:Name="useNativeMinMaxDates">UseNativeMinMaxDates</ToggleButton>
129134
<Button x:Name="btnWithNativeFlyout">
130135
<Button.Flyout>
131136
<android:NativeDatePickerFlyout
132137
x:Name="btnNativeFlyout"
133138
Date="{x:Bind PickedDate, Mode=TwoWay}"
134139
MinYear="{x:Bind DtYear(minYear.SelectedItem), Mode=OneWay}"
135140
MaxYear="{x:Bind DtYear(maxYear.SelectedItem), Mode=OneWay}"
141+
UseNativeMinMaxDates="{Binding IsChecked, ElementName=useNativeMinMaxDates}"
136142
CalendarIdentifier="{Binding SelectedItem.Content, ElementName=calendarIdentifier, FallbackValue=GregorianCalendar}"
137143
DayVisible="{Binding IsChecked, ElementName=dayVisible}"
138144
MonthVisible="{Binding IsChecked, ElementName=monthVisible}"
@@ -142,6 +148,7 @@
142148
Date="{x:Bind PickedDate, Mode=TwoWay}"
143149
MinYear="{x:Bind DtYear(minYear.SelectedItem), Mode=OneWay}"
144150
MaxYear="{x:Bind DtYear(maxYear.SelectedItem), Mode=OneWay}"
151+
UseNativeMinMaxDates="{Binding IsChecked, ElementName=useNativeMinMaxDates}"
145152
CalendarIdentifier="{Binding SelectedItem.Content, ElementName=calendarIdentifier, FallbackValue=GregorianCalendar}"
146153
DayVisible="{Binding IsChecked, ElementName=dayVisible}"
147154
MonthVisible="{Binding IsChecked, ElementName=monthVisible}"
@@ -159,6 +166,7 @@
159166
<StackPanel Orientation="Horizontal" Spacing="7">
160167
<DatePicker
161168
xamarin:UseNativeStyle="True"
169+
xamarin:UseNativeMinMaxDates="{Binding IsChecked, ElementName=useNativeMinMaxDates}"
162170
x:Name="nativeDatePicker"
163171
Date="{x:Bind PickedDate, Mode=TwoWay}"
164172
MinYear="{x:Bind DtYear(minYear.SelectedItem), Mode=OneWay}"

src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/DatePicker/DatePicker_Features.xaml.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,21 @@ public DatePicker_Features()
3030

3131
public DateTimeOffset DtYear(object o)
3232
{
33+
var now = DateTimeOffset.Now;
3334
if (o is SelectorItem item && item.Tag is string tag && !string.IsNullOrEmpty(tag))
3435
{
36+
switch (tag)
37+
{
38+
case "lastweek": return now.AddDays(-7);
39+
case "nextweek": return now.AddDays(7);
40+
case "today": return now;
41+
}
42+
3543
var year = Convert.ToUInt16(tag);
3644
return new DateTime(year, 1, 1, 0, 0, 0);
3745
}
38-
return DateTimeOffset.Now;
46+
47+
return now;
3948
}
4049

4150
public string DtString(object o)

src/Uno.Foundation/UnoOnlyAttribute.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
namespace Uno
66
{
77
/// <summary>
8-
/// This member is only available in Uno and not part of the UWP contract.
8+
/// This member is only available in Uno and not part of the UWP/WinUI contract.
99
/// </summary>
1010
[System.AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = false)]
1111
public sealed class UnoOnlyAttribute : Attribute

src/Uno.UI/UI/Xaml/Controls/DatePicker/DatePicker.Flyout.cs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,44 @@ partial class DatePicker
1212
private const bool DEFAULT_NATIVE_STYLE = false;
1313
#endif
1414

15+
[UnoOnly]
1516
public static DependencyProperty UseNativeStyleProperty { get; } = DependencyProperty.Register(
1617
"UseNativeStyle",
1718
typeof(bool),
1819
typeof(DatePicker),
1920
new FrameworkPropertyMetadata(DEFAULT_NATIVE_STYLE));
2021

2122
/// <summary>
22-
/// If we should use the native picker for the platform.
23+
/// [UnoOnly] If we should use the native picker for the platform.
2324
/// IMPORTANT: must be set before the first time the picker is opened.
2425
/// </summary>
26+
[UnoOnly]
2527
public bool UseNativeStyle
2628
{
2729
get => (bool)GetValue(UseNativeStyleProperty);
2830
set => SetValue(UseNativeStyleProperty, value);
2931
}
3032

33+
[UnoOnly]
34+
public static DependencyProperty UseNativeMinMaxDatesProperty { get; } = DependencyProperty.Register(
35+
"UseNativeMinMaxDates",
36+
typeof(bool),
37+
typeof(DatePicker),
38+
new FrameworkPropertyMetadata(false));
39+
40+
/// <summary>
41+
/// [UnoOnly] When using native pickers (through the UseNativeStyle property),
42+
/// setting this to true will interpret MinYear/MaxYear as MinDate and MaxDate.
43+
/// </summary>
44+
/// <remarks>
45+
/// This property has no effect when not using native pickers.
46+
/// </remarks>
47+
[UnoOnly]
48+
public bool UseNativeMinMaxDates
49+
{
50+
get => (bool)GetValue(UseNativeMinMaxDatesProperty);
51+
set => SetValue(UseNativeMinMaxDatesProperty, value);
52+
}
3153

3254
/// <summary>
3355
/// FlyoutPresenterStyle is an Uno-only property to allow the styling of the DatePicker's FlyoutPresenter.
@@ -39,6 +61,7 @@ public Style FlyoutPresenterStyle
3961
set => this.SetValue(FlyoutPresenterStyleProperty, value);
4062
}
4163

64+
[UnoOnly]
4265
public static DependencyProperty FlyoutPresenterStyleProperty { get; } =
4366
DependencyProperty.Register(
4467
nameof(FlyoutPresenterStyle),

src/Uno.UI/UI/Xaml/Controls/DatePicker/DatePicker.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -858,6 +858,12 @@ void OnFlyoutButtonClick(
858858
_flyout.MaxYear = MaxYear;
859859
_flyout.Date = SelectedDate ?? Date;
860860

861+
// UnoOnly
862+
if (_flyout is NativeDatePickerFlyout nativeFlyout)
863+
{
864+
nativeFlyout.UseNativeMinMaxDates = UseNativeMinMaxDates;
865+
}
866+
861867
ShowPickerFlyout();
862868
}
863869

src/Uno.UI/UI/Xaml/Controls/DatePicker/DatePickerSelector.iOS.cs

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,30 @@ namespace Windows.UI.Xaml.Controls
1414
{
1515
public partial class DatePickerSelector
1616
{
17+
public static DependencyProperty UseNativeMinMaxDatesProperty { get; } = DependencyProperty.Register(
18+
"UseNativeMinMaxDates",
19+
typeof(bool),
20+
typeof(DatePickerSelector),
21+
new FrameworkPropertyMetadata(false, propertyChangedCallback: OnUseNativeMinMaxDatesChanged));
22+
23+
/// <summary>
24+
/// Setting this to true will interpret MinYear/MaxYear as MinDate and MaxDate.
25+
/// </summary>
26+
public bool UseNativeMinMaxDates
27+
{
28+
get => (bool)GetValue(UseNativeMinMaxDatesProperty);
29+
set => SetValue(UseNativeMinMaxDatesProperty, value);
30+
}
31+
32+
private static void OnUseNativeMinMaxDatesChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
33+
{
34+
if (o is DatePickerSelector selector)
35+
{
36+
selector.UpdateMinMaxYears();
37+
}
38+
}
39+
40+
1741
private UIDatePicker _picker;
1842
private NSDate _initialValue;
1943
private NSDate _newValue;
@@ -107,8 +131,11 @@ private void UpdateMinMaxYears()
107131
var calendar = new NSCalendar(NSCalendarType.Gregorian);
108132

109133
winCalendar.SetDateTime(MaxYear);
110-
winCalendar.Month = winCalendar.LastMonthInThisYear;
111-
winCalendar.Day = winCalendar.LastDayInThisMonth;
134+
if (!UseNativeMinMaxDates)
135+
{
136+
winCalendar.Month = winCalendar.LastMonthInThisYear;
137+
winCalendar.Day = winCalendar.LastDayInThisMonth;
138+
}
112139

113140
var maximumDateComponents = new NSDateComponents
114141
{
@@ -120,8 +147,11 @@ private void UpdateMinMaxYears()
120147
_picker.MaximumDate = calendar.DateFromComponents(maximumDateComponents);
121148

122149
winCalendar.SetDateTime(MinYear);
123-
winCalendar.Month = winCalendar.FirstMonthInThisYear;
124-
winCalendar.Day = winCalendar.FirstDayInThisMonth;
150+
if (!UseNativeMinMaxDates)
151+
{
152+
winCalendar.Month = winCalendar.FirstMonthInThisYear;
153+
winCalendar.Day = winCalendar.FirstDayInThisMonth;
154+
}
125155

126156
var minimumDateComponents = new NSDateComponents
127157
{

src/Uno.UI/UI/Xaml/Controls/DatePicker/NativeDatePickerFlyout.Android.cs

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,21 @@ public partial class NativeDatePickerFlyout : DatePickerFlyout
1414
{
1515
private DatePickerDialog _dialog;
1616

17+
public static DependencyProperty UseNativeMinMaxDatesProperty { get; } = DependencyProperty.Register(
18+
"UseNativeMinMaxDates",
19+
typeof(bool),
20+
typeof(NativeDatePickerFlyout),
21+
new FrameworkPropertyMetadata(false));
22+
23+
/// <summary>
24+
/// Setting this to true will interpret MinYear/MaxYear as MinDate and MaxDate.
25+
/// </summary>
26+
public bool UseNativeMinMaxDates
27+
{
28+
get => (bool)GetValue(UseNativeMinMaxDatesProperty);
29+
set => SetValue(UseNativeMinMaxDatesProperty, value);
30+
}
31+
1732
public NativeDatePickerFlyout()
1833
{
1934
this.RegisterPropertyChangedCallback(DateProperty, OnDateChanged);
@@ -49,13 +64,21 @@ protected internal override void Open()
4964
//Removes title that is unnecessary as it is a duplicate -> http://stackoverflow.com/questions/33486643/remove-title-from-datepickerdialog
5065
_dialog.SetTitle("");
5166

52-
var minYearCalendar = Calendar.Instance;
53-
minYearCalendar.Set(MinYear.Year, MinYear.Month - 1, MinYear.Day, MinYear.Hour, MinYear.Minute, MinYear.Second);
54-
_dialog.DatePicker.MinDate = minYearCalendar.TimeInMillis;
67+
if (UseNativeMinMaxDates)
68+
{
69+
_dialog.DatePicker.MinDate = MinYear.ToUnixTimeMilliseconds();
70+
_dialog.DatePicker.MaxDate = MaxYear.ToUnixTimeMilliseconds();
71+
}
72+
else
73+
{
74+
var minYearCalendar = Calendar.Instance;
75+
minYearCalendar.Set(MinYear.Year, MinYear.Month - 1, MinYear.Day, MinYear.Hour, MinYear.Minute, MinYear.Second);
76+
_dialog.DatePicker.MinDate = minYearCalendar.TimeInMillis;
5577

56-
var maxYearCalendar = Calendar.Instance;
57-
maxYearCalendar.Set(MaxYear.Year, MaxYear.Month - 1, MaxYear.Day, MaxYear.Hour, MaxYear.Minute, MaxYear.Second);
58-
_dialog.DatePicker.MaxDate = maxYearCalendar.TimeInMillis;
78+
var maxYearCalendar = Calendar.Instance;
79+
maxYearCalendar.Set(MaxYear.Year, MaxYear.Month - 1, MaxYear.Day, MaxYear.Hour, MaxYear.Minute, MaxYear.Second);
80+
_dialog.DatePicker.MaxDate = maxYearCalendar.TimeInMillis;
81+
}
5982

6083
_dialog.DismissEvent += OnDismiss;
6184
_dialog.Show();

src/Uno.UI/UI/Xaml/Controls/DatePicker/NativeDatePickerFlyout.iOS.cs

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,28 @@ private NativeDatePickerFlyoutPresenter _presenter
3636
}
3737
private DatePickerSelector _selector;
3838

39+
public static DependencyProperty UseNativeMinMaxDatesProperty { get; } = DependencyProperty.Register(
40+
"UseNativeMinMaxDates",
41+
typeof(bool),
42+
typeof(NativeDatePickerFlyout),
43+
new FrameworkPropertyMetadata(false, propertyChangedCallback: OnUseNativeMinMaxDatesChanged));
44+
45+
/// <summary>
46+
/// Setting this to true will interpret MinYear/MaxYear as MinDate and MaxDate.
47+
/// </summary>
48+
public bool UseNativeMinMaxDates
49+
{
50+
get => (bool)GetValue(UseNativeMinMaxDatesProperty);
51+
set => SetValue(UseNativeMinMaxDatesProperty, value);
52+
}
53+
54+
private static void OnUseNativeMinMaxDatesChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
55+
{
56+
if (o is NativeDatePickerFlyout selector)
57+
{
58+
}
59+
}
60+
3961
public NativeDatePickerFlyout()
4062
{
4163
Opening += DatePickerFlyout_Opening;
@@ -72,12 +94,9 @@ private void InitializeContent()
7294

7395
_isInitialized = true;
7496

75-
Content = _selector = new DatePickerSelector()
76-
{
77-
MinYear = MinYear,
78-
MaxYear = MaxYear
79-
};
97+
Content = _selector = new DatePickerSelector();
8098

99+
BindToContent("UseNativeMinMaxDates");
81100
BindToContent("MinYear");
82101
BindToContent("MaxYear");
83102
}
@@ -237,7 +256,7 @@ private IDisposable AttachFlyoutCommand(string targetButtonName, Action<NativeDa
237256

238257
private void BindToContent(string propertyName)
239258
{
240-
this.Binding(propertyName, propertyName, Content, BindingMode.TwoWay);
259+
Content.Binding(propertyName, propertyName, this, BindingMode.OneWay);
241260
}
242261
}
243262
}

0 commit comments

Comments
 (0)