C# Сброс таймера обратного отсчета-DispatcherTimer- в приложении Windows Store

Я C# newbie_and в программировании в общем_ и я пытаюсь создать приложение математической викторины с таймером обратного отсчета.

Я генерирую уравнение каждый раз, когда пользователь нажимает кнопку запуска, и я даю ему максимум 60 секунд, чтобы ответить. Пользователь отвечает - является ли его ответ неправильным или правильным, не имеет значения_ и может ли он / она снова щелкнуть мышью для получения нового уравнения. Поэтому я хочу, чтобы таймер сбрасывался каждый раз, когда пользователю показывается новое случайное уравнение. До сих пор мне удавалось сбросить это значение только по истечении 60 секунд, но даже если это не работает должным образом, иногда отображается 60 или 58 секунд вместо 60.

Пока что чтение других вопросов мне не очень помогло, и таймер меня смущает. Я также принимаю предложения, чтобы сделать мой код проще и элегантнее.

Вот мой код:

EquationView.xaml.cs

public sealed partial class EquationView : Page
    {
        DispatcherTimer timer = new DispatcherTimer();
        int tick = 60;
        int result;

        public EquationView()
        {
            this.NavigationCacheMode = NavigationCacheMode.Enabled;
            this.InitializeComponent();
        }

        private void startButton_Click(object sender, RoutedEventArgs e)
        {
            // Once clicked then disabled
            startButton.IsEnabled = false;

            // Enable buttons required for answering 
            resultTextBox.IsEnabled = true;
            submitButton.IsEnabled = true;

            var viewModel = App.equation.GenerateEquation();
            this.DataContext = viewModel;
            result = App.equation.GetResult(viewModel);

            timer.Interval = new TimeSpan(0, 0, 0, 1);
            //timer.Tick += new EventHandler(timer_Tick);
            timer.Tick += timer_Tick;
            timer.Start();
            DateTime startTime = DateTime.Now;

            // Reset message label
            if (message.Text.Length > 0)
            {
                message.Text = "";
            }

            // Reset result text box
            if (resultTextBox.Text.Length > 0)
            {
                resultTextBox.Text = "";
            }
        }

        private void timer_Tick(object sender, object e)
        {
            Countdown.Text = tick + " second(s) ";
            if (tick > 0)
                tick--;
            else
            {
                Countdown.Text = "Times Up";
                timer.Stop();
                submitButton.IsEnabled = false;
                resultTextBox.IsEnabled = false;
                startButton.IsEnabled = true;
                tick = 60;
            }

        }

        private void submitButton_Click(object sender, RoutedEventArgs e)
        {
            timer.Stop();
            submitButton.IsEnabled = false;
            resultTextBox.IsEnabled = false;

            if (System.Text.RegularExpressions.Regex.IsMatch(resultTextBox.Text, "[^0-9]"))
            {
                MessageDialog msgDialog = new MessageDialog("Please enter only numbers.");
                msgDialog.ShowAsync();

                resultTextBox.Text.Remove(resultTextBox.Text.Length - 1);

                //Reset buttons to answer again
                submitButton.IsEnabled = true;
                resultTextBox.IsEnabled = true;
                timer.Start();
            }
            else
            {
                try
                {
                    int userinput = Int32.Parse(resultTextBox.Text);

                    if (userinput == result)
                    {
                        message.Text = "Bingo!";
                        App.player.UpdateScore();
                        startButton.IsEnabled = true;
                    }
                    else
                    {
                        message.Text = "Wrong, sorry...";  
                        startButton.IsEnabled = true;
                    }
                }
                catch (Exception ex)
                {
                    MessageDialog msgDialog = new MessageDialog(ex.Message);
                    msgDialog.ShowAsync();
                    submitButton.IsEnabled = true;
                    resultTextBox.IsEnabled = true;
                    timer.Start();
                }


            }
        }

1 ответ

Решение

Мне кажется, что у вас есть как минимум две существенные проблемы здесь. Во-первых, ваш таймер, скорее всего, даст пользователю более 60 секунд из-за неточности в планировщике потоков Windows (т. Е. Каждый тик будет происходить с интервалом чуть более 1 секунды). Другое (и более актуальное для вашего вопроса) то, что вы не сбрасываете tick значение до 60, кроме случаев, когда таймер истек.

Для последнего вопроса было бы лучше просто сбросить значение обратного отсчета при запуске таймера, а не пытаться вспомнить везде, где вы его остановили.

Чтобы исправить это и первую проблему, избавьтесь от tick поле и измените код так, чтобы он выглядел так:

    static readonly TimeSpan duration = TimeSpan.FromSeconds(60);
    System.Diagnostics.Stopwatch sw;

    private void startButton_Click(object sender, RoutedEventArgs e)
    {
        // Once clicked then disabled
        startButton.IsEnabled = false;

        // Enable buttons required for answering 
        resultTextBox.IsEnabled = true;
        submitButton.IsEnabled = true;

        var viewModel = App.equation.GenerateEquation();
        this.DataContext = viewModel;
        result = App.equation.GetResult(viewModel);

        sw = System.Diagnostics.Stopwatch.StartNew();
        timer.Interval = new TimeSpan(0, 0, 0, 1);
        timer.Tick += timer_Tick;
        timer.Start();

        // Reset message label
        if (message.Text.Length > 0)
        {
            message.Text = "";
        }

        // Reset result text box
        if (resultTextBox.Text.Length > 0)
        {
            resultTextBox.Text = "";
        }
    }

    private void timer_Tick(object sender, object e)
    {
        if (sw.Elapsed < duration)
        {
            Countdown.Text = (int)(duration - sw.Elapsed).TotalSeconds + " second(s) ";
        }
        else
        {
            Countdown.Text = "Times Up";
            timer.Stop();
            submitButton.IsEnabled = false;
            resultTextBox.IsEnabled = false;
            startButton.IsEnabled = true;
        }
    }

Таким образом, не будет иметь значения, когда именно произойдет тиковое событие, код все равно будет правильно вычислять фактическое оставшееся время и использовать его для отображения и для определения того, истекло ли время.

Другие вопросы по тегам