【问题标题】:Problematic if-Statement有问题的 if 语句
【发布时间】:2015-01-05 08:00:17
【问题描述】:

我曾尝试过两到三遍这个问题,但未能正确地解决这个问题,所以我想再试一次。我正在制作一个训练秒表应用程序。该应用程序的功能是计算10秒,让学员有10秒的准备时间。一旦该时间过去,它计为 20 秒,受训者在 20 秒内进行了艰苦的锻炼。之后,有 10 秒的休息时间。然后它循环回到 20 秒的锻炼并继续这个循环 8 轮。

我的问题是它会开始 10 秒准备,但随后会循环回到 10 秒计时器。出于某种原因,我的 if else 语句不断循环回到准备时间。 我在 if 语句中使用秒表和时间跨度。

private void timer_Tick(object sender, EventArgs e)
    {
        //throw new NotImplementedException();
        //timer timespan is more than zero, start stopwatch(get the prepare counter going)
        if (timerWatch.Elapsed < new TimeSpan(0, 0, 11))// if its 5sec
        {
            milllisecond = timerWatch.ElapsedMilliseconds;
            second = milllisecond / 1000;
            milllisecond = milllisecond % 1000;
            minute = second / 60;
            second = second % 60;
            hour = minute / 60;
            minute = minute % 60;
            txtblTime.Text = minute.ToString("00") + ":" + second.ToString("00");
        }
        else if (timerWatch.Elapsed >= new TimeSpan(0, 0, 10) && timerWatch.Elapsed < new TimeSpan(0, 0, 21))//more than 4sec
        {
            timerWatch.Restart();

            milllisecond = timerWatch.ElapsedMilliseconds;
            second = milllisecond / 1000;
            milllisecond = milllisecond % 1000;
            minute = second / 60;
            second = second % 60;
            hour = minute / 60;
            minute = minute % 60;
            txtblTime.Text = minute.ToString("00") + ":" + second.ToString("00");

            txtblPrepare.Visibility = System.Windows.Visibility.Collapsed;
            txtblGo.Visibility = System.Windows.Visibility.Visible;
        }
        else if (timerWatch.Elapsed < new TimeSpan(0, 0, 21))
        {
            timerWatch.Restart();

            milllisecond = timerWatch.ElapsedMilliseconds;
            second = milllisecond / 1000;
            milllisecond = milllisecond % 1000;
            minute = second / 60;
            second = second % 60;
            hour = minute / 60;
            minute = minute % 60;

            txtblTime.Text = minute.ToString("00") + ":" + second.ToString("00");
            txtblGo.Visibility = System.Windows.Visibility.Collapsed;
        }
        else
            txtblTime.Text = "Times Up!";                    
    }

【问题讨论】:

  • 为什么不使用 Enum 来跟踪状态或模式 {Prep, WorkOut, Rest} 并根据该类型的 var 设置计时器间隔。诸如切换控件之类的其他事情也可以作用于该值。这样,每当计时器关闭时,您就知道一个阶段已经结束并进入下一个阶段。也许添加一个None,直到他们开始循环/测试/竞赛。
  • 最好使用某种状态机设计问题,你正在尝试执行。去谷歌上查询。无论如何,您为什么要重新启动计时器。我认为这是导致问题的原因,因为计时器在第一种情况以外的情况下会重置。
  • 定时器实例的类是什么?
  • 你第三个 else-if 毫无意义。

标签: c# if-statement windows-phone-8


【解决方案1】:

您尝试实现的是所谓的finite-state machine。从计时器推断这台机器的状态使得代码难以理解和阅读。我会以更直接的方式存储状态。正如 Plutonix 所说,使用枚举

public enum TrainingState
{
    Stopped, // The state machine is not working yet or has finished its work.
    Preparing,
    Working,
    Resting
}

此外,您还需要一个循环次数计数器

private TrainingState _state = TrainingState.Stopped;
private int _roundNo;

现在您可以像这样制定状态转换

private void ChangeState()
{
    switch (_state) {
        case  TrainingState.Stopped:
            //TODO: Initialize and start the timer, display state
            _state = TrainingState.Preparing;
            break;
        case  TrainingState.Preparing:
            //TODO: Adjust timer intervall for working phase, display state
            _roundNo = 1; // We are going into the first round
           _state = TrainingState.Working;
            break;
        case  TrainingState.Working:
             //TODO: Adjust timer intervall for resting phase, display state
            _state = TrainingState.Resting;
            break;
        case  TrainingState.Resting:
            if (_roundNo == 8) {
                _state = TrainingState.Stopped;
                //TODO: stop timer, display state
            } else {
                //TODO: Adjust timer intervall for working phase, display state
                _roundNo++; // We are going into the next round
               _state = TrainingState.Working;
            }
            break;
    }
}

您必须在启动时和在timer_Tick 内部调用此方法。

private void timer_Tick(object sender, EventArgs e)
{
    ChangeState();
}

private void btnStart_Click(object sender, EventArgs e)
{
    ChangeState();
}

【讨论】:

  • 不好意思问一下,在timer_Tick的启动和内部怎么调用这个方法?
  • 我取决于你是如何开始的。如果您从按钮单击开始,请在按钮单击事件处理程序中调用 ChangeState();。否则在表单的构造函数中或在 Form_Load 事件中调用它。并在timer_Click 中致电ChangeState();
【解决方案2】:

以下是使用 Enum 跟踪阶段的要点。这似乎比跟踪秒表和 TimeSpan 更容易……当计时器响起时,情况就会发生变化。

private enum Phases
{
    Stopped,
    Prep,
    WorkOut,
    Rest
}

private Phases thisPhase;       // phase tracker
private int workOutCount;       // 8 cycle counter

private void Timer1_Tick(object sender, EventArgs e)
{
    Timer1.Enabled = false;

    // ToDo: Fiddle with controls as needed
    // also the durations...not sure if a new Prep
    // follows the final rest or if they are the same
    switch (thisPhase) {
        case Phases.Stopped:
            // start things off
            thisPhase = Phases.Prep;
            Timer1.Interval = 10000;
            // prep time
            break;

        case Phases.Prep:
            workOutCount = 1;
            thisPhase = Phases.WorkOut;
            Timer1.Interval = 20000;
            // work out time
            break;

        case Phases.WorkOut:
            thisPhase = Phases.Rest;
            Timer1.Interval = 10000;
            // rest time
            break;

        case Phases.Rest:
            workOutCount += 1;

            if (workOutCount == 8) {
                thisPhase = Phases.Prep;
                // perhaps to None, if there is an instruction timeout
                Timer1.Interval = 10000;
                // prep time
                // actually means 10sec rest + 10 prep before next workout task
            } else {
                // next workout starts in...
                Timer1.Interval = 10000;
                // prep time
            }

            break;
    }
    Timer1.Enabled = true;
}

从 VB 转换可能不完美,但它应该传达这个想法。

【讨论】:

    【解决方案3】:

    你正在使用

    timer.Restart()
    

    它重置了计时器,因此它再次执行第一个案例。查看Stopwatch 的 MSDN 文档。这个答案当然假设您使用 Stopwatch 类作为计时器。

    我认为,它至少会执行一次这些情况以重置计时器。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-09-15
      • 1970-01-01
      • 1970-01-01
      • 2012-11-19
      • 1970-01-01
      • 2017-02-11
      • 2014-01-23
      • 2021-06-08
      相关资源
      最近更新 更多