这是直接来自网站 ( http://jobijoy.blogspot.com/2007/10/time-picker-user-control.html )的 C# 代码,当有人询问 WPF 的 TimePicker 时,每个人都会参考这些代码,尽管我将它移动了有点更有条理。(请注意,如果您尝试运行此代码以使用它:您必须在显示小时、分钟和秒的 3 个网格上将此站点上的 XAML 代码从 KeyDown 更改为 PreviewKeyDown,并将 TextBlocks 更改为每个网格到文本框)
public partial class TimeControl : UserControl
{
public TimeControl()
{
InitializeComponent();
}
public TimeSpan Value
{
get { return (TimeSpan)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(TimeSpan), typeof(TimeControl),
new UIPropertyMetadata(DateTime.Now.TimeOfDay, new PropertyChangedCallback(OnValueChanged)));
public int Hours
{
get { return (int)GetValue(HoursProperty); }
set { SetValue(HoursProperty, value); }
}
public static readonly DependencyProperty HoursProperty =
DependencyProperty.Register("Hours", typeof(int), typeof(TimeControl),
new UIPropertyMetadata(0, new PropertyChangedCallback(OnTimeChanged)));
public int Minutes
{
get { return (int)GetValue(MinutesProperty); }
set { SetValue(MinutesProperty, value); }
}
public static readonly DependencyProperty MinutesProperty =
DependencyProperty.Register("Minutes", typeof(int), typeof(TimeControl),
new UIPropertyMetadata(0, new PropertyChangedCallback(OnTimeChanged)));
public int Seconds
{
get { return (int)GetValue(SecondsProperty); }
set { SetValue(SecondsProperty, value); }
}
public static readonly DependencyProperty SecondsProperty =
DependencyProperty.Register("Seconds", typeof(int), typeof(TimeControl),
new UIPropertyMetadata(0, new PropertyChangedCallback(OnTimeChanged)));
private static void OnValueChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
TimeControl control = obj as TimeControl;
control.Hours = ((TimeSpan)e.NewValue).Hours;
control.Minutes = ((TimeSpan)e.NewValue).Minutes;
control.Seconds = ((TimeSpan)e.NewValue).Seconds;
}
private static void OnTimeChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
TimeControl control = obj as TimeControl;
control.Value = new TimeSpan(control.Hours, control.Minutes, control.Seconds);
}
private void Down(object sender, KeyEventArgs args)
{
switch (((Grid)sender).Name)
{
case "sec":
if (args.Key == Key.Up)
this.Seconds++;
if (args.Key == Key.Down)
this.Seconds--;
break;
case "min":
if (args.Key == Key.Up)
this.Minutes++;
if (args.Key == Key.Down)
this.Minutes--;
break;
case "hour":
if (args.Key == Key.Up)
this.Hours++;
if (args.Key == Key.Down)
this.Hours--;
break;
}
}
}
我对依赖或绑定还不是很好,我只是在学习它,这就是我无法弄清楚的原因。但问题是:当 Minutes 或 Seconds 超过 59/-59 时,就会出现无限循环。我将解释它的流程(至少我在这里学到了很多东西!):
假设 TimeControl 对象位于 0:59:00,我们在关注分钟 TextBox 时按下向上键。因此,按照逻辑,它转到 PreviewKeyDown 事件,switch 语句将我们带到 this.Minutes++,它获取 Minutes 并看到 59,因此将分钟设置为 60。
这会触发 OnTimeChanged for Minutes,它会获取 Hours (0) Minutes (60) Seconds (0) 并将 Value 设置为该值。由于 Value 是 TimeSpan,因此它将其解释为 1:00:00,这很好。
因此,一旦设置好,它就会触发 OnValueChanged,它将 Hours 设置为 1,这会立即回调 OnTimeChanged for Hours。此时,它获取小时 (1) 分钟 (60) 秒 (0) 并将 Value 设置为该值(解释为 2:00:00)。
现在我们有一个无限循环,直到 Hours 变得太大并引发异常。了解如何解决它有点过头了。什么是“适当的”修复?我知道可以使用 switch 语句中的 if 语句,甚至 OnTimeChanged/OnValueChanged 方法来修复它,但我确信有更好的方法来处理依赖项。