mirror of
https://github.com/AtomUI/AtomUI.git
synced 2026-10-28 14:20:47 +08:00
Add DualMonthRangeDatePickerPresenter Control
Add DualMonthRangeDatePickerPresenter Control
This commit is contained in:
@@ -26,6 +26,12 @@
|
||||
Description="Date selection panel with time selection.">
|
||||
<calendarView:DualMonthRangeCalendar IsSelectRangeStart="True" SecondarySelectedDate="2024-10-1"/>
|
||||
</desktop:ShowCaseItem>
|
||||
|
||||
<desktop:ShowCaseItem
|
||||
Title="With Time Picker"
|
||||
Description="Date selection panel with time selection.">
|
||||
<atom:RangeDatePicker IsShowTime="true"/>
|
||||
</desktop:ShowCaseItem>
|
||||
<!-- -->
|
||||
<!-- <desktop:ShowCaseItem -->
|
||||
<!-- Title="Need Confirm" -->
|
||||
|
||||
@@ -13,10 +13,10 @@ namespace AtomUI.Controls.CalendarView;
|
||||
|
||||
public class DateSelectedEventArgs : EventArgs
|
||||
{
|
||||
public DateTime? Value { get; }
|
||||
public DateTime? Date { get; }
|
||||
public DateSelectedEventArgs(DateTime? value)
|
||||
{
|
||||
Value = value;
|
||||
Date = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ using Avalonia.Input;
|
||||
using Avalonia.Input.Raw;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Threading;
|
||||
|
||||
namespace AtomUI.Controls.CalendarView;
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ public class DatePicker : InfoPickerInput
|
||||
AvaloniaProperty.Register<DatePicker, string?>(nameof(Format));
|
||||
|
||||
public static readonly StyledProperty<bool> IsShowTimeProperty =
|
||||
AvaloniaProperty.Register<DatePicker, bool>(nameof(IsShowTime));
|
||||
AvaloniaProperty.Register<DatePicker, bool>(nameof(IsShowTime), false);
|
||||
|
||||
public static readonly StyledProperty<bool> IsNeedConfirmProperty =
|
||||
AvaloniaProperty.Register<DatePicker, bool>(nameof(IsNeedConfirm));
|
||||
@@ -124,7 +124,7 @@ public class DatePicker : InfoPickerInput
|
||||
return format;
|
||||
}
|
||||
|
||||
public string FormatDateTime(DateTime? dateTime)
|
||||
protected string FormatDateTime(DateTime? dateTime)
|
||||
{
|
||||
if (dateTime is null)
|
||||
{
|
||||
@@ -208,9 +208,9 @@ public class DatePicker : InfoPickerInput
|
||||
|
||||
private void HandleHoverDateTimeChanged(object? sender, DateSelectedEventArgs args)
|
||||
{
|
||||
if (args.Value.HasValue)
|
||||
if (args.Date.HasValue)
|
||||
{
|
||||
Text = FormatDateTime(args.Value);
|
||||
Text = FormatDateTime(args.Date);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -226,9 +226,7 @@ public class DatePicker : InfoPickerInput
|
||||
|
||||
private void ClearHoverSelectedInfo()
|
||||
{
|
||||
DateTime? targetValue = default;
|
||||
targetValue = SelectedDateTime;
|
||||
Text = FormatDateTime(targetValue);
|
||||
Text = FormatDateTime(SelectedDateTime);
|
||||
}
|
||||
|
||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||
|
||||
@@ -267,7 +267,7 @@ internal class DatePickerPresenter : PickerPresenterBase
|
||||
{
|
||||
// 需要组合日期和时间
|
||||
// 暂时没实现
|
||||
var hoverDateTime = CollectDateTime(args.Value, TempSelectedTime);
|
||||
var hoverDateTime = CollectDateTime(args.Date, TempSelectedTime);
|
||||
HoverDateTimeChanged?.Invoke(this, new DateSelectedEventArgs(hoverDateTime));
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ using AtomUI.Theme.Data;
|
||||
using AtomUI.Theme.Styling;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Templates;
|
||||
using Avalonia.Data;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Styling;
|
||||
using PickerCalendar = AtomUI.Controls.CalendarView.Calendar;
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace AtomUI.Controls;
|
||||
|
||||
internal class DualMonthRangeDatePickerPresenter : RangeDatePickerPresenter
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using AtomUI.Theme.Styling;
|
||||
|
||||
namespace AtomUI.Controls;
|
||||
|
||||
[ControlThemeProvider]
|
||||
internal class DualMonthRangeDatePickerPresenterTheme : DatePickerPresenterTheme
|
||||
{
|
||||
public DualMonthRangeDatePickerPresenterTheme() : this(typeof(DualMonthRangeDatePickerPresenter))
|
||||
{
|
||||
}
|
||||
|
||||
public DualMonthRangeDatePickerPresenterTheme(Type targetType) : base(targetType)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,415 @@
|
||||
using System.Globalization;
|
||||
using AtomUI.Controls.CalendarView;
|
||||
using AtomUI.Controls.Internal;
|
||||
using AtomUI.Controls.TimePickerLang;
|
||||
using AtomUI.Data;
|
||||
using AtomUI.Theme.Data;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Data;
|
||||
|
||||
namespace AtomUI.Controls;
|
||||
|
||||
public class RangeDatePicker : RangeInfoPickerInput
|
||||
{
|
||||
#region 公共属性定义
|
||||
|
||||
public static readonly StyledProperty<DateTime?> RangeStartSelectedDateProperty =
|
||||
AvaloniaProperty.Register<RangeDatePicker, DateTime?>(nameof(RangeStartSelectedDate),
|
||||
defaultBindingMode: BindingMode.TwoWay,
|
||||
enableDataValidation: true);
|
||||
|
||||
public static readonly StyledProperty<DateTime?> RangeEndSelectedDateProperty =
|
||||
AvaloniaProperty.Register<RangeDatePicker, DateTime?>(nameof(RangeEndSelectedDate),
|
||||
defaultBindingMode: BindingMode.TwoWay,
|
||||
enableDataValidation: true);
|
||||
|
||||
public static readonly StyledProperty<DateTime?> RangeStartDefaultDateProperty =
|
||||
AvaloniaProperty.Register<RangeDatePicker, DateTime?>(nameof(RangeStartDefaultDate),
|
||||
enableDataValidation: true);
|
||||
|
||||
public static readonly StyledProperty<DateTime?> RangeEndDefaultDateProperty =
|
||||
AvaloniaProperty.Register<RangeDatePicker, DateTime?>(nameof(RangeEndDefaultDate),
|
||||
enableDataValidation: true);
|
||||
|
||||
public static readonly StyledProperty<bool> IsNeedConfirmProperty =
|
||||
AvaloniaProperty.Register<RangeDatePicker, bool>(nameof(IsNeedConfirm));
|
||||
|
||||
public static readonly StyledProperty<bool> IsShowNowProperty =
|
||||
DatePicker.IsShowNowProperty.AddOwner<RangeDatePicker>();
|
||||
|
||||
public static readonly StyledProperty<bool> IsShowTimeProperty =
|
||||
DatePicker.IsShowTimeProperty.AddOwner<RangeDatePicker>();
|
||||
|
||||
public static readonly StyledProperty<ClockIdentifierType> ClockIdentifierProperty =
|
||||
DatePicker.ClockIdentifierProperty.AddOwner<RangeDatePicker>();
|
||||
|
||||
public static readonly StyledProperty<string?> FormatProperty =
|
||||
DatePicker.FormatProperty.AddOwner<RangeDatePicker>();
|
||||
|
||||
public DateTime? RangeStartSelectedDate
|
||||
{
|
||||
get => GetValue(RangeStartSelectedDateProperty);
|
||||
set => SetValue(RangeStartSelectedDateProperty, value);
|
||||
}
|
||||
|
||||
public DateTime? RangeEndSelectedDate
|
||||
{
|
||||
get => GetValue(RangeEndSelectedDateProperty);
|
||||
set => SetValue(RangeEndSelectedDateProperty, value);
|
||||
}
|
||||
|
||||
public DateTime? RangeStartDefaultDate
|
||||
{
|
||||
get => GetValue(RangeStartDefaultDateProperty);
|
||||
set => SetValue(RangeStartDefaultDateProperty, value);
|
||||
}
|
||||
|
||||
public DateTime? RangeEndDefaultDate
|
||||
{
|
||||
get => GetValue(RangeEndDefaultDateProperty);
|
||||
set => SetValue(RangeEndDefaultDateProperty, value);
|
||||
}
|
||||
|
||||
public bool IsNeedConfirm
|
||||
{
|
||||
get => GetValue(IsNeedConfirmProperty);
|
||||
set => SetValue(IsNeedConfirmProperty, value);
|
||||
}
|
||||
|
||||
public bool IsShowNow
|
||||
{
|
||||
get => GetValue(IsShowNowProperty);
|
||||
set => SetValue(IsShowNowProperty, value);
|
||||
}
|
||||
|
||||
public bool IsShowTime
|
||||
{
|
||||
get => GetValue(IsShowTimeProperty);
|
||||
set => SetValue(IsShowTimeProperty, value);
|
||||
}
|
||||
|
||||
public ClockIdentifierType ClockIdentifier
|
||||
{
|
||||
get => GetValue(ClockIdentifierProperty);
|
||||
set => SetValue(ClockIdentifierProperty, value);
|
||||
}
|
||||
|
||||
public string? Format
|
||||
{
|
||||
get => GetValue(FormatProperty);
|
||||
set => SetValue(FormatProperty, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private RangeDatePickerPresenter? _pickerPresenter;
|
||||
|
||||
protected override Flyout CreatePickerFlyout()
|
||||
{
|
||||
return new RangeDatePickerFlyout();
|
||||
}
|
||||
|
||||
public override void Clear()
|
||||
{
|
||||
base.Clear();
|
||||
|
||||
RangeStartSelectedDate = null;
|
||||
RangeEndSelectedDate = null;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
RangeStartSelectedDate = RangeStartDefaultDate;
|
||||
RangeEndSelectedDate = RangeEndDefaultDate;
|
||||
}
|
||||
|
||||
protected override void NotifyFlyoutPresenterCreated(Control flyoutPresenter)
|
||||
{
|
||||
if (flyoutPresenter is RangeDatePickerFlyoutPresenter rangeDatePickerFlyoutPresenter)
|
||||
{
|
||||
BindUtils.RelayBind(this, IsShowTimeProperty, rangeDatePickerFlyoutPresenter, RangeDatePickerFlyoutPresenter.IsShowTimeProperty);
|
||||
rangeDatePickerFlyoutPresenter.AttachedToVisualTree += (sender, args) =>
|
||||
{
|
||||
_pickerPresenter = rangeDatePickerFlyoutPresenter.DatePickerPresenter;
|
||||
ConfigurePickerPresenter(_pickerPresenter);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private void ConfigurePickerPresenter(RangeDatePickerPresenter? presenter)
|
||||
{
|
||||
if (presenter is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BindUtils.RelayBind(this, RangeStartSelectedDateProperty, presenter, RangeDatePickerPresenter.SelectedDateTimeProperty);
|
||||
BindUtils.RelayBind(this, RangeEndSelectedDateProperty, presenter, RangeDatePickerPresenter.SecondarySelectedDateTimeProperty);
|
||||
BindUtils.RelayBind(this, ClockIdentifierProperty, presenter, RangeDatePickerPresenter.ClockIdentifierProperty);
|
||||
BindUtils.RelayBind(this, IsNeedConfirmProperty, presenter, RangeDatePickerPresenter.IsNeedConfirmProperty);
|
||||
BindUtils.RelayBind(this, IsShowNowProperty, presenter, RangeDatePickerPresenter.IsShowNowProperty);
|
||||
}
|
||||
|
||||
protected override void NotifyFlyoutOpened()
|
||||
{
|
||||
base.NotifyFlyoutOpened();
|
||||
if (_pickerPresenter is not null)
|
||||
{
|
||||
_pickerPresenter.ChoosingStatueChanged += HandleChoosingStatueChanged;
|
||||
_pickerPresenter.HoverDateTimeChanged += HandleHoverDateTimeChanged;
|
||||
_pickerPresenter.Confirmed += HandleConfirmed;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void NotifyFlyoutAboutToClose(bool selectedIsValid)
|
||||
{
|
||||
base.NotifyFlyoutAboutToClose(selectedIsValid);
|
||||
if (_pickerPresenter is not null)
|
||||
{
|
||||
_pickerPresenter.ChoosingStatueChanged -= HandleChoosingStatueChanged;
|
||||
_pickerPresenter.HoverDateTimeChanged -= HandleHoverDateTimeChanged;
|
||||
_pickerPresenter.Confirmed -= HandleConfirmed;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleChoosingStatueChanged(object? sender, ChoosingStatusEventArgs args)
|
||||
{
|
||||
_isChoosing = args.IsChoosing;
|
||||
UpdatePseudoClasses();
|
||||
if (!args.IsChoosing)
|
||||
{
|
||||
ClearHoverSelectedInfo();
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearHoverSelectedInfo()
|
||||
{
|
||||
if (RangeActivatedPart == RangeActivatedPart.Start)
|
||||
{
|
||||
Text = FormatDateTime(RangeStartSelectedDate);
|
||||
}
|
||||
else if (RangeActivatedPart == RangeActivatedPart.End)
|
||||
{
|
||||
SecondaryText = FormatDateTime(RangeEndSelectedDate);
|
||||
}
|
||||
}
|
||||
|
||||
private string GetEffectiveFormat()
|
||||
{
|
||||
if (Format is not null)
|
||||
{
|
||||
return Format;
|
||||
}
|
||||
|
||||
var format = "yyyy-MM-dd";
|
||||
if (IsShowTime)
|
||||
{
|
||||
|
||||
if (ClockIdentifier == ClockIdentifierType.HourClock12)
|
||||
{
|
||||
format = $"{format} hh:mm:ss tt";
|
||||
}
|
||||
else
|
||||
{
|
||||
format = $"{format} HH:mm:ss";
|
||||
}
|
||||
}
|
||||
|
||||
return format;
|
||||
}
|
||||
|
||||
protected string FormatDateTime(DateTime? dateTime)
|
||||
{
|
||||
if (dateTime is null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var format = GetEffectiveFormat();
|
||||
if (ClockIdentifier == ClockIdentifierType.HourClock12)
|
||||
{
|
||||
var formatInfo = new DateTimeFormatInfo();
|
||||
formatInfo.AMDesignator = LanguageResourceBinder.GetLangResource(TimePickerLangResourceKey.AMText)!;
|
||||
formatInfo.PMDesignator = LanguageResourceBinder.GetLangResource(TimePickerLangResourceKey.PMText)!;
|
||||
return dateTime.Value.ToString(format, formatInfo);
|
||||
}
|
||||
|
||||
return dateTime.Value.ToString(format);
|
||||
}
|
||||
|
||||
private void HandleHoverDateTimeChanged(object? sender, DateSelectedEventArgs args)
|
||||
{
|
||||
if (args.Date.HasValue)
|
||||
{
|
||||
if (RangeActivatedPart == RangeActivatedPart.Start)
|
||||
{
|
||||
Text = FormatDateTime(args.Date);
|
||||
}
|
||||
else if (RangeActivatedPart == RangeActivatedPart.End)
|
||||
{
|
||||
SecondaryText = FormatDateTime(RangeEndDefaultDate);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Text = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleConfirmed(object? sender, EventArgs args)
|
||||
{
|
||||
if (RangeActivatedPart == RangeActivatedPart.Start)
|
||||
{
|
||||
RangeStartSelectedDate = _pickerPresenter?.SelectedDateTime;
|
||||
if (RangeEndSelectedDate is null)
|
||||
{
|
||||
RangeActivatedPart = RangeActivatedPart.End;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (RangeActivatedPart == RangeActivatedPart.End)
|
||||
{
|
||||
RangeEndSelectedDate = _pickerPresenter?.SelectedDateTime;
|
||||
if (RangeStartSelectedDate is null)
|
||||
{
|
||||
RangeActivatedPart = RangeActivatedPart.Start;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ClosePickerFlyout();
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
|
||||
{
|
||||
base.OnPropertyChanged(change);
|
||||
if (change.Property == RangeActivatedPartProperty)
|
||||
{
|
||||
HandleRangeActivatedPartChanged();
|
||||
}
|
||||
|
||||
if (VisualRoot is not null)
|
||||
{
|
||||
if (change.Property == RangeStartSelectedDateProperty)
|
||||
{
|
||||
if (RangeStartSelectedDate.HasValue)
|
||||
{
|
||||
Text = FormatDateTime(RangeStartSelectedDate.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
ResetRangeStartDateValue();
|
||||
}
|
||||
}
|
||||
else if (change.Property == RangeEndSelectedDateProperty)
|
||||
{
|
||||
if (RangeEndSelectedDate.HasValue)
|
||||
{
|
||||
SecondaryText = FormatDateTime(RangeEndSelectedDate.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
ResetRangeEndDateValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void ResetRangeStartDateValue()
|
||||
{
|
||||
if (_infoInputBox is not null)
|
||||
{
|
||||
if (RangeStartDefaultDate is not null)
|
||||
{
|
||||
_infoInputBox.Text = FormatDateTime(RangeStartDefaultDate.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
_infoInputBox.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void ResetRangeEndDateValue()
|
||||
{
|
||||
if (_secondaryInfoInputBox is not null)
|
||||
{
|
||||
if (RangeEndDefaultDate is not null)
|
||||
{
|
||||
_secondaryInfoInputBox.Text = FormatDateTime(RangeEndDefaultDate.Value);;
|
||||
}
|
||||
else
|
||||
{
|
||||
_secondaryInfoInputBox.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void HandleRangeActivatedPartChanged()
|
||||
{
|
||||
SetupPickerIndicatorPosition();
|
||||
if (RangeActivatedPart == RangeActivatedPart.Start)
|
||||
{
|
||||
_infoInputBox!.Focus();
|
||||
if (RangeEndSelectedDate is null)
|
||||
{
|
||||
ResetRangeStartDateValue();
|
||||
}
|
||||
if (_pickerPresenter is not null)
|
||||
{
|
||||
_pickerPresenter.SelectedDateTime = RangeStartSelectedDate;
|
||||
}
|
||||
|
||||
}
|
||||
else if (RangeActivatedPart == RangeActivatedPart.End)
|
||||
{
|
||||
_secondaryInfoInputBox!.Focus();
|
||||
if (RangeStartSelectedDate is null)
|
||||
{
|
||||
ResetRangeEndDateValue();
|
||||
}
|
||||
if (_pickerPresenter is not null)
|
||||
{
|
||||
_pickerPresenter.SelectedDateTime = RangeEndSelectedDate;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (RangeStartSelectedDate is null)
|
||||
{
|
||||
ResetRangeStartDateValue();
|
||||
}
|
||||
|
||||
if (RangeEndSelectedDate is null)
|
||||
{
|
||||
ResetRangeEndDateValue();
|
||||
}
|
||||
if (_pickerPresenter is not null)
|
||||
{
|
||||
_pickerPresenter.SelectedDateTime = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||
{
|
||||
base.OnApplyTemplate(e);
|
||||
if (RangeStartDefaultDate is not null && RangeStartSelectedDate is null)
|
||||
{
|
||||
RangeStartSelectedDate = RangeStartDefaultDate;
|
||||
}
|
||||
|
||||
if (RangeEndDefaultDate is not null && RangeEndSelectedDate is null)
|
||||
{
|
||||
RangeEndSelectedDate = RangeEndDefaultDate;
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool ShowClearButtonPredicate()
|
||||
{
|
||||
return RangeStartSelectedDate is not null || RangeEndSelectedDate is not null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using AtomUI.Data;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
|
||||
namespace AtomUI.Controls;
|
||||
|
||||
internal class RangeDatePickerFlyout : Flyout
|
||||
{
|
||||
protected override Control CreatePresenter()
|
||||
{
|
||||
var presenter = new RangeDatePickerFlyoutPresenter();
|
||||
BindUtils.RelayBind(this, IsShowArrowEffectiveProperty, presenter, IsShowArrowProperty);
|
||||
CalculateShowArrowEffective();
|
||||
SetupArrowPosition(Popup, presenter);
|
||||
return presenter;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls.Primitives;
|
||||
|
||||
namespace AtomUI.Controls;
|
||||
|
||||
internal class RangeDatePickerFlyoutPresenter : FlyoutPresenter
|
||||
{
|
||||
#region 公共属性定义
|
||||
|
||||
public static readonly StyledProperty<bool> IsShowTimeProperty =
|
||||
DatePicker.IsShowTimeProperty.AddOwner<RangeDatePickerFlyoutPresenter>();
|
||||
|
||||
public bool IsShowTime
|
||||
{
|
||||
get => GetValue(IsShowTimeProperty);
|
||||
set => SetValue(IsShowTimeProperty, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
internal RangeDatePickerPresenter? DatePickerPresenter;
|
||||
|
||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||
{
|
||||
base.OnApplyTemplate(e);
|
||||
SetupDatePickerPresenter();
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnPropertyChanged(e);
|
||||
if (e.Property == IsShowTimeProperty)
|
||||
{
|
||||
SetupDatePickerPresenter();
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupDatePickerPresenter()
|
||||
{
|
||||
if (IsShowTime)
|
||||
{
|
||||
DatePickerPresenter = new TimedRangeDatePickerPresenter()
|
||||
{
|
||||
IsShowTime = true
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
DatePickerPresenter = new DualMonthRangeDatePickerPresenter();
|
||||
}
|
||||
|
||||
Content = DatePickerPresenter;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using AtomUI.Theme.Styling;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Templates;
|
||||
|
||||
namespace AtomUI.Controls;
|
||||
|
||||
[ControlThemeProvider]
|
||||
internal class RangeDatePickerFlyoutPresenterTheme : ArrowDecoratedBoxTheme
|
||||
{
|
||||
public const string PickerPresenterContentPart = "PART_PickerPresenterContent";
|
||||
|
||||
public RangeDatePickerFlyoutPresenterTheme()
|
||||
: this(typeof(RangeDatePickerFlyoutPresenter))
|
||||
{
|
||||
}
|
||||
|
||||
protected RangeDatePickerFlyoutPresenterTheme(Type targetType) : base(targetType)
|
||||
{
|
||||
}
|
||||
|
||||
protected override Control BuildContent(INameScope scope)
|
||||
{
|
||||
var datePickerPresenter = new RangeDatePickerPresenter()
|
||||
{
|
||||
Name = PickerPresenterContentPart,
|
||||
};
|
||||
datePickerPresenter.RegisterInNameScope(scope);
|
||||
return datePickerPresenter;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using Avalonia;
|
||||
|
||||
namespace AtomUI.Controls;
|
||||
|
||||
internal class RangeDatePickerPresenter : DatePickerPresenter
|
||||
{
|
||||
#region 公共属性定义
|
||||
|
||||
public static readonly StyledProperty<DateTime?> SecondarySelectedDateTimeProperty =
|
||||
AvaloniaProperty.Register<RangeDatePickerPresenter, DateTime?>(nameof(SecondarySelectedDateTime));
|
||||
|
||||
public DateTime? SecondarySelectedDateTime
|
||||
{
|
||||
get => GetValue(SecondarySelectedDateTimeProperty);
|
||||
set => SetValue(SecondarySelectedDateTimeProperty, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using AtomUI.Controls.Internal;
|
||||
using AtomUI.Theme.Styling;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Styling;
|
||||
|
||||
namespace AtomUI.Controls;
|
||||
|
||||
[ControlThemeProvider]
|
||||
internal class RangeDatePickerTheme : RangeInfoPickerInputTheme
|
||||
{
|
||||
public RangeDatePickerTheme() : base(typeof(RangeDatePicker))
|
||||
{
|
||||
}
|
||||
|
||||
protected override PathIcon BuildInfoIcon(InfoPickerInput infoPickerInput, INameScope scope)
|
||||
{
|
||||
return new PathIcon()
|
||||
{
|
||||
Kind = "ClockCircleOutlined"
|
||||
};
|
||||
}
|
||||
|
||||
protected override void BuildStyles()
|
||||
{
|
||||
base.BuildStyles();
|
||||
{
|
||||
var infoInputBoxStyle = new Style(selector => selector.Nesting().Template().Name(InfoInputBoxPart));
|
||||
infoInputBoxStyle.Add(TextBox.MinWidthProperty, DatePickerTokenResourceKey.PickerInputMinWidth);
|
||||
Add(infoInputBoxStyle);
|
||||
|
||||
var secondaryInfoInputBoxStyle = new Style(selector => selector.Nesting().Template().Name(SecondaryInfoInputBoxPart));
|
||||
secondaryInfoInputBoxStyle.Add(TextBox.MinWidthProperty, DatePickerTokenResourceKey.PickerInputMinWidth);
|
||||
Add(secondaryInfoInputBoxStyle);
|
||||
}
|
||||
|
||||
var withTimeStyle =
|
||||
new Style(selector => selector.Nesting().PropertyEquals(DatePicker.IsShowTimeProperty, true));
|
||||
withTimeStyle.Add(DatePicker.MinWidthProperty, DatePickerTokenResourceKey.PickerInputWithTimeMinWidth);
|
||||
{
|
||||
var infoInputBoxStyle = new Style(selector => selector.Nesting().Template().Name(InfoInputBoxPart));
|
||||
infoInputBoxStyle.Add(TextBox.MinWidthProperty, DatePickerTokenResourceKey.PickerInputMinWidth);
|
||||
withTimeStyle.Add(infoInputBoxStyle);
|
||||
|
||||
var secondaryInfoInputBoxStyle = new Style(selector => selector.Nesting().Template().Name(SecondaryInfoInputBoxPart));
|
||||
secondaryInfoInputBoxStyle.Add(TextBox.MinWidthProperty, DatePickerTokenResourceKey.PickerInputMinWidth);
|
||||
withTimeStyle.Add(secondaryInfoInputBoxStyle);
|
||||
}
|
||||
Add(withTimeStyle);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace AtomUI.Controls;
|
||||
|
||||
internal class TimedRangeDatePickerPresenter : RangeDatePickerPresenter
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using AtomUI.Controls.CalendarView;
|
||||
using AtomUI.Theme.Styling;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Templates;
|
||||
using Avalonia.Layout;
|
||||
|
||||
namespace AtomUI.Controls;
|
||||
|
||||
[ControlThemeProvider]
|
||||
internal class TimedRangeDatePickerPresenterTheme : DatePickerPresenterTheme
|
||||
{
|
||||
public TimedRangeDatePickerPresenterTheme() : this(typeof(TimedRangeDatePickerPresenter))
|
||||
{
|
||||
}
|
||||
|
||||
public TimedRangeDatePickerPresenterTheme(Type targetType) : base(targetType)
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual Control BuildCalendarView(DatePickerPresenter presenter, INameScope scope)
|
||||
{
|
||||
var calendarLayout = new StackPanel()
|
||||
{
|
||||
Orientation = Orientation.Horizontal
|
||||
};
|
||||
var calendarView = new RangeCalendar()
|
||||
{
|
||||
Name = CalendarViewPart,
|
||||
};
|
||||
CreateTemplateParentBinding(calendarView, RangeCalendar.SelectedDateProperty, DatePickerPresenter.SelectedDateTimeProperty);
|
||||
calendarView.RegisterInNameScope(scope);
|
||||
calendarLayout.Children.Add(calendarView);
|
||||
|
||||
var timeView = new TimeView()
|
||||
{
|
||||
Name = TimeViewPart,
|
||||
VerticalAlignment = VerticalAlignment.Top,
|
||||
};
|
||||
CreateTemplateParentBinding(timeView, TimeView.ClockIdentifierProperty, DatePickerPresenter.ClockIdentifierProperty);
|
||||
CreateTemplateParentBinding(timeView, TimeView.IsVisibleProperty, DatePickerPresenter.IsShowTimeProperty);
|
||||
timeView.RegisterInNameScope(scope);
|
||||
calendarLayout.Children.Add(timeView);
|
||||
|
||||
return calendarLayout;
|
||||
}
|
||||
}
|
||||
@@ -159,7 +159,7 @@ public abstract class PopupFlyoutBase : FlyoutBase, IPopupHostProvider
|
||||
|
||||
#endregion
|
||||
|
||||
IPopupHost? IPopupHostProvider.PopupHost => Popup?.Host;
|
||||
IPopupHost? IPopupHostProvider.PopupHost => Popup.Host;
|
||||
protected Popup Popup => _popupLazy.Value;
|
||||
|
||||
private readonly Lazy<Popup> _popupLazy;
|
||||
@@ -591,4 +591,12 @@ public abstract class PopupFlyoutBase : FlyoutBase, IPopupHostProvider
|
||||
//Add new classes
|
||||
presenter.Classes.AddRange(classes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 有时候需要清空 Popup 的 Child控件,强制重新创建
|
||||
/// </summary>
|
||||
internal void ClearUpPopupChild()
|
||||
{
|
||||
Popup.Child = null;
|
||||
}
|
||||
}
|
||||
+4
@@ -38,6 +38,10 @@
|
||||
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.DatePickerFlyoutPresenterTheme());
|
||||
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.DatePickerPresenterTheme());
|
||||
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.DatePickerTheme());
|
||||
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.DualMonthRangeDatePickerPresenterTheme());
|
||||
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.RangeDatePickerFlyoutPresenterTheme());
|
||||
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.RangeDatePickerTheme());
|
||||
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.TimedRangeDatePickerPresenterTheme());
|
||||
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.EmptyIndicatorTheme());
|
||||
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.ExpanderTheme());
|
||||
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.MenuFlyoutPresenterTheme());
|
||||
|
||||
@@ -200,6 +200,7 @@ public abstract class InfoPickerInput : TemplatedControl
|
||||
_flyoutStateHelper.FlyoutAboutToShow += HandleFlyoutAboutToShow;
|
||||
_flyoutStateHelper.FlyoutAboutToClose += HandleFlyoutAboutToClose;
|
||||
_flyoutStateHelper.FlyoutOpened += HandleFlyoutOpened;
|
||||
_flyoutStateHelper.FlyoutClosed += HandleFlyoutClosed;
|
||||
_flyoutStateHelper.OpenFlyoutPredicate = FlyoutOpenPredicate;
|
||||
_flyoutStateHelper.ClickHideFlyoutPredicate = ClickHideFlyoutPredicate;
|
||||
}
|
||||
@@ -238,11 +239,19 @@ public abstract class InfoPickerInput : TemplatedControl
|
||||
NotifyFlyoutOpened();
|
||||
}
|
||||
|
||||
|
||||
protected virtual void NotifyFlyoutOpened()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
private void HandleFlyoutClosed(object? sender, EventArgs args)
|
||||
{
|
||||
NotifyFlyoutClosed();
|
||||
}
|
||||
|
||||
protected virtual void NotifyFlyoutClosed()
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual bool ClickHideFlyoutPredicate(IPopupHostProvider hostProvider, RawPointerEventArgs args)
|
||||
{
|
||||
if (hostProvider.PopupHost != args.Root)
|
||||
|
||||
@@ -284,7 +284,7 @@ public abstract class RangeInfoPickerInput : InfoPickerInput
|
||||
SetupPickerIndicatorPosition();
|
||||
}
|
||||
|
||||
private void SetupPickerIndicatorPosition()
|
||||
protected void SetupPickerIndicatorPosition()
|
||||
{
|
||||
if (_rangePickerIndicator is null ||
|
||||
_decoratedBox is null ||
|
||||
|
||||
Reference in New Issue
Block a user