Fix DatePicker Arrow bug

This commit is contained in:
chinboy
2025-08-15 14:47:51 +08:00
parent 399a92410a
commit e5f1f550e4
9 changed files with 143 additions and 216 deletions
+10 -22
View File
@@ -165,36 +165,24 @@ public class DatePicker : InfoPickerInput,
var flyout = new DatePickerFlyout();
flyout.IsDetectMouseClickEnabled = false;
BindUtils.RelayBind(this, IsMotionEnabledProperty, flyout, DatePickerFlyout.IsMotionEnabledProperty);
BindUtils.RelayBind(this, IsMotionEnabledProperty, flyout, DatePickerPresenter.IsMotionEnabledProperty);
BindUtils.RelayBind(this, SelectedDateTimeProperty, flyout, DatePickerPresenter.SelectedDateTimeProperty);
BindUtils.RelayBind(this, IsNeedConfirmProperty, flyout, DatePickerPresenter.IsNeedConfirmProperty);
BindUtils.RelayBind(this, IsShowNowProperty, flyout, DatePickerPresenter.IsShowNowProperty);
BindUtils.RelayBind(this, IsShowTimeProperty, flyout, DatePickerPresenter.IsShowTimeProperty);
BindUtils.RelayBind(this, ClockIdentifierProperty, flyout, DatePickerPresenter.ClockIdentifierProperty);
return flyout;
}
protected override void NotifyFlyoutPresenterCreated(Control flyoutPresenter)
{
if (flyoutPresenter is DatePickerFlyoutPresenter datePickerFlyoutPresenter)
if (PickerFlyout is DatePickerFlyout datePickerFlyout)
{
datePickerFlyoutPresenter.AttachedToVisualTree += (sender, args) =>
{
_pickerPresenter = datePickerFlyoutPresenter.DatePickerPresenter;
ConfigurePickerPresenter(_pickerPresenter);
};
_pickerPresenter = datePickerFlyout.DatePickerPresenter;
}
}
private void ConfigurePickerPresenter(DatePickerPresenter? presenter)
{
if (presenter is null)
{
return;
}
BindUtils.RelayBind(this, IsMotionEnabledProperty, presenter, DatePickerPresenter.IsMotionEnabledProperty);
BindUtils.RelayBind(this, SelectedDateTimeProperty, presenter, DatePickerPresenter.SelectedDateTimeProperty);
BindUtils.RelayBind(this, IsNeedConfirmProperty, presenter, DatePickerPresenter.IsNeedConfirmProperty);
BindUtils.RelayBind(this, IsShowNowProperty, presenter, DatePickerPresenter.IsShowNowProperty);
BindUtils.RelayBind(this, IsShowTimeProperty, presenter, DatePickerPresenter.IsShowTimeProperty);
BindUtils.RelayBind(this, ClockIdentifierProperty, presenter, DatePickerPresenter.ClockIdentifierProperty);
}
protected override void NotifyFlyoutOpened()
{
base.NotifyFlyoutOpened();
@@ -1,18 +1,77 @@
using AtomUI.Data;
using Avalonia;
using Avalonia.Controls;
namespace AtomUI.Controls;
internal class DatePickerFlyout : Flyout
{
public static readonly StyledProperty<DateTime?> SelectedDateTimeProperty =
DatePicker.SelectedDateTimeProperty.AddOwner<DatePickerFlyout>();
public static readonly StyledProperty<bool> IsNeedConfirmProperty =
DatePicker.IsNeedConfirmProperty.AddOwner<DatePickerFlyout>();
public static readonly StyledProperty<bool> IsShowNowProperty =
DatePicker.IsShowNowProperty.AddOwner<DatePickerFlyout>();
public static readonly StyledProperty<bool> IsShowTimeProperty =
DatePicker.IsShowTimeProperty.AddOwner<DatePickerFlyout>();
public static readonly StyledProperty<ClockIdentifierType> ClockIdentifierProperty =
TimePicker.ClockIdentifierProperty.AddOwner<DatePickerFlyout>();
public DateTime? SelectedDateTime
{
get => GetValue(SelectedDateTimeProperty);
set => SetValue(SelectedDateTimeProperty, 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);
}
internal DatePickerPresenter? DatePickerPresenter { get; set; }
protected override Control CreatePresenter()
{
var presenter = new DatePickerFlyoutPresenter();
BindUtils.RelayBind(this, IsShowArrowEffectiveProperty, presenter, IsShowArrowProperty);
DatePickerPresenter = new DatePickerPresenter();
BindUtils.RelayBind(this, IsMotionEnabledProperty, DatePickerPresenter, DatePickerPresenter.IsMotionEnabledProperty);
BindUtils.RelayBind(this, SelectedDateTimeProperty, DatePickerPresenter, DatePickerPresenter.SelectedDateTimeProperty);
BindUtils.RelayBind(this, IsNeedConfirmProperty, DatePickerPresenter, DatePickerPresenter.IsNeedConfirmProperty);
BindUtils.RelayBind(this, IsShowNowProperty, DatePickerPresenter, DatePickerPresenter.IsShowNowProperty);
BindUtils.RelayBind(this, IsShowTimeProperty, DatePickerPresenter, DatePickerPresenter.IsShowTimeProperty);
BindUtils.RelayBind(this, ClockIdentifierProperty, DatePickerPresenter, DatePickerPresenter.ClockIdentifierProperty);
var flyoutPresenter = new FlyoutPresenter
{
Content = DatePickerPresenter
};
BindUtils.RelayBind(this, IsShowArrowEffectiveProperty, flyoutPresenter, IsShowArrowProperty);
CalculateShowArrowEffective();
SetupArrowPosition(Popup, presenter);
return presenter;
SetupArrowPosition(Popup, flyoutPresenter);
return flyoutPresenter;
}
}
@@ -1,18 +0,0 @@
using AtomUI.Controls.Themes;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
namespace AtomUI.Controls;
internal class DatePickerFlyoutPresenter : FlyoutPresenter
{
protected override Type StyleKeyOverride => typeof(DatePickerFlyoutPresenter);
internal DatePickerPresenter? DatePickerPresenter;
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
DatePickerPresenter = e.NameScope.Get<DatePickerPresenter>(DatePickerFlyoutPresenterThemeConstants.DatePickerPresenterPart);
}
}
@@ -128,6 +128,14 @@ public class RangeDatePicker : RangeInfoPickerInput,
var flyout = new RangeDatePickerFlyout();
flyout.IsDetectMouseClickEnabled = false;
BindUtils.RelayBind(this, IsMotionEnabledProperty, flyout, RangeDatePickerFlyout.IsMotionEnabledProperty);
BindUtils.RelayBind(this, RangeStartSelectedDateProperty, flyout, RangeDatePickerFlyout.SelectedDateTimeProperty);
BindUtils.RelayBind(this, RangeEndSelectedDateProperty, flyout, RangeDatePickerFlyout.SecondarySelectedDateTimeProperty);
BindUtils.RelayBind(this, ClockIdentifierProperty, flyout, RangeDatePickerFlyout.ClockIdentifierProperty);
BindUtils.RelayBind(this, IsNeedConfirmProperty, flyout, RangeDatePickerFlyout.IsNeedConfirmProperty);
BindUtils.RelayBind(this, IsShowNowProperty, flyout, RangeDatePickerFlyout.IsShowNowProperty);
BindUtils.RelayBind(this, IsShowTimeProperty, flyout, RangeDatePickerFlyout.IsShowTimeProperty);
return flyout;
}
@@ -147,32 +155,13 @@ public class RangeDatePicker : RangeInfoPickerInput,
protected override void NotifyFlyoutPresenterCreated(Control flyoutPresenter)
{
if (flyoutPresenter is RangeDatePickerFlyoutPresenter rangeDatePickerFlyoutPresenter)
if (PickerFlyout is RangeDatePickerFlyout datePickerFlyout)
{
BindUtils.RelayBind(this, IsShowTimeProperty, rangeDatePickerFlyoutPresenter, RangeDatePickerFlyoutPresenter.IsShowTimeProperty);
rangeDatePickerFlyoutPresenter.AttachedToVisualTree += (sender, args) =>
{
_pickerPresenter = rangeDatePickerFlyoutPresenter.DatePickerPresenter;
ConfigurePickerPresenter(_pickerPresenter);
};
_pickerPresenter = datePickerFlyout.DatePickerPresenter as RangeDatePickerPresenter;
_pickerPresenter?.NotifyRepairReverseRange(true);
}
}
private void ConfigurePickerPresenter(RangeDatePickerPresenter? presenter)
{
if (presenter is null)
{
return;
}
presenter.NotifyRepairReverseRange(true);
BindUtils.RelayBind(this, IsMotionEnabledProperty, presenter, RangeDatePickerPresenter.IsMotionEnabledProperty);
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();
@@ -193,7 +182,6 @@ public class RangeDatePicker : RangeInfoPickerInput,
{
_pickerPresenter.NotifySelectRangeStart(false);
}
}
}
@@ -1,16 +1,68 @@
using AtomUI.Data;
using Avalonia;
using Avalonia.Controls;
namespace AtomUI.Controls;
internal class RangeDatePickerFlyout : Flyout
internal class RangeDatePickerFlyout : DatePickerFlyout
{
public static readonly StyledProperty<DateTime?> SecondarySelectedDateTimeProperty =
RangeDatePickerPresenter.SecondarySelectedDateTimeProperty.AddOwner<RangeDatePickerFlyout>();
public DateTime? SecondarySelectedDateTime
{
get => GetValue(SecondarySelectedDateTimeProperty);
set => SetValue(SecondarySelectedDateTimeProperty, value);
}
internal FlyoutPresenter? _flyoutPresenter;
protected override Control CreatePresenter()
{
var presenter = new RangeDatePickerFlyoutPresenter();
BindUtils.RelayBind(this, IsShowArrowEffectiveProperty, presenter, IsShowArrowProperty);
_flyoutPresenter = new FlyoutPresenter();
ConfigureDatePickerPresenter();
BindUtils.RelayBind(this, IsShowArrowEffectiveProperty, _flyoutPresenter, IsShowArrowProperty);
CalculateShowArrowEffective();
SetupArrowPosition(Popup, presenter);
return presenter;
SetupArrowPosition(Popup, _flyoutPresenter);
return _flyoutPresenter;
}
private void ConfigureDatePickerPresenter()
{
if (_flyoutPresenter != null)
{
DatePickerPresenter? presenter;
if (IsShowTime)
{
presenter = new TimedRangeDatePickerPresenter()
{
IsShowTime = true
};
}
else
{
presenter = new DualMonthRangeDatePickerPresenter();
}
BindUtils.RelayBind(this, IsMotionEnabledProperty, presenter, RangeDatePickerPresenter.IsMotionEnabledProperty);
BindUtils.RelayBind(this, SelectedDateTimeProperty, presenter, RangeDatePickerPresenter.SelectedDateTimeProperty);
BindUtils.RelayBind(this, IsNeedConfirmProperty, presenter, RangeDatePickerPresenter.IsNeedConfirmProperty);
BindUtils.RelayBind(this, IsShowNowProperty, presenter, RangeDatePickerPresenter.IsShowNowProperty);
BindUtils.RelayBind(this, IsShowTimeProperty, presenter, RangeDatePickerPresenter.IsShowTimeProperty);
BindUtils.RelayBind(this, ClockIdentifierProperty, presenter, RangeDatePickerPresenter.ClockIdentifierProperty);
BindUtils.RelayBind(this, SecondarySelectedDateTimeProperty, presenter, RangeDatePickerPresenter.SecondarySelectedDateTimeProperty);
_flyoutPresenter.Content = presenter;
DatePickerPresenter = presenter;
}
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
if (e.Property == IsShowTimeProperty)
{
ConfigureDatePickerPresenter();
}
}
}
@@ -1,57 +0,0 @@
using AtomUI.Data;
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 OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(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();
}
BindUtils.RelayBind(this, IsMotionEnabledProperty, DatePickerPresenter, IsMotionEnabledProperty);
Content = DatePickerPresenter;
}
}
@@ -1,42 +0,0 @@
<ResourceDictionary
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:themes="using:AtomUI.Controls.Themes"
xmlns:atom="https://atomui.net"
x:ClassModifier="internal">
<ControlTheme x:Key="{x:Type atom:DatePickerFlyoutPresenter}" TargetType="atom:DatePickerFlyoutPresenter">
<ControlTheme.BasedOn>
<themes:ArrowDecoratedBoxTheme TargetType="atom:DatePickerFlyoutPresenter" />
</ControlTheme.BasedOn>
<Setter Property="Template">
<ControlTemplate>
<DockPanel
Name="{x:Static atom:ArrowDecoratedBoxThemeConstants.ContentLayoutPart}"
LastChildFill="True">
<Panel Name="{x:Static atom:ArrowDecoratedBoxThemeConstants.ArrowPositionLayoutPart}">
<LayoutTransformControl
Name="{x:Static atom:ArrowDecoratedBoxThemeConstants.ArrowIndicatorLayoutPart}"
HorizontalAlignment="Left"
VerticalAlignment="Top"
IsVisible="{TemplateBinding IsShowArrow}">
<atom:ArrowIndicator
Name="{x:Static atom:ArrowDecoratedBoxThemeConstants.ArrowIndicatorPart}"
FilledColor="{TemplateBinding Background}" />
</LayoutTransformControl>
</Panel>
<Border
Name="{x:Static atom:ArrowDecoratedBoxThemeConstants.ContentDecoratorPart}"
Margin="0"
BackgroundSizing="{TemplateBinding BackgroundSizing}"
Background="{TemplateBinding Background}"
CornerRadius="{TemplateBinding CornerRadius}"
Padding="{TemplateBinding Padding}">
<atom:DatePickerPresenter
Name="{x:Static atom:DatePickerFlyoutPresenterThemeConstants.DatePickerPresenterPart}"
IsMotionEnabled="{TemplateBinding IsMotionEnabled}"/>
</Border>
</DockPanel>
</ControlTemplate>
</Setter>
</ControlTheme>
</ResourceDictionary>
@@ -11,9 +11,7 @@
<ResourceInclude Source="CalendarView/DualMonthRangeCalendarTheme.axaml"/>
<ResourceInclude Source="CalendarView/DualMonthCalendarItemTheme.axaml"/>
<ResourceInclude Source="DatePickerFlyoutPresenterTheme.axaml"/>
<ResourceInclude Source="DualMonthRangeDatePickerPresenterTheme.axaml"/>
<ResourceInclude Source="RangeDatePickerFlyoutPresenterTheme.axaml"/>
<ResourceInclude Source="TimedRangeDatePickerPresenterTheme.axaml"/>
<ResourceInclude Source="DatePickerTheme.axaml"/>
<ResourceInclude Source="RangeDatePickerTheme.axaml"/>
@@ -1,41 +0,0 @@
<ResourceDictionary
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:themes="using:AtomUI.Controls.Themes"
xmlns:atom="https://atomui.net"
x:ClassModifier="internal">
<ControlTheme x:Key="{x:Type atom:RangeDatePickerFlyoutPresenter}" TargetType="atom:RangeDatePickerFlyoutPresenter">
<ControlTheme.BasedOn>
<themes:ArrowDecoratedBoxTheme TargetType="atom:RangeDatePickerFlyoutPresenter" />
</ControlTheme.BasedOn>
<Setter Property="Template">
<ControlTemplate>
<DockPanel
Name="{x:Static atom:ArrowDecoratedBoxThemeConstants.ContentLayoutPart}"
LastChildFill="True">
<Panel Name="{x:Static atom:ArrowDecoratedBoxThemeConstants.ArrowPositionLayoutPart}">
<LayoutTransformControl
Name="{x:Static atom:ArrowDecoratedBoxThemeConstants.ArrowIndicatorLayoutPart}"
HorizontalAlignment="Left"
VerticalAlignment="Top"
IsVisible="{TemplateBinding IsShowArrow}">
<atom:ArrowIndicator
Name="{x:Static atom:ArrowDecoratedBoxThemeConstants.ArrowIndicatorPart}"
FilledColor="{TemplateBinding Background}" />
</LayoutTransformControl>
</Panel>
<Border
Name="{x:Static atom:ArrowDecoratedBoxThemeConstants.ContentDecoratorPart}"
Margin="0"
BackgroundSizing="{TemplateBinding BackgroundSizing}"
Background="{TemplateBinding Background}"
CornerRadius="{TemplateBinding CornerRadius}"
Padding="{TemplateBinding Padding}">
<atom:RangeDatePickerPresenter
Name="{x:Static atom:RangeDatePickerFlyoutPresenterThemeConstants.PickerPresenterContentPart}"/>
</Border>
</DockPanel>
</ControlTemplate>
</Setter>
</ControlTheme>
</ResourceDictionary>