Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
CompositeDatePicker.cs
1using System;
2using System.ComponentModel;
3using System.Globalization;
4using Microsoft.Maui.Controls;
5using Microsoft.Maui.Graphics;
8using Waher.Events;
10
12{
17 {
18 private static readonly DateTime SafeMinDate = new DateTime(1900, 1, 1);
19 private static readonly DateTime SafeMaxDate = new DateTime(2100, 12, 31);
20
24 public static readonly BindableProperty FontProperty = BindableProperty.Create(
25 propertyName: nameof(Font),
26 returnType: typeof(Microsoft.Maui.Font),
27 declaringType: typeof(CompositeDatePicker),
28 defaultValue: new Microsoft.Maui.Font());
29
33 public Microsoft.Maui.Font Font
34 {
35 get => (Microsoft.Maui.Font)this.GetValue(FontProperty);
36 set => this.SetValue(FontProperty, value);
37 }
38
42 public static readonly BindableProperty XAlignProperty = BindableProperty.Create(
43 propertyName: nameof(XAlign),
44 returnType: typeof(TextAlignment),
45 declaringType: typeof(CompositeDatePicker),
46 defaultValue: TextAlignment.Start);
47
51 public TextAlignment XAlign
52 {
53 get => (TextAlignment)this.GetValue(XAlignProperty);
54 set => this.SetValue(XAlignProperty, value);
55 }
56
60 public static readonly BindableProperty HasBorderProperty = BindableProperty.Create(
61 propertyName: nameof(HasBorder),
62 returnType: typeof(bool),
63 declaringType: typeof(CompositeDatePicker),
64 defaultValue: true);
65
69 public bool HasBorder
70 {
71 get => (bool)this.GetValue(HasBorderProperty);
72 set => this.SetValue(HasBorderProperty, value);
73 }
74
78 public static readonly BindableProperty PlaceholderProperty = BindableProperty.Create(
79 propertyName: nameof(Placeholder),
80 returnType: typeof(string),
81 declaringType: typeof(CompositeDatePicker),
82 defaultValue: string.Empty,
83 defaultBindingMode: BindingMode.OneWay);
84
88 public string Placeholder
89 {
90 get => (string)this.GetValue(PlaceholderProperty);
91 set => this.SetValue(PlaceholderProperty, value);
92 }
93
97 public static readonly BindableProperty PlaceholderTextColorProperty = BindableProperty.Create(
98 propertyName: nameof(PlaceholderTextColor),
99 returnType: typeof(Color),
100 declaringType: typeof(CompositeDatePicker),
101 defaultValue: Colors.Transparent);
102
107 {
108 get => (Color)this.GetValue(PlaceholderTextColorProperty);
109 set => this.SetValue(PlaceholderTextColorProperty, value);
110 }
111
115 public static readonly BindableProperty TextColorProperty = BindableProperty.Create(
116 propertyName: nameof(TextColor),
117 returnType: typeof(Color),
118 declaringType: typeof(CompositeDatePicker),
119 defaultValue: Colors.Black);
120
124 public Color TextColor
125 {
126 get => (Color)this.GetValue(TextColorProperty);
127 set => this.SetValue(TextColorProperty, value);
128 }
129
133 public static readonly BindableProperty PickerStyleProperty = BindableProperty.Create(
134 propertyName: nameof(PickerStyle),
135 returnType: typeof(Style),
136 declaringType: typeof(CompositeDatePicker),
137 defaultValue: null);
138
142 public Style PickerStyle
143 {
144 get => (Style)this.GetValue(PickerStyleProperty);
145 set => this.SetValue(PickerStyleProperty, value);
146 }
147
151 public static readonly BindableProperty NullableDateProperty = BindableProperty.Create(
152 propertyName: nameof(NullableDate),
153 returnType: typeof(DateTime?),
154 declaringType: typeof(CompositeDatePicker),
155 defaultValue: null,
156 defaultBindingMode: BindingMode.TwoWay);
157
161 public DateTime? NullableDate
162 {
163 get => (DateTime?)this.GetValue(NullableDateProperty);
164 set => this.SetValue(NullableDateProperty, value);
165 }
166
170 public static readonly BindableProperty MinimumDateProperty = BindableProperty.Create(
171 propertyName: nameof(MinimumDate),
172 returnType: typeof(DateTime),
173 declaringType: typeof(CompositeDatePicker),
174 defaultValue: SafeMinDate);
175
179 public DateTime MinimumDate
180 {
181 get => (DateTime)this.GetValue(MinimumDateProperty);
182 set => this.SetValue(MinimumDateProperty, value.SanitizeForDatePicker(SafeMinDate, SafeMaxDate));
183 }
184
188 public static readonly BindableProperty MaximumDateProperty = BindableProperty.Create(
189 propertyName: nameof(MaximumDate),
190 returnType: typeof(DateTime),
191 declaringType: typeof(CompositeDatePicker),
192 defaultValue: SafeMaxDate);
193
197 public DateTime MaximumDate
198 {
199 get => (DateTime)this.GetValue(MaximumDateProperty);
200 set => this.SetValue(MaximumDateProperty, value.SanitizeForDatePicker(SafeMinDate, SafeMaxDate));
201 }
202
206 public event EventHandler<NullableDateChangedEventArgs>? NullableDateSelected;
207
208 private readonly WrappedDatePicker picker;
209
214 {
215 this.picker = new WrappedDatePicker();
216 this.SetDefaultDate();
217
218 // Ensure bounds are applied on internal picker immediately.
219 this.picker.MinimumDate = SafeMinDate;
220 this.picker.MaximumDate = SafeMaxDate;
221
222 // Bind internal properties to this control
223 this.picker.SetBinding(DatePicker.DateProperty,
224 new Binding(nameof(this.NullableDate), source: this, mode: BindingMode.TwoWay));
225 this.picker.SetBinding(DatePicker.MinimumDateProperty,
226 new Binding(nameof(this.MinimumDate), source: this));
227 this.picker.SetBinding(DatePicker.MaximumDateProperty,
228 new Binding(nameof(this.MaximumDate), source: this));
229 this.picker.SetBinding(DatePicker.TextColorProperty,
230 new Binding(nameof(this.TextColor), source: this));
231 this.picker.SetBinding(DatePicker.StyleProperty,
232 new Binding(nameof(this.PickerStyle), source: this));
233
234 // Apply initial format (placeholder or date)
235 this.UpdateFormat();
236
237 // Handle user changes and property updates
238 this.picker.DateSelected += this.OnPickerDateSelected;
239 if (this.picker is VisualElement E)
240 E.Focused += this.OnPickerUnfocused;
241 this.PropertyChanged += this.OnControlPropertyChanged;
242
243 this.CenterView = this.picker;
244 }
245
249 private void OnControlPropertyChanged(object? Sender, PropertyChangedEventArgs E)
250 {
251 if (E.PropertyName == nameof(this.Placeholder) || E.PropertyName == nameof(this.NullableDate))
252 this.UpdateFormat();
253
254 if (E.PropertyName == nameof(this.NullableDate) && this.NullableDate.HasValue)
255 {
256 DateTime Clamped = this.NullableDate.Value.SanitizeForDatePicker(this.MinimumDate, this.MaximumDate);
257 if (Clamped != this.NullableDate.Value)
258 this.NullableDate = Clamped;
259 }
260 }
261
266 private void OnPickerDateSelected(object? Sender, DateChangedEventArgs E)
267 {
268 DateTime? OldDate = this.NullableDate;
269 DateTime? NewDate = E.NewDate;
270
271 if (NewDate.HasValue)
272 {
273 DateTime Clamped = NewDate.Value.SanitizeForDatePicker(this.MinimumDate, this.MaximumDate);
274 this.NullableDate = Clamped;
275 }
276 else
277 {
278 this.NullableDate = null;
279 }
280
281 NullableDateSelected?.Invoke(this, new NullableDateChangedEventArgs(OldDate, this.NullableDate));
282 }
283
284 private void OnPickerUnfocused(object? sender, FocusEventArgs e)
285 {
286 if (!this.NullableDate.HasValue)
287 {
288 DateTime? PickerDate = this.picker.Date;
289
290 if (PickerDate.HasValue)
291 {
292 DateTime Picked = PickerDate.Value.SanitizeForDatePicker(this.MinimumDate, this.MaximumDate);
293 this.NullableDate = Picked;
294 NullableDateSelected?.Invoke(this, new NullableDateChangedEventArgs(null, Picked));
295 }
296 }
297 }
298
302 private void UpdateFormat()
303 {
304 if (this.NullableDate.HasValue)
305 {
306 // Use the current culture's short date pattern once a date is chosen.
307 this.picker.Format = CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern;
308 }
309 else
310 {
311 // Escape any single-quotes in the placeholder,
312 // then wrap the whole thing in single-quotes.
313 string escaped = this.Placeholder.Replace("'", "''");
314 this.picker.Format = $"'{escaped}'";
315 }
316 }
317
321 private void SetDefaultDate()
322 {
323 DateTime Today = DateTime.Today.SanitizeForDatePicker(SafeMinDate, SafeMaxDate);
324 this.picker.Date = Today;
325 }
326 }
327}
Extended DatePicker for nullable values with text placeholder.
static readonly BindableProperty TextColorProperty
The TextColor property.
DateTime MaximumDate
Gets or sets the maximum allowable date.
Color TextColor
Gets or sets the color of the selected date text.
static readonly BindableProperty MaximumDateProperty
The MaximumDate property.
Color PlaceholderTextColor
Gets or sets the color of the placeholder text.
static readonly BindableProperty PlaceholderTextColorProperty
The PlaceholderTextColor property.
TextAlignment XAlign
Gets or sets the horizontal alignment of the text.
static readonly BindableProperty PlaceholderProperty
The Placeholder property.
static readonly BindableProperty PickerStyleProperty
The PickerStyle property.
bool HasBorder
Gets or sets whether the border should be shown.
CompositeDatePicker()
Initializes a new instance of the CompositeDatePicker class.
static readonly BindableProperty HasBorderProperty
The HasBorder property.
static readonly BindableProperty MinimumDateProperty
The MinimumDate property.
static readonly BindableProperty NullableDateProperty
The NullableDate property.
static readonly BindableProperty FontProperty
The Font property.
static readonly BindableProperty XAlignProperty
The XAlign property.
Style PickerStyle
Gets or sets the style applied to the internal DatePicker.
EventHandler< NullableDateChangedEventArgs >? NullableDateSelected
Occurs when the nullable date is changed by user action.
DateTime MinimumDate
Gets or sets the minimum allowable date.
Microsoft.Maui.Font Font
Gets or sets the font.
DateTime? NullableDate
Gets or sets the selected date, or null if none.
string Placeholder
Gets or sets the placeholder text to display when no date is selected.
DatePicker wrapper preventing redundant reentrant Date updates and guarding against invalid extreme d...