0

これは、Web サイト ( http://jobijoy.blogspot.com/2007/10/time-picker-user-control.html )から直接取得した C# コードです。誰かが WPF の TimePicker について質問するときに参照しますが、私はそれを移動しました。より整理するために少し。(このコードを実行して動作させる場合は、このサイトの XAML コードを KeyDown から PreviewKeyDown に変更する必要があります。時間、分、秒がライブで表示される 3 つのグリッドで、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;
        }
    }
}

Dependency や Binding はまだあまり得意ではありません。学習しているだけなので、理解できません。しかし、ここに問題があります。分または秒が 59/-59 を超えると、無限ループが発生します。その流れを説明します (少なくとも、私はここで多くのことを学んでいます!):

TimeControl オブジェクトが 0:59:00 にあり、分の TextBox にフォーカスしているときに上キーを押したとします。したがって、ロジックに従うと、PreviewKeyDown イベントに移動し、switch ステートメントによって this.Minutes++ に移動し、Minutes を取得して 59 と表示されるため、分を 60 に設定します。

これは、時間 (0) 分 (60) 秒 (0) を取得し、それに値を設定する分の OnTimeChanged をトリガーします。Value は TimeSpan であるため、これを 1:00:00 と解釈します。これはすばらしいことです。

したがって、これが設定されると、OnValueChanged がトリガーされ、Hours が 1 に設定され、すぐに Hours の OnTimeChanged が呼び出されます。この時点で、時間 (1) 分 (60) 秒 (0) を取得し、値をその値に設定します (これは 2:00:00 と解釈されます)。

Hours が大きくなりすぎて例外がスローされるまで、無限ループが発生します。これは、修正方法を理解するのに少し頭を悩ませています。「適切な」修正は何ですか?switch ステートメントの if ステートメント、または OnTimeChanged/OnValueChanged メソッドで修正できることはわかっていますが、依存関係を使用してそれを行うより良い方法があると確信しています。

4

2 に答える 2

0

簡単な修正:最初に分をリセットしてから時間を更新するように変更します。

//免責事項:まだコードを読んでいないので、間違っている可能性があります

于 2010-01-29T14:04:47.147 に答える
0

プロパティに違いがなければ、プロパティを設定する必要はありません。次のようにしてみてください。

private static void OnValueChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
    TimeControl control = obj as TimeControl;
    var ts =  (TimeSpan)e.NewValue;
    if(ts.Hours != control.Hours) control.Hours = ts.Hours;
    if(ts.Minutes != control.Minutes) control.Minutes = ts.Minutes;
    if(ts.Seconds != control.Seconds) control.Seconds = ts.Seconds;
}

通常、私はこのロジックをセッターに配置します。これは、データアクセスレイヤーで一般的に見られるものです...しかし、依存関係の呼び出しは引き続きそこで発生すると思うので、コードのこのイベントハンドラーで実行するのが最善です。

于 2010-01-29T14:10:17.757 に答える