一、效果图,仿照ElementUI的TimePicker
二、创建一个自定义用户控件TimePicker。
Generic.xaml部分的代码
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp1">
<Style TargetType="{x:Type local:TimePicker}">
<Setter Property="Height" Value="40" />
<Setter Property="Width" Value="220" />
<Setter Property="FontSize" Value="14" />
<Setter Property="Foreground" Value="#606266" />
<Setter Property="Background" Value="White" />
<Setter Property="BorderBrush" Value="#dcdfe6" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:TimePicker}">
<ControlTemplate.Resources>
<Style TargetType="Button">
<Setter Property="Cursor" Value="Hand" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button" >
<Border Background="Transparent">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ControlTemplate.Resources>
<Border x:Name="border" Background="{TemplateBinding Background}"
Height="{TemplateBinding Height}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Cursor="Hand" SnapsToDevicePixels="True" CornerRadius="4">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25" />
<ColumnDefinition />
<ColumnDefinition Width="25" />
</Grid.ColumnDefinitions>
<Viewbox Width="14" Height="14">
<Path Fill="#8d8d8d">
<Path.Data>
<Geometry>
M512 56.889c-250.311 0-455.111 204.8-455.111 455.111S261.689 967.111 512 967.111 967.111 762.311 967.111 512 762.311 56.889 512 56.889m0 853.333c-221.867 0-398.222-176.355-398.222-398.222S290.133 113.778 512 113.778 910.222 290.133 910.222 512 733.867 910.222 512 910.222
M512 512V227.556h-56.889v341.333h284.445V512z
</Geometry>
</Path.Data>
</Path>
</Viewbox>
<TextBlock Grid.Column="1" VerticalAlignment="Center"
FontSize="{TemplateBinding FontSize}"
x:Name="Placeholder" Visibility="Hidden"
Foreground="#9d9d9d" Text="{TemplateBinding Placeholder}" />
<TextBox x:Name="PART_ContentHost" Height="{TemplateBinding Height}"
Text="{TemplateBinding SelectedTime}"
Background="Transparent" Grid.Column="1"
BorderThickness="0" VerticalContentAlignment="Center" />
<Popup x:Name="PART_Popup" PlacementTarget="{Binding ElementName=PART_ContentHost}"
HorizontalOffset="-28"
Grid.ColumnSpan="3" AllowDrop="True" Width="186" Height="238">
<Popup.Resources>
<Style TargetType="Popup">
<Setter Property="AllowsTransparency" Value="True"/>
<Setter Property="PopupAnimation" Value="Fade"/>
<Setter Property="Placement" Value="Bottom" />
<Setter Property="Child">
<Setter.Value>
<Border Padding="2" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="10"/>
<RowDefinition/>
</Grid.RowDefinitions>
<!--Popup的内容-->
<Border Grid.Row="1" CornerRadius="4" Background="White" BorderThickness="1" BorderBrush="#d9d9d9">
<Border.Effect>
<DropShadowEffect Color="Black" Opacity="0.1" BlurRadius="10" ShadowDepth="0" Direction="0" />
</Border.Effect>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="38" />
</Grid.RowDefinitions>
<Border Margin="15 3 15 0" Height="32" VerticalAlignment="Center" BorderThickness="0 1" BorderBrush="#D9D9d9" />
<UniformGrid Columns="3">
<!--时-->
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="24" />
<RowDefinition />
<RowDefinition Height="24"/>
</Grid.RowDefinitions>
<Button x:Name="PART_HourUp" FocusManager.IsFocusScope="True">
<Viewbox Width="16" Height="16">
<Path Fill="#8d8d8d">
<Path.Data>
<Geometry>
M253.651376 655.446718c-6.503881 0-13.007763-2.16796-18.066337-7.226535-10.117149-10.117149-10.117149-26.015526 0-35.410021l231.971771-231.971771c10.117149-10.117149 23.847565-15.898377 39.023289-15.898377s28.183486 5.781228 39.023288 15.898377l231.249118 231.249118c10.117149 10.117149 10.117149 26.015526 0 35.410021-10.117149 10.117149-26.015526 10.117149-35.410021 0l-231.249118-231.249118c-2.16796-2.16796-4.335921-2.16796-5.781228 0l-232.694425 231.249118c-5.058574 5.058574-11.562456 7.949188-18.066337 7.949188z
</Geometry>
</Path.Data>
</Path>
</Viewbox>
</Button>
<Button x:Name="PART_HourDown" Grid.Row="2" FocusManager.IsFocusScope="True">
<Viewbox Width="16" Height="16">
<Path Fill="#8d8d8d">
<Path.Data>
<Geometry>
M508.025406 655.446718c-14.45307 0-28.183486-5.781228-39.023289-15.898376l-231.249118-231.249118c-10.117149-10.117149-10.117149-26.015526 0-36.132675s26.015526-10.117149 36.132675 0l231.249118 231.249118c2.16796 2.16796 4.335921 2.16796 5.781228 0l231.971771-231.971771c10.117149-10.117149 26.015526-10.117149 35.410021 0 10.117149 10.117149 10.117149 26.015526 0 36.132674l-231.971771 231.971772c-9.394495 10.117149-23.124912 15.898377-38.300635 15.898376z
</Geometry>
</Path.Data>
</Path>
</Viewbox>
</Button>
<ItemsControl x:Name="PART_HourItems" Grid.Row="1" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Height="28" VerticalAlignment="Center">
<TextBlock x:Name="ItemValue" Margin="5 0 0 0" FontSize="12" Foreground="#606266" FontWeight="Normal" HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding Value}"/>
</Border>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsActive}" Value="True">
<Setter TargetName="ItemValue" Property="Foreground" Value="#303133" />
<Setter TargetName="ItemValue" Property="FontWeight" Value="Black" />
</DataTrigger>
<DataTrigger Binding="{Binding IsActive}" Value="False">
<Setter TargetName="ItemValue" Property="Foreground" Value="#606266" />
<Setter TargetName="ItemValue" Property="FontWeight" Value="Normal" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
<!--分-->
<Grid Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="24" />
<RowDefinition />
<RowDefinition Height="24"/>
</Grid.RowDefinitions>
<Button x:Name="PART_MinuteUp" FocusManager.IsFocusScope="True" >
<Viewbox Width="16" Height="16">
<Path Fill="#8d8d8d">
<Path.Data>
<Geometry>
M253.651376 655.446718c-6.503881 0-13.007763-2.16796-18.066337-7.226535-10.117149-10.117149-10.117149-26.015526 0-35.410021l231.971771-231.971771c10.117149-10.117149 23.847565-15.898377 39.023289-15.898377s28.183486 5.781228 39.023288 15.898377l231.249118 231.249118c10.117149 10.117149 10.117149 26.015526 0 35.410021-10.117149 10.117149-26.015526 10.117149-35.410021 0l-231.249118-231.249118c-2.16796-2.16796-4.335921-2.16796-5.781228 0l-232.694425 231.249118c-5.058574 5.058574-11.562456 7.949188-18.066337 7.949188z
</Geometry>
</Path.Data>
</Path>
</Viewbox>
</Button>
<Button Grid.Row="2" x:Name="PART_MinuteDown" FocusManager.IsFocusScope="True" >
<Viewbox Width="16" Height="16">
<Path Fill="#8d8d8d">
<Path.Data>
<Geometry>
M508.025406 655.446718c-14.45307 0-28.183486-5.781228-39.023289-15.898376l-231.249118-231.249118c-10.117149-10.117149-10.117149-26.015526 0-36.132675s26.015526-10.117149 36.132675 0l231.249118 231.249118c2.16796 2.16796 4.335921 2.16796 5.781228 0l231.971771-231.971771c10.117149-10.117149 26.015526-10.117149 35.410021 0 10.117149 10.117149 10.117149 26.015526 0 36.132674l-231.971771 231.971772c-9.394495 10.117149-23.124912 15.898377-38.300635 15.898376z
</Geometry>
</Path.Data>
</Path>
</Viewbox>
</Button>
<ItemsControl x:Name="PART_MinuteItems" Grid.Row="1" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Height="28" VerticalAlignment="Center">
<TextBlock x:Name="ItemValue" Margin="5 0 0 0" FontSize="12" Foreground="#606266" FontWeight="Normal" HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding Value}"/>
</Border>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsActive}" Value="True">
<Setter TargetName="ItemValue" Property="Foreground" Value="#303133" />
<Setter TargetName="ItemValue" Property="FontWeight" Value="Black" />
</DataTrigger>
<DataTrigger Binding="{Binding IsActive}" Value="False">
<Setter TargetName="ItemValue" Property="Foreground" Value="#606266" />
<Setter TargetName="ItemValue" Property="FontWeight" Value="Normal" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
<!--秒-->
<Grid Grid.Column="2">
<Grid.RowDefinitions>
<RowDefinition Height="24" />
<RowDefinition />
<RowDefinition Height="24"/>
</Grid.RowDefinitions>
<Button x:Name="PART_SecondUp" FocusManager.IsFocusScope="True" >
<Viewbox Width="16" Height="16">
<Path Fill="#8d8d8d">
<Path.Data>
<Geometry>
M253.651376 655.446718c-6.503881 0-13.007763-2.16796-18.066337-7.226535-10.117149-10.117149-10.117149-26.015526 0-35.410021l231.971771-231.971771c10.117149-10.117149 23.847565-15.898377 39.023289-15.898377s28.183486 5.781228 39.023288 15.898377l231.249118 231.249118c10.117149 10.117149 10.117149 26.015526 0 35.410021-10.117149 10.117149-26.015526 10.117149-35.410021 0l-231.249118-231.249118c-2.16796-2.16796-4.335921-2.16796-5.781228 0l-232.694425 231.249118c-5.058574 5.058574-11.562456 7.949188-18.066337 7.949188z
</Geometry>
</Path.Data>
</Path>
</Viewbox>
</Button>
<Button Grid.Row="2" Name="PART_SecondDown" FocusManager.IsFocusScope="True" >
<Viewbox Width="16" Height="16">
<Path Fill="#8d8d8d">
<Path.Data>
<Geometry>
M508.025406 655.446718c-14.45307 0-28.183486-5.781228-39.023289-15.898376l-231.249118-231.249118c-10.117149-10.117149-10.117149-26.015526 0-36.132675s26.015526-10.117149 36.132675 0l231.249118 231.249118c2.16796 2.16796 4.335921 2.16796 5.781228 0l231.971771-231.971771c10.117149-10.117149 26.015526-10.117149 35.410021 0 10.117149 10.117149 10.117149 26.015526 0 36.132674l-231.971771 231.971772c-9.394495 10.117149-23.124912 15.898377-38.300635 15.898376z
</Geometry>
</Path.Data>
</Path>
</Viewbox>
</Button>
<ItemsControl x:Name="PART_SecondItems" Grid.Row="1" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Height="28" VerticalAlignment="Center">
<TextBlock x:Name="ItemValue" Margin="5 0 0 0" FontSize="12" Foreground="#606266" FontWeight="Normal" HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding Value}"/>
</Border>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsActive}" Value="True">
<Setter TargetName="ItemValue" Property="Foreground" Value="#303133" />
<Setter TargetName="ItemValue" Property="FontWeight" Value="Black" />
</DataTrigger>
<DataTrigger Binding="{Binding IsActive}" Value="False">
<Setter TargetName="ItemValue" Property="Foreground" Value="#606266" />
<Setter TargetName="ItemValue" Property="FontWeight" Value="Normal" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</UniformGrid>
<Border Grid.Row="1" BorderThickness="0 1 0 0" BorderBrush="#d8d8d8" Padding="4" Margin="0 5 0 0" >
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
<Button x:Name="PART_Cancel" Content="取消" Foreground="#303133" FontSize="12" Margin="5 0" />
<Button x:Name="PART_Submit" Content="确定" FontWeight="Black" Foreground="#409eff" FontSize="12" Margin="5 0" />
</StackPanel>
</Border>
</Grid>
</Border>
<!--三角形指示器-->
<Grid Width="Auto" Margin="25 0 0 0">
<Polyline VerticalAlignment="Bottom" Margin="0 0 0 -1" Points="0,12 6,6 12,12" Stroke="#d9d9d9" StrokeThickness="1" Fill="White"/>
<Polyline VerticalAlignment="Bottom" Margin="0 0 0 -1" Points="0,12 6,6 12,12" Stroke="#d9d9d9" StrokeThickness="1" Fill="White"/>
<Polyline VerticalAlignment="Bottom" Margin="0 0 0 -1" Points="0,12 6,6 12,12" Stroke="#d9d9d9" StrokeThickness="1" Fill="White"/>
</Grid>
</Grid>
</Border>
</Setter.Value>
</Setter>
</Style>
</Popup.Resources>
</Popup>
<Button Grid.Column="2" Name="PART_Clear" Margin="25 0 0 0">
<Viewbox Width="14" Height="14">
<Path Fill="#8d8d8d">
<Path.Data>
<Geometry>
M963.9424 520.17664c-1.792 238.32064-192.47104 436.28032-431.04256 445.2352-237.76256 8.92416-443.0592-180.59776-459.008-416.5376-16.0256-237.02016 166.00576-449.23392 401.73056-472.27904 236.04736-23.07584 454.79936 151.43936 484.9152 386.6368 2.41152 18.87744 3.25632 37.92384 3.4048 56.94464 0.25088 33.00352 51.45088 33.024 51.2 0-1.75616-234.1376-168.20736-439.81824-398.31552-486.90688C386.97472-13.76768 149.35552 113.76128 59.76064 329.97888c-90.78784 219.10528-9.93792 472.9344 185.22112 604.7744 195.7888 132.26496 465.39264 98.176 629.39648-68.16256 90.53696-91.83232 139.79648-218.08128 140.75904-346.4192 0.25088-33.024-50.94912-32.9984-51.19488 0.00512z
M339.26656 735.56992l394.63936-394.64448c23.36768-23.36768-12.83584-59.5712-36.1984-36.20352l-394.64448 394.6496c-23.36768 23.36256 12.83584 59.56608 36.20352 36.1984z
M733.90592 699.37152l-394.63936-394.6496c-23.36768-23.36256-59.5712 12.83584-36.20352 36.20352 131.54816 131.54816 263.0912 263.10144 394.64448 394.64448 23.36256 23.36768 59.56608-12.83584 36.1984-36.1984z
</Geometry>
</Path.Data>
</Path>
</Viewbox>
</Button>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="BorderBrush" Value="#c0c4cc" />
</Trigger>
<Trigger SourceName="PART_ContentHost" Property="IsFocused" Value="True">
<Setter Property="BorderBrush" Value="#409eff" />
<Setter TargetName="PART_Popup" Property="IsOpen" Value="True" />
</Trigger>
<Trigger SourceName="PART_ContentHost" Property="Text" Value="">
<Setter TargetName="PART_Clear" Property="Visibility" Value="Hidden" />
<Setter TargetName="Placeholder" Property="Visibility" Value="Visible" />
</Trigger>
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard>
<Storyboard>
<ThicknessAnimation Storyboard.TargetName="PART_Clear"
Storyboard.TargetProperty="Margin"
To="0" Duration="0:0:.1" />
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="PART_Clear" Storyboard.TargetProperty="Opacity">
<SplineDoubleKeyFrame KeyTime="0:0:0.1" Value="1" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<BeginStoryboard>
<Storyboard>
<Storyboard>
<ThicknessAnimation Storyboard.TargetName="PART_Clear"
Storyboard.TargetProperty="Margin"
To="25 0 0 0" Duration="0:0:0.1"/>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="PART_Clear" Storyboard.TargetProperty="Opacity">
<SplineDoubleKeyFrame KeyTime="0:0:0.1" Value="0" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
TimePicker.cs部分的代码
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
namespace WpfApp1
{
public class ValueItem:INotifyPropertyChanged
{
private string _value;
public string Value
{
get { return _value; }
set
{
_value = value;
OnPropertyChanged(nameof(Value));
}
}
private bool _isActive;
public bool IsActive
{
get { return _isActive; }
set
{
_isActive = value;
OnPropertyChanged(nameof(IsActive));
}
}
public event PropertyChangedEventHandler? PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(propertyName));
}
}
public class TimePicker : Control
{
static TimePicker()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(TimePicker), new FrameworkPropertyMetadata(typeof(TimePicker)));
}
public string Placeholder
{
get { return (string)GetValue(PlaceholderProperty); }
set { SetValue(PlaceholderProperty, value); }
}
public static readonly DependencyProperty PlaceholderProperty =
DependencyProperty.Register("Placeholder", typeof(string), typeof(TimePicker), new PropertyMetadata("请选择时间"));
public string SelectedTime
{
get { return (string)GetValue(SelectedTimeProperty); }
set { SetValue(SelectedTimeProperty, value); }
}
public static readonly DependencyProperty SelectedTimeProperty =
DependencyProperty.Register("SelectedTime", typeof(string), typeof(TimePicker), new PropertyMetadata(""));
public ObservableCollection<ValueItem> Hours = new ObservableCollection<ValueItem>();
public ObservableCollection<ValueItem> Minutes = new ObservableCollection<ValueItem>();
public ObservableCollection<ValueItem> Seconds = new ObservableCollection<ValueItem>();
public override void OnApplyTemplate()
{
var lastSelectedTime = SelectedTime;
var popup = GetTemplateChild("PART_Popup") as Popup;
var txtBox = GetTemplateChild("PART_ContentHost") as TextBox;
if (popup != null)
{
var hourUpBtn = LogicalTreeHelper.FindLogicalNode(popup?.Child, "PART_HourUp") as Button;
var hourDownBtn = LogicalTreeHelper.FindLogicalNode(popup?.Child, "PART_HourDown") as Button;
var minuteUpBtn = LogicalTreeHelper.FindLogicalNode(popup?.Child, "PART_MinuteUp") as Button;
var minuteDownBtn = LogicalTreeHelper.FindLogicalNode(popup?.Child, "PART_MinuteDown") as Button;
var secondUpBtn = LogicalTreeHelper.FindLogicalNode(popup?.Child, "PART_SecondUp") as Button;
var secondDownBtn = LogicalTreeHelper.FindLogicalNode(popup?.Child, "PART_SecondDown") as Button;
var clearBtn = GetTemplateChild("PART_Clear") as Button;
var submitBtn = LogicalTreeHelper.FindLogicalNode(popup?.Child, "PART_Submit") as Button;
var cancelBtn = LogicalTreeHelper.FindLogicalNode(popup?.Child, "PART_Cancel") as Button;
var hourItems = LogicalTreeHelper.FindLogicalNode(popup?.Child, "PART_HourItems") as ItemsControl;
if(hourItems != null)
{
hourItems.ItemsSource = Hours;
hourItems.MouseEnter += (sender, e) =>
{
txtBox?.Select(0,2);
};
}
var minuteItems = LogicalTreeHelper.FindLogicalNode(popup?.Child, "PART_MinuteItems") as ItemsControl;
if (minuteItems != null)
{
minuteItems.ItemsSource = Minutes;
minuteItems.MouseEnter += (sender, e) =>
{
txtBox?.Select(3, 2);
};
}
var secondItems = LogicalTreeHelper.FindLogicalNode(popup?.Child, "PART_SecondItems") as ItemsControl;
if (secondItems != null)
{
secondItems.ItemsSource = Seconds;
secondItems.MouseEnter += (sender, e) =>
{
txtBox?.Select(6, 2);
};
}
if (hourUpBtn != null)
{
hourUpBtn.Click += (sender, e) =>
{
var temp = Hours.Last();
Hours.RemoveAt(Hours.Count - 1);
Hours.Insert(0, temp);
Hours[1].IsActive = false;
Hours[2].IsActive = true;
Hours[3].IsActive = false;
SelectedTime = $"{Hours[2].Value}:{Minutes[2].Value}:{Seconds[2].Value}";
txtBox?.Select(0, 2);
};
}
if (hourDownBtn != null)
{
hourDownBtn.Click += (sender, e) =>
{
var temp = Hours.First();
Hours.RemoveAt(0);
Hours.Add(temp);
Hours[1].IsActive = false;
Hours[2].IsActive = true;
Hours[3].IsActive = false;
SelectedTime = $"{Hours[2].Value}:{Minutes[2].Value}:{Seconds[2].Value}";
txtBox?.Select(0, 2);
};
}
if (minuteUpBtn != null)
{
minuteUpBtn.Click += (sender, e) =>
{
var temp = Minutes.Last();
Minutes.RemoveAt(Minutes.Count - 1);
Minutes.Insert(0, temp);
Minutes[1].IsActive = false;
Minutes[2].IsActive = true;
Minutes[3].IsActive = false;
SelectedTime = $"{Hours[2].Value}:{Minutes[2].Value}:{Seconds[2].Value}";
txtBox?.Select(3, 2);
};
}
if (minuteDownBtn != null)
{
minuteDownBtn.Click += (sender, e) =>
{
var temp = Minutes.First();
Minutes.RemoveAt(0);
Minutes.Add(temp);
Minutes[1].IsActive = false;
Minutes[2].IsActive = true;
Minutes[3].IsActive = false;
SelectedTime = $"{Hours[2].Value}:{Minutes[2].Value}:{Seconds[2].Value}";
txtBox?.Select(3, 2);
};
}
if (secondUpBtn != null)
{
secondUpBtn.Click += (sender, e) =>
{
var temp = Seconds.Last();
Seconds.RemoveAt(Seconds.Count - 1);
Seconds.Insert(0, temp);
Seconds[1].IsActive = false;
Seconds[2].IsActive = true;
Seconds[3].IsActive = false;
SelectedTime = $"{Hours[2].Value}:{Minutes[2].Value}:{Seconds[2].Value}";
txtBox?.Select(6, 2);
};
}
if (secondDownBtn != null)
{
secondDownBtn.Click += (sender, e) =>
{
var temp = Seconds.First();
Seconds.RemoveAt(0);
Seconds.Add(temp);
Seconds[1].IsActive = false;
Seconds[2].IsActive = true;
Seconds[3].IsActive = false;
SelectedTime = $"{Hours[2].Value}:{Minutes[2].Value}:{Seconds[2].Value}";
txtBox?.Select(6,2);
};
}
if (submitBtn != null)
{
submitBtn.Click += (sender, e) =>
{
SelectedTime = $"{Hours[2].Value}:{Minutes[2].Value}:{Seconds[2].Value}";
lastSelectedTime = SelectedTime;
};
}
if (cancelBtn !=null)
{
cancelBtn.Click += (sender, e) =>
{
SelectedTime = lastSelectedTime;
};
}
if (clearBtn != null)
{
clearBtn.Click += (sender, e) =>
{
SelectedTime = "";
lastSelectedTime = SelectedTime;
};
}
txtBox.PreviewGotKeyboardFocus += (sender, e) =>
{
txtBox.Select(0,2);
};
popup.Opened += (sender, e) =>
{
Hours.Clear();
Minutes.Clear();
Seconds.Clear();
for (int i = 0; i < 24; i++)
{
Hours.Add(new ValueItem
{
Value = i.ToString("00"),
IsActive = false
});
}
for (int i = 0; i < 60; i++)
{
Minutes.Add(new ValueItem
{
Value = i.ToString("00"),
IsActive = false
});
Seconds.Add(new ValueItem
{
Value = i.ToString("00"),
IsActive = false
});
}
if (!string.IsNullOrWhiteSpace(SelectedTime))
{
var time = SelectedTime.Split(":");
var targetHour = Hours.FirstOrDefault(it => it.Value == time[0]);
if (targetHour != null)
{
targetHour.IsActive = true;
var hourIndex = Hours.IndexOf(targetHour);
for (int i = 0; i < hourIndex - 2; i++)
{
var hourTemp = Hours[0];
Hours.RemoveAt(0);
Hours.Add(hourTemp);
}
}
var targetMinute = Minutes.FirstOrDefault(it => it.Value == time[1]);
if (targetMinute != null)
{
targetMinute.IsActive = true;
var minuteIndex = Minutes.IndexOf(targetMinute);
for (int i = 0; i < minuteIndex - 2; i++)
{
var minuteTemp = Minutes[0];
Minutes.RemoveAt(0);
Minutes.Add(minuteTemp);
}
}
var targetSecond = Seconds.FirstOrDefault(it => it.Value == time[2]);
if (targetSecond != null)
{
targetSecond.IsActive = true;
var secondIndex = Seconds.IndexOf(targetSecond);
for (int i = 0; i < secondIndex - 2; i++)
{
var secondTemp = Seconds[0];
Seconds.RemoveAt(0);
Seconds.Add(secondTemp);
}
}
}
else
{
Hours[2].IsActive = true;
Minutes[2].IsActive = true;
Seconds[2].IsActive = true;
}
};
}
}
}
}
三、使用部分
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<StackPanel>
<local:TimePicker Margin="50" SelectedTime="15:04:03" />
</StackPanel>
</Window>