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