feat: fix several selection issue related to 12 clock mode.

This commit is contained in:
rabbitism
2024-04-26 20:34:20 +08:00
parent 1e5da1869c
commit 63b9ccfe5e
4 changed files with 52 additions and 50 deletions

View File

@@ -6,9 +6,8 @@
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Ursa.Demo.Pages.TimePickerDemo"> x:Class="Ursa.Demo.Pages.TimePickerDemo">
<StackPanel HorizontalAlignment="Left"> <StackPanel HorizontalAlignment="Left">
<u:TimePickerPresenter Name="presenter" HorizontalAlignment="Left" VerticalAlignment="Top"/> <ToggleSwitch Content="Need Confirm" Name="needConfirm"></ToggleSwitch>
<TextBlock Text="{Binding #presenter.Time}"/> <TextBlock Text="{Binding #picker.SelectedTime}" ></TextBlock>
<u:TimePicker Name="picker" Width="200" NeedConfirmation="{Binding #needConfirm.IsChecked}" PanelFormat="hh mm tt"></u:TimePicker>
<u:TimePicker Width="200" NeedConfirmation="False"></u:TimePicker>
</StackPanel> </StackPanel>
</UserControl> </UserControl>

View File

@@ -152,11 +152,16 @@
Placement="BottomEdgeAlignedLeft" Placement="BottomEdgeAlignedLeft"
PlacementTarget="Background"> PlacementTarget="Background">
<Border Theme="{DynamicResource CardBorder}"> <Border Theme="{DynamicResource CardBorder}">
<DockPanel>
<StackPanel DockPanel.Dock="Bottom" IsVisible="{TemplateBinding NeedConfirmation}">
<Button Content="Confirm" Command="{Binding $parent[u:TimePicker].Confirm}"></Button>
</StackPanel>
<u:TimePickerPresenter <u:TimePickerPresenter
Name="{x:Static u:TimePicker.PART_Presenter}" Name="{x:Static u:TimePicker.PART_Presenter}"
NeedsConfirmation="{TemplateBinding NeedConfirmation}" NeedsConfirmation="{TemplateBinding NeedConfirmation}"
PanelFormat="{TemplateBinding PanelFormat}" PanelFormat="{TemplateBinding PanelFormat}"
Time="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=SelectedTime, Mode=OneWayToSource}" /> Time="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=SelectedTime, Mode=OneWayToSource}" />
</DockPanel>
</Border> </Border>
</Popup> </Popup>
</Grid> </Grid>

View File

@@ -11,22 +11,17 @@ using Irihi.Avalonia.Shared.Helpers;
namespace Ursa.Controls; namespace Ursa.Controls;
[TemplatePart( PART_TextBox, typeof(TextBox))] [TemplatePart(PART_TextBox, typeof(TextBox))]
[TemplatePart( PART_Popup, typeof(Popup))] [TemplatePart(PART_Popup, typeof(Popup))]
[TemplatePart( PART_Presenter, typeof(TimePickerPresenter))] [TemplatePart(PART_Presenter, typeof(TimePickerPresenter))]
public class TimePicker : TemplatedControl, IClearControl, IInnerContentControl, IPopupInnerContent public class TimePicker : TemplatedControl, IClearControl, IInnerContentControl, IPopupInnerContent
{ {
public const string PART_TextBox = "PART_TextBox"; public const string PART_TextBox = "PART_TextBox";
public const string PART_Popup = "PART_Popup"; public const string PART_Popup = "PART_Popup";
public const string PART_Presenter = "PART_Presenter"; public const string PART_Presenter = "PART_Presenter";
private TextBox? _textBox; public static readonly StyledProperty<string?> DisplayFormatProperty =
private Popup? _popup; AvaloniaProperty.Register<TimePicker, string?>(
private TimePickerPresenter? _presenter;
private bool _updateFromPresenter;
public static readonly StyledProperty<string?> DisplayFormatProperty = AvaloniaProperty.Register<TimePicker, string?>(
nameof(DisplayFormat), "HH:mm:ss"); nameof(DisplayFormat), "HH:mm:ss");
public static readonly StyledProperty<string> PanelFormatProperty = AvaloniaProperty.Register<TimePicker, string>( public static readonly StyledProperty<string> PanelFormatProperty = AvaloniaProperty.Register<TimePicker, string>(
@@ -62,6 +57,19 @@ public class TimePicker : TemplatedControl, IClearControl, IInnerContentControl,
public static readonly StyledProperty<bool> IsDropdownOpenProperty = AvaloniaProperty.Register<TimePicker, bool>( public static readonly StyledProperty<bool> IsDropdownOpenProperty = AvaloniaProperty.Register<TimePicker, bool>(
nameof(IsDropdownOpen), defaultBindingMode: BindingMode.TwoWay); nameof(IsDropdownOpen), defaultBindingMode: BindingMode.TwoWay);
private Popup? _popup;
private TimePickerPresenter? _presenter;
private TextBox? _textBox;
private bool _updateFromText;
static TimePicker()
{
SelectedTimeProperty.Changed.AddClassHandler<TimePicker, TimeSpan?>((picker, args) =>
picker.OnSelectionChanged(args));
}
public bool IsDropdownOpen public bool IsDropdownOpen
{ {
get => GetValue(IsDropdownOpenProperty); get => GetValue(IsDropdownOpenProperty);
@@ -74,16 +82,6 @@ public class TimePicker : TemplatedControl, IClearControl, IInnerContentControl,
set => SetValue(WatermarkProperty, value); set => SetValue(WatermarkProperty, value);
} }
private TimeSpan? _selectedTimeHolder;
static TimePicker()
{
PanelFormatProperty.Changed.AddClassHandler<TimePicker, string>((picker, args) =>
picker.OnPanelFormatChanged(args));
SelectedTimeProperty.Changed.AddClassHandler<TimePicker, TimeSpan?>((picker, args) =>
picker.OnSelectionChanged(args));
}
public string? DisplayFormat public string? DisplayFormat
{ {
get => GetValue(DisplayFormatProperty); get => GetValue(DisplayFormatProperty);
@@ -137,12 +135,6 @@ public class TimePicker : TemplatedControl, IClearControl, IInnerContentControl,
set => SetValue(PopupInnerBottomContentProperty, value); set => SetValue(PopupInnerBottomContentProperty, value);
} }
private void OnPanelFormatChanged(AvaloniaPropertyChangedEventArgs<string> args)
{
var format = args.NewValue.Value;
var parts = format.Split(' ', '-', ':');
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e) protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{ {
@@ -151,9 +143,10 @@ public class TimePicker : TemplatedControl, IClearControl, IInnerContentControl,
_textBox = e.NameScope.Find<TextBox>(PART_TextBox); _textBox = e.NameScope.Find<TextBox>(PART_TextBox);
_popup = e.NameScope.Find<Popup>(PART_Popup); _popup = e.NameScope.Find<Popup>(PART_Popup);
_presenter = e.NameScope.Find<TimePickerPresenter>(PART_Presenter); _presenter = e.NameScope.Find<TimePickerPresenter>(PART_Presenter);
TextBox.GotFocusEvent.AddHandler(OnTextBoxGetFocus, _textBox); GotFocusEvent.AddHandler(OnTextBoxGetFocus, _textBox);
TextBox.TextChangedEvent.AddDisposableHandler(OnTextChanged, _textBox); TextBox.TextChangedEvent.AddDisposableHandler(OnTextChanged, _textBox);
TextBox.PointerPressedEvent.AddHandler(OnTextBoxPointerPressed, RoutingStrategies.Tunnel, false, _textBox); PointerPressedEvent.AddHandler(OnTextBoxPointerPressed, RoutingStrategies.Tunnel, false, _textBox);
SetCurrentValue(SelectedTimeProperty, DateTime.Now.TimeOfDay);
} }
private void OnTextBoxPointerPressed(object sender, PointerPressedEventArgs e) private void OnTextBoxPointerPressed(object sender, PointerPressedEventArgs e)
@@ -169,35 +162,38 @@ public class TimePicker : TemplatedControl, IClearControl, IInnerContentControl,
private void OnTextChanged(object sender, TextChangedEventArgs e) private void OnTextChanged(object sender, TextChangedEventArgs e)
{ {
_updateFromText = true;
if (DisplayFormat is null || DisplayFormat.Length == 0) if (DisplayFormat is null || DisplayFormat.Length == 0)
{ {
if (TimeSpan.TryParse(_textBox?.Text, out var defaultTime)) if (TimeSpan.TryParse(_textBox?.Text, out var defaultTime))
{
TimePickerPresenter.TimeProperty.SetValue(defaultTime, _presenter); TimePickerPresenter.TimeProperty.SetValue(defaultTime, _presenter);
} }
}
else else
{ {
if(DateTime.TryParseExact(_textBox?.Text, DisplayFormat, CultureInfo.CurrentUICulture, DateTimeStyles.None, out var time)) if (DateTime.TryParseExact(_textBox?.Text, DisplayFormat, CultureInfo.CurrentUICulture, DateTimeStyles.None,
{ out var time)) TimePickerPresenter.TimeProperty.SetValue(time.TimeOfDay, _presenter);
TimePickerPresenter.TimeProperty.SetValue(time.TimeOfDay, _presenter);
}
} }
_updateFromText = false;
} }
private void OnSelectionChanged(AvaloniaPropertyChangedEventArgs<TimeSpan?> args) private void OnSelectionChanged(AvaloniaPropertyChangedEventArgs<TimeSpan?> args)
{ {
if (_textBox is null) return; if (_textBox is null) return;
var time = args.NewValue.Value; var time = args.NewValue.Value;
var text = new DateTime(1,1,1, time?.Hours ?? 0, time?.Minutes ?? 0, time?.Seconds ?? 0).ToString(DisplayFormat); DateTime date = new DateTime(1, 1, 1, time?.Hours ?? 0, time?.Minutes ?? 0, time?.Seconds ?? 0);
var text = date.ToString(DisplayFormat);
_textBox.Text = text; _textBox.Text = text;
} }
public void Confirm() public void Confirm()
{ {
if (NeedConfirmation) _presenter?.Confirm();
// TODO: close popup. SetCurrentValue(IsDropdownOpenProperty, false);
SetCurrentValue(SelectedTimeProperty, _selectedTimeHolder); }
public void Dismiss()
{
SetCurrentValue(IsDropdownOpenProperty, false);
} }
protected override void UpdateDataValidation(AvaloniaProperty property, BindingValueType state, Exception? error) protected override void UpdateDataValidation(AvaloniaProperty property, BindingValueType state, Exception? error)

View File

@@ -266,7 +266,9 @@ public class TimePickerPresenter: TemplatedControl
var time = Time ?? DateTime.Now.TimeOfDay; var time = Time ?? DateTime.Now.TimeOfDay;
if (_hourSelector is not null) if (_hourSelector is not null)
{ {
_hourSelector.SelectedValue = _use12Clock ? time.Hours % 12 : time.Hours; var index = _use12Clock ? time.Hours % 12 : time.Hours;
if (index == 0) index = 12;
_hourSelector.SelectedValue = index;
} }
if (_minuteSelector is not null) if (_minuteSelector is not null)
{ {