Вот код C # непосредственно с веб-сайта (http://jobijoy.blogspot.com/2007/10/time-picker-user-control.html), на который все ссылаются, когда кто-то спрашивает о TimePicker для WPF, хотя я немного переместил его, чтобы быть более организованным. (Обратите внимание, если вы мы пытаемся запустить этот код для работы с ним: необходимо изменить код XAML на этом сайте с KeyDown на PreviewKeyDown в 3 сетках, где отображаются часы, минуты и секунды, и изменить TextBlocks с каждой сеткой на TextBoxes)
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;
}
}
}
Я пока не очень хорошо разбираюсь в зависимости и связывании, я только учусь этому, поэтому не могу понять. Но вот проблема: когда минуты или секунды взяты за пределы 59 / -59, возникает бесконечный цикл. Я объясню, как это происходит (по крайней мере, я многому здесь учусь!):
Допустим, объект TimeControl находится в 0:59:00, и мы нажимаем клавишу «вверх», в то время как фокусируемся на минутном TextBox. Итак, следуя логике, она переходит к событию PreviewKeyDown, и оператор switch переводит нас к этому. Minutes ++, который получает Minutes и видит 59, поэтому устанавливает минут на 60.
Это вызывает OnTimeChanged для минут, который получает Hours (0) Minutes (60) Seconds (0) и устанавливает для него значение. Поскольку Value - это TimeSpan, он интерпретирует это как 1:00:00, и это здорово.
Итак, как только это установлено, он переключает OnValueChanged, который устанавливает Hours на 1, и это немедленно вызывает OnTimeChanged для Hours. В этот момент он получает Hours (1) Minutes (60) Seconds (0) и устанавливает значение в значение (которое интерпретируется как 2:00:00).
Теперь у нас есть бесконечный цикл, пока Часы не станут слишком большими и не сгенерируют исключение. Это немного над моей головой, чтобы понять, как это исправить. Что будет правильным решением? Я знаю, что это можно исправить с помощью операторов if в операторе switch или даже с помощью методов OnTimeChanged / OnValueChanged, но я уверен, что есть лучший способ сделать это с зависимостями.