feat: add popup content. format code.

This commit is contained in:
rabbitism
2024-04-27 01:11:17 +08:00
parent 9cce1cc180
commit 31847513d9
3 changed files with 125 additions and 126 deletions

View File

@@ -108,6 +108,7 @@
<Setter Property="BorderBrush" Value="{DynamicResource TextBoxDefaultBorderBrush}" /> <Setter Property="BorderBrush" Value="{DynamicResource TextBoxDefaultBorderBrush}" />
<Setter Property="BorderThickness" Value="{DynamicResource TextBoxBorderThickness}" /> <Setter Property="BorderThickness" Value="{DynamicResource TextBoxBorderThickness}" />
<Setter Property="CornerRadius" Value="{DynamicResource TextBoxDefaultCornerRadius}" /> <Setter Property="CornerRadius" Value="{DynamicResource TextBoxDefaultCornerRadius}" />
<Setter Property="MinHeight" Value="32"/>
<Setter Property="Template"> <Setter Property="Template">
<ControlTemplate TargetType="u:TimePicker"> <ControlTemplate TargetType="u:TimePicker">
<DataValidationErrors> <DataValidationErrors>
@@ -117,12 +118,12 @@
VerticalAlignment="Stretch"> VerticalAlignment="Stretch">
<Border <Border
x:Name="Background" x:Name="Background"
HorizontalAlignment="Stretch"
Background="{TemplateBinding Background}" Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}" BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}" BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}" /> CornerRadius="{TemplateBinding CornerRadius}" />
<Grid ColumnDefinitions="*, Auto, Auto"> <Grid ColumnDefinitions="*, Auto, Auto">
<!-- InnerLeftContent, Text and Watermark, ClearButton, InnerRightContent, Icon -->
<TextBox <TextBox
Name="{x:Static u:TimePicker.PART_TextBox}" Name="{x:Static u:TimePicker.PART_TextBox}"
Grid.Column="0" Grid.Column="0"
@@ -196,10 +197,25 @@
<DockPanel> <DockPanel>
<StackPanel DockPanel.Dock="Bottom" IsVisible="{TemplateBinding NeedConfirmation}"> <StackPanel DockPanel.Dock="Bottom" IsVisible="{TemplateBinding NeedConfirmation}">
<Button <Button
Margin="8"
HorizontalAlignment="Right" HorizontalAlignment="Right"
Command="{Binding $parent[u:TimePicker].Confirm}" Command="{Binding $parent[u:TimePicker].Confirm}"
Content="Confirm" /> Content="Confirm" />
</StackPanel> </StackPanel>
<ContentPresenter
Name="PART_PopupHeader"
Margin="8,8,8,0"
Content="{TemplateBinding PopupInnerTopContent}"
DockPanel.Dock="Top"
IsVisible="{TemplateBinding PopupInnerTopContent,
Converter={x:Static ObjectConverters.IsNotNull}}" />
<ContentPresenter
Name="PART_PopupFooter"
Margin="8,0,8,8"
Content="{TemplateBinding PopupInnerBottomContent}"
DockPanel.Dock="Bottom"
IsVisible="{TemplateBinding PopupInnerBottomContent,
Converter={x:Static ObjectConverters.IsNotNull}}" />
<u:TimePickerPresenter <u:TimePickerPresenter
Name="{x:Static u:TimePicker.PART_Presenter}" Name="{x:Static u:TimePicker.PART_Presenter}"
NeedsConfirmation="{TemplateBinding NeedConfirmation}" NeedsConfirmation="{TemplateBinding NeedConfirmation}"

View File

@@ -62,17 +62,12 @@ public class TimePicker : TemplatedControl, IClearControl, IInnerContentControl,
public static readonly StyledProperty<bool> IsReadonlyProperty = AvaloniaProperty.Register<TimePicker, bool>( public static readonly StyledProperty<bool> IsReadonlyProperty = AvaloniaProperty.Register<TimePicker, bool>(
nameof(IsReadonly)); nameof(IsReadonly));
public bool IsReadonly private Button? _button;
{
get => GetValue(IsReadonlyProperty);
set => SetValue(IsReadonlyProperty, value);
}
private Popup? _popup; private Popup? _popup;
private TimePickerPresenter? _presenter; private TimePickerPresenter? _presenter;
private TextBox? _textBox; private TextBox? _textBox;
private Button? _button;
static TimePicker() static TimePicker()
@@ -81,6 +76,12 @@ public class TimePicker : TemplatedControl, IClearControl, IInnerContentControl,
picker.OnSelectionChanged(args)); picker.OnSelectionChanged(args));
} }
public bool IsReadonly
{
get => GetValue(IsReadonlyProperty);
set => SetValue(IsReadonlyProperty, value);
}
public bool IsDropdownOpen public bool IsDropdownOpen
{ {
get => GetValue(IsDropdownOpenProperty); get => GetValue(IsDropdownOpenProperty);
@@ -187,7 +188,11 @@ public class TimePicker : TemplatedControl, IClearControl, IInnerContentControl,
private void OnTextChanged(object? sender, TextChangedEventArgs e) private void OnTextChanged(object? sender, TextChangedEventArgs e)
{ {
if (DisplayFormat is null || DisplayFormat.Length == 0) if (string.IsNullOrEmpty(_textBox?.Text))
{
TimePickerPresenter.TimeProperty.SetValue(null, _presenter);
}
else 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);
@@ -203,7 +208,13 @@ public class TimePicker : TemplatedControl, IClearControl, IInnerContentControl,
{ {
if (_textBox is null) return; if (_textBox is null) return;
var time = args.NewValue.Value; var time = args.NewValue.Value;
DateTime date = new DateTime(1, 1, 1, time?.Hours ?? 0, time?.Minutes ?? 0, time?.Seconds ?? 0); if (time is null)
{
_textBox.Text = null;
return;
}
var date = new DateTime(1, 1, 1, time.Value.Hours, time.Value.Minutes, time.Value.Seconds);
var text = date.ToString(DisplayFormat); var text = date.ToString(DisplayFormat);
_textBox.Text = text; _textBox.Text = text;
} }
@@ -212,11 +223,13 @@ public class TimePicker : TemplatedControl, IClearControl, IInnerContentControl,
{ {
_presenter?.Confirm(); _presenter?.Confirm();
SetCurrentValue(IsDropdownOpenProperty, false); SetCurrentValue(IsDropdownOpenProperty, false);
Focus();
} }
public void Dismiss() public void Dismiss()
{ {
SetCurrentValue(IsDropdownOpenProperty, false); SetCurrentValue(IsDropdownOpenProperty, false);
Focus();
} }
protected override void UpdateDataValidation(AvaloniaProperty property, BindingValueType state, Exception? error) protected override void UpdateDataValidation(AvaloniaProperty property, BindingValueType state, Exception? error)

View File

@@ -18,7 +18,7 @@ namespace Ursa.Controls;
[TemplatePart(PART_FirstSeparator, typeof(Control))] [TemplatePart(PART_FirstSeparator, typeof(Control))]
[TemplatePart(PART_SecondSeparator, typeof(Control))] [TemplatePart(PART_SecondSeparator, typeof(Control))]
[TemplatePart(PART_ThirdSeparator, typeof(Control))] [TemplatePart(PART_ThirdSeparator, typeof(Control))]
public class TimePickerPresenter: TemplatedControl public class TimePickerPresenter : TemplatedControl
{ {
public const string PART_HourSelector = "PART_HourSelector"; public const string PART_HourSelector = "PART_HourSelector";
public const string PART_MinuteSelector = "PART_MinuteSelector"; public const string PART_MinuteSelector = "PART_MinuteSelector";
@@ -35,25 +35,56 @@ public class TimePickerPresenter: TemplatedControl
public const string PART_SecondSeparator = "PART_SecondSeparator"; public const string PART_SecondSeparator = "PART_SecondSeparator";
public const string PART_ThirdSeparator = "PART_ThirdSeparator"; public const string PART_ThirdSeparator = "PART_ThirdSeparator";
private DateTimePickerPanel? _hourSelector;
private DateTimePickerPanel? _minuteSelector; public static readonly StyledProperty<bool> NeedsConfirmationProperty =
private DateTimePickerPanel? _secondSelector; AvaloniaProperty.Register<TimePickerPresenter, bool>(
private DateTimePickerPanel? _ampmSelector; nameof(NeedsConfirmation));
private Grid? _pickerContainer;
private Control? _hourScrollPanel; public static readonly StyledProperty<int> MinuteIncrementProperty =
private Control? _minuteScrollPanel; AvaloniaProperty.Register<TimePickerPresenter, int>(
private Control? _secondScrollPanel; nameof(MinuteIncrement));
public static readonly StyledProperty<int> SecondIncrementProperty =
AvaloniaProperty.Register<TimePickerPresenter, int>(
nameof(SecondIncrement));
public static readonly StyledProperty<TimeSpan?> TimeProperty =
AvaloniaProperty.Register<TimePickerPresenter, TimeSpan?>(
nameof(Time));
public static readonly StyledProperty<string> PanelFormatProperty =
AvaloniaProperty.Register<TimePickerPresenter, string>(
nameof(PanelFormat), "HH mm ss t");
private Control? _ampmScrollPanel; private Control? _ampmScrollPanel;
private DateTimePickerPanel? _ampmSelector;
private Control? _firstSeparator; private Control? _firstSeparator;
private Control? _hourScrollPanel;
private DateTimePickerPanel? _hourSelector;
private Control? _minuteScrollPanel;
private DateTimePickerPanel? _minuteSelector;
private Grid? _pickerContainer;
private Control? _secondScrollPanel;
private DateTimePickerPanel? _secondSelector;
private Control? _secondSeparator; private Control? _secondSeparator;
private Control? _thirdSeparator; private Control? _thirdSeparator;
private bool _use12Clock;
private bool _updateFromTimeChange;
internal TimeSpan _timeHolder; internal TimeSpan _timeHolder;
private bool _updateFromTimeChange;
private bool _use12Clock;
static TimePickerPresenter()
{
PanelFormatProperty.Changed.AddClassHandler<TimePickerPresenter, string>((presenter, args) =>
presenter.OnPanelFormatChanged(args));
TimeProperty.Changed.AddClassHandler<TimePickerPresenter, TimeSpan?>((presenter, args) =>
presenter.OnTimeChanged(args));
}
public static readonly StyledProperty<bool> NeedsConfirmationProperty = AvaloniaProperty.Register<TimePickerPresenter, bool>( public TimePickerPresenter()
nameof(NeedsConfirmation)); {
SetCurrentValue(TimeProperty, DateTime.Now.TimeOfDay);
}
public bool NeedsConfirmation public bool NeedsConfirmation
{ {
@@ -61,36 +92,24 @@ public class TimePickerPresenter: TemplatedControl
set => SetValue(NeedsConfirmationProperty, value); set => SetValue(NeedsConfirmationProperty, value);
} }
public static readonly StyledProperty<int> MinuteIncrementProperty = AvaloniaProperty.Register<TimePickerPresenter, int>(
nameof(MinuteIncrement));
public int MinuteIncrement public int MinuteIncrement
{ {
get => GetValue(MinuteIncrementProperty); get => GetValue(MinuteIncrementProperty);
set => SetValue(MinuteIncrementProperty, value); set => SetValue(MinuteIncrementProperty, value);
} }
public static readonly StyledProperty<int> SecondIncrementProperty = AvaloniaProperty.Register<TimePickerPresenter, int>(
nameof(SecondIncrement));
public int SecondIncrement public int SecondIncrement
{ {
get => GetValue(SecondIncrementProperty); get => GetValue(SecondIncrementProperty);
set => SetValue(SecondIncrementProperty, value); set => SetValue(SecondIncrementProperty, value);
} }
public static readonly StyledProperty<TimeSpan?> TimeProperty = AvaloniaProperty.Register<TimePickerPresenter, TimeSpan?>(
nameof(Time));
public TimeSpan? Time public TimeSpan? Time
{ {
get => GetValue(TimeProperty); get => GetValue(TimeProperty);
set => SetValue(TimeProperty, value); set => SetValue(TimeProperty, value);
} }
public static readonly StyledProperty<string> PanelFormatProperty = AvaloniaProperty.Register<TimePickerPresenter, string>(
nameof(PanelFormat), defaultValue: "HH mm ss t");
public string PanelFormat public string PanelFormat
{ {
get => GetValue(PanelFormatProperty); get => GetValue(PanelFormatProperty);
@@ -99,16 +118,10 @@ public class TimePickerPresenter: TemplatedControl
public event EventHandler<TimePickerSelectedValueChangedEventArgs>? SelectedTimeChanged; public event EventHandler<TimePickerSelectedValueChangedEventArgs>? SelectedTimeChanged;
static TimePickerPresenter()
{
PanelFormatProperty.Changed.AddClassHandler<TimePickerPresenter, string>((presenter, args) => presenter.OnPanelFormatChanged(args));
TimeProperty.Changed.AddClassHandler<TimePickerPresenter, TimeSpan?>((presenter, args) => presenter.OnTimeChanged(args));
}
private void OnTimeChanged(AvaloniaPropertyChangedEventArgs<TimeSpan?> args) private void OnTimeChanged(AvaloniaPropertyChangedEventArgs<TimeSpan?> args)
{ {
_updateFromTimeChange = true; _updateFromTimeChange = true;
UpdatePanelsFromSelectedTime(); UpdatePanelsFromSelectedTime(args.NewValue.Value);
_updateFromTimeChange = false; _updateFromTimeChange = false;
SelectedTimeChanged?.Invoke(this, SelectedTimeChanged?.Invoke(this,
new TimePickerSelectedValueChangedEventArgs(args.OldValue.Value, args.NewValue.Value)); new TimePickerSelectedValueChangedEventArgs(args.OldValue.Value, args.NewValue.Value));
@@ -155,10 +168,11 @@ public class TimePickerPresenter: TemplatedControl
_ampmSelector?.SetValue(DateTimePickerPanel.ItemFormatProperty, part); _ampmSelector?.SetValue(DateTimePickerPanel.ItemFormatProperty, part);
} }
} }
if (panels.Count < 1) return; if (panels.Count < 1) return;
IsVisibleProperty.SetValue(false, _hourScrollPanel, _minuteScrollPanel, _secondScrollPanel, _ampmScrollPanel, IsVisibleProperty.SetValue(false, _hourScrollPanel, _minuteScrollPanel, _secondScrollPanel, _ampmScrollPanel,
_firstSeparator, _secondSeparator, _thirdSeparator); _firstSeparator, _secondSeparator, _thirdSeparator);
for(var i = 0; i< panels.Count; i++) for (var i = 0; i < panels.Count; i++)
{ {
var panel = panels[i]; var panel = panels[i];
if (panel is null) continue; if (panel is null) continue;
@@ -169,56 +183,27 @@ public class TimePickerPresenter: TemplatedControl
0 => _firstSeparator, 0 => _firstSeparator,
1 => _secondSeparator, 1 => _secondSeparator,
2 => _thirdSeparator, 2 => _thirdSeparator,
_ => null, _ => null
}; };
if (i != panels.Count - 1) IsVisibleProperty.SetValue(true, separator); if (i != panels.Count - 1) IsVisibleProperty.SetValue(true, separator);
} }
} }
public TimePickerPresenter()
{
SetCurrentValue(TimeProperty, DateTime.Now.TimeOfDay);
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e) protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{ {
base.OnApplyTemplate(e); base.OnApplyTemplate(e);
if (_hourSelector is not null) if (_hourSelector is not null) _hourSelector.SelectionChanged -= OnPanelSelectionChanged;
{ if (_minuteSelector is not null) _minuteSelector.SelectionChanged -= OnPanelSelectionChanged;
_hourSelector.SelectionChanged -= OnPanelSelectionChanged; if (_secondSelector is not null) _secondSelector.SelectionChanged -= OnPanelSelectionChanged;
} if (_ampmSelector is not null) _ampmSelector.SelectionChanged -= OnPanelSelectionChanged;
if (_minuteSelector is not null)
{
_minuteSelector.SelectionChanged -= OnPanelSelectionChanged;
}
if (_secondSelector is not null)
{
_secondSelector.SelectionChanged -= OnPanelSelectionChanged;
}
if (_ampmSelector is not null)
{
_ampmSelector.SelectionChanged -= OnPanelSelectionChanged;
}
_hourSelector = e.NameScope.Find<DateTimePickerPanel>(PART_HourSelector); _hourSelector = e.NameScope.Find<DateTimePickerPanel>(PART_HourSelector);
_minuteSelector = e.NameScope.Find<DateTimePickerPanel>(PART_MinuteSelector); _minuteSelector = e.NameScope.Find<DateTimePickerPanel>(PART_MinuteSelector);
_secondSelector = e.NameScope.Find<DateTimePickerPanel>(PART_SecondSelector); _secondSelector = e.NameScope.Find<DateTimePickerPanel>(PART_SecondSelector);
_ampmSelector = e.NameScope.Find<DateTimePickerPanel>(PART_AmPmSelector); _ampmSelector = e.NameScope.Find<DateTimePickerPanel>(PART_AmPmSelector);
if(_hourSelector is not null) if (_hourSelector is not null) _hourSelector.SelectionChanged += OnPanelSelectionChanged;
{ if (_minuteSelector is not null) _minuteSelector.SelectionChanged += OnPanelSelectionChanged;
_hourSelector.SelectionChanged += OnPanelSelectionChanged; if (_secondSelector is not null) _secondSelector.SelectionChanged += OnPanelSelectionChanged;
} if (_ampmSelector is not null) _ampmSelector.SelectionChanged += OnPanelSelectionChanged;
if(_minuteSelector is not null)
{
_minuteSelector.SelectionChanged += OnPanelSelectionChanged;
}
if(_secondSelector is not null)
{
_secondSelector.SelectionChanged += OnPanelSelectionChanged;
}
if(_ampmSelector is not null)
{
_ampmSelector.SelectionChanged += OnPanelSelectionChanged;
}
_pickerContainer = e.NameScope.Find<Grid>(PART_PickerContainer); _pickerContainer = e.NameScope.Find<Grid>(PART_PickerContainer);
_hourScrollPanel = e.NameScope.Find<Control>(PART_HourScrollPanel); _hourScrollPanel = e.NameScope.Find<Control>(PART_HourScrollPanel);
_minuteScrollPanel = e.NameScope.Find<Control>(PART_MinuteScrollPanel); _minuteScrollPanel = e.NameScope.Find<Control>(PART_MinuteScrollPanel);
@@ -229,58 +214,46 @@ public class TimePickerPresenter: TemplatedControl
_thirdSeparator = e.NameScope.Find<Control>(PART_ThirdSeparator); _thirdSeparator = e.NameScope.Find<Control>(PART_ThirdSeparator);
Initialize(); Initialize();
UpdatePanelLayout(PanelFormat); UpdatePanelLayout(PanelFormat);
UpdatePanelsFromSelectedTime(); UpdatePanelsFromSelectedTime(Time);
} }
private void OnPanelSelectionChanged(object sender, System.EventArgs e) private void OnPanelSelectionChanged(object sender, System.EventArgs e)
{ {
if (_updateFromTimeChange) return; if (_updateFromTimeChange) return;
TimeSpan time = NeedsConfirmation ? _timeHolder : Time ?? DateTime.Now.TimeOfDay; var time = NeedsConfirmation ? _timeHolder : Time ?? DateTime.Now.TimeOfDay;
int hour = _hourSelector?.SelectedValue ?? time.Hours; var hour = _hourSelector?.SelectedValue ?? time.Hours;
int minute = _minuteSelector?.SelectedValue ?? time.Minutes; var minute = _minuteSelector?.SelectedValue ?? time.Minutes;
int second = _secondSelector?.SelectedValue ?? time.Seconds; var second = _secondSelector?.SelectedValue ?? time.Seconds;
int ampm = _ampmSelector?.SelectedValue ?? (time.Hours >= 12 ? 1 : 0); var ampm = _ampmSelector?.SelectedValue ?? (time.Hours >= 12 ? 1 : 0);
if (_use12Clock) if (_use12Clock)
{
hour = ampm switch hour = ampm switch
{ {
0 when hour == 12 => 0, 0 when hour == 12 => 0,
1 when hour < 12 => hour + 12, 1 when hour < 12 => hour + 12,
_ => hour _ => hour
}; };
}
var newTime = new TimeSpan(hour, minute, second); var newTime = new TimeSpan(hour, minute, second);
if (NeedsConfirmation) if (NeedsConfirmation)
{
_timeHolder = newTime; _timeHolder = newTime;
}
else else
{
SetCurrentValue(TimeProperty, newTime); SetCurrentValue(TimeProperty, newTime);
} }
}
private void UpdatePanelsFromSelectedTime() private void UpdatePanelsFromSelectedTime(TimeSpan? time)
{ {
if (Time is null) return; if (time is null) return;
var time = Time ?? DateTime.Now.TimeOfDay;
if (_hourSelector is not null) if (_hourSelector is not null)
{ {
var index = _use12Clock ? time.Hours % 12 : time.Hours; var index = _use12Clock ? time.Value.Hours % 12 : time.Value.Hours;
if (index == 0) index = 12; if (index == 0) index = 12;
_hourSelector.SelectedValue = index; _hourSelector.SelectedValue = index;
} }
if (_minuteSelector is not null)
{ if (_minuteSelector is not null) _minuteSelector.SelectedValue = time.Value.Minutes;
_minuteSelector.SelectedValue = time.Minutes; if (_secondSelector is not null) _secondSelector.SelectedValue = time.Value.Seconds;
}
if (_secondSelector is not null)
{
_secondSelector.SelectedValue = time.Seconds;
}
if (_ampmSelector is not null) if (_ampmSelector is not null)
{ {
_ampmSelector.SelectedValue = time.Hours switch _ampmSelector.SelectedValue = time.Value.Hours switch
{ {
>= 12 => 1, >= 12 => 1,
_ => 0 _ => 0
@@ -297,23 +270,23 @@ public class TimePickerPresenter: TemplatedControl
_hourSelector.ItemFormat = "hh"; _hourSelector.ItemFormat = "hh";
_hourSelector.MaximumValue = _use12Clock ? 12 : 23; _hourSelector.MaximumValue = _use12Clock ? 12 : 23;
_hourSelector.MinimumValue = _use12Clock ? 1 : 0; _hourSelector.MinimumValue = _use12Clock ? 1 : 0;
} }
if(_minuteSelector is not null)
if (_minuteSelector is not null)
{ {
_minuteSelector.ItemFormat = "mm"; _minuteSelector.ItemFormat = "mm";
_minuteSelector.MaximumValue = 59; _minuteSelector.MaximumValue = 59;
_minuteSelector.MinimumValue = 0; _minuteSelector.MinimumValue = 0;
} }
if(_secondSelector is not null)
if (_secondSelector is not null)
{ {
_secondSelector.ItemFormat = "mm"; _secondSelector.ItemFormat = "mm";
_secondSelector.MaximumValue = 59; _secondSelector.MaximumValue = 59;
_secondSelector.MinimumValue = 0; _secondSelector.MinimumValue = 0;
} }
if(_ampmSelector is not null)
if (_ampmSelector is not null)
{ {
_ampmSelector.ItemFormat = "t"; _ampmSelector.ItemFormat = "t";
_ampmSelector.MaximumValue = 1; _ampmSelector.MaximumValue = 1;
@@ -323,9 +296,6 @@ public class TimePickerPresenter: TemplatedControl
public void Confirm() public void Confirm()
{ {
if (NeedsConfirmation) if (NeedsConfirmation) SetCurrentValue(TimeProperty, _timeHolder);
{
SetCurrentValue(TimeProperty, _timeHolder);
}
} }
} }