Остановка DispatcherTimer нажатием кнопки

Когда я нажимаю кнопку «Стоп», мой таймер продолжает обратный отсчет, хотя я говорю ему остановиться.

Мой текущий соответствующий код:

Я называю таймеры здесь, так как мне нужно получить к ним доступ для кнопки «остановить/запустить все».

namespace Row_Interface
{
    public partial class MainWindow : Window
    {
        //Declare the timers here, so the stop all button can access them as well
        DispatcherTimer motorTimer_1 = new DispatcherTimer();
        TimeSpan motorCycleTime_1 = TimeSpan.FromSeconds(0);

Когда я нажимаю кнопку включения, вызывается метод IndividualTestStart и передаются соответствующие параметры:

public void motorOnBtn_1_Click(object sender, RoutedEventArgs e)
        {
            IndividualTestStart(motorOnBtn_1, motorOffBtn_1, motorTimer_1, motorCycleTime_1, timeUntilmotorCycle_1, motorTestCycles_1);
        }

Когда я нажимаю кнопку выключения, я хочу остановить этот таймер, чтобы цикл никогда не заканчивался:

        private void motorOffBtn_1_Click(object sender, RoutedEventArgs e)
        {
            motorTimer_1.Stop();
            motorOnBtn_1.IsEnabled = true; //Enables the start test button
            motorOffBtn_1.IsEnabled = false; //Disables the stop test button

        }

Это вызывается, когда я нажимаю «Пуск». Со временем у меня будет что-то похожее для кнопки остановки, но я делаю все шаг за шагом:

private void IndividualTestStart(Button startButton, Button stopButton, DispatcherTimer dispatcherTimer, TimeSpan timeSpan, TextBox timeRemaining, TextBox cycleCount)
        {
            stopButton.IsEnabled = true; //Enables the stop button

            //Set the time to run. This will be set from the database eventually.
            timeSpan = TimeSpan.FromSeconds(10);

            //Set up the new timer. Updated every second.
            dispatcherTimer = new DispatcherTimer(new TimeSpan(0, 0, 1), DispatcherPriority.Normal, delegate
            {
                timeRemaining.Text = timeSpan.ToString("c"); //Sets the text in the textbox to the time remaining in the timer
                startButton.IsEnabled = false; //Disables the start test button once the test is started
                if (timeSpan == TimeSpan.Zero) //Checks to seee if the time has run out
                {
                    dispatcherTimer.Stop(); //Stops the timer once the time has run out
                    startButton.IsEnabled = true; //Enables the start test button
                    int initialCycleCount = 0;
                    initialCycleCount++;
                    cycleCount.Text = initialCycleCount.ToString();
                    stopButton.IsEnabled = false;//Disables the stop button

                }
                timeSpan = timeSpan.Add(TimeSpan.FromSeconds(-1)); //Subtracts one second each time the timer "ticks"
            }, Application.Current.Dispatcher);  //runs within the UI thread

            dispatcherTimer.Start(); //Starts the timer 
        }
}

Когда я нажимаю кнопку «Стоп», я ожидаю, что таймер в текстовом поле перестанет отсчитывать. Тем не менее, он просто продолжает тикать. Когда я нажимаю «Стоп», кнопка «Пуск» снова активируется, поэтому я знаю, что она запускает код в обработчике событий. Но это не останавливает таймер.

Не запускать новый таймер сейчас. Новый код:

        public void motorOnBtn_1_Click(object sender, RoutedEventArgs e)
        {
            IndividualTestStart(motorOnBtn_1, motorOffBtn_1, motorTimer_1, motorCycleTime_1, timeUntilmotorCycle_1, motorTestCycles_1);
        }

        private void IndividualTestStart(Button startButton, Button stopButton, DispatcherTimer dispatcherTimer, TimeSpan timeSpan, TextBox timeRemaining, TextBox cycleCount)
        {
            stopButton.IsEnabled = true; //Enables the stop button

            //Set the time to run. This will be set from the database eventually.
            timeSpan = TimeSpan.FromSeconds(10);

            {
                timeRemaining.Text = timeSpan.ToString("c"); //Sets the text in the textbox to the time remaining in the timer
                startButton.IsEnabled = false; //Disables the start test button once the test is started
                if (timeSpan == TimeSpan.Zero) //Checks to seee if the time has run out
                {
                    dispatcherTimer.Stop(); //Stops the timer once the time has run out
                    startButton.IsEnabled = true; //Enables the start test button
                    int initialCycleCount = 0;
                    initialCycleCount++;
                    cycleCount.Text = initialCycleCount.ToString();
                    stopButton.IsEnabled = false;//Disables the stop button

                }
                timeSpan = timeSpan.Add(TimeSpan.FromSeconds(-1)); //Subtracts one second each time the timer "ticks"
            };  //runs within the UI thread

            dispatcherTimer.Start(); //Starts the timer 
        }

Вы передаете motorTimer_1 в IndividualTestStart() в качестве параметра dispatcherTimer. Затем вы заменяете значение параметра вновь созданным DispatcherTimer, который вы инициализируете и запускаете. motorTimer_1 никогда не запускается и никогда не является ссылкой на DispatcherTimer, который фактически запущен.

15ee8f99-57ff-4f92-890c-b56153 01.05.2019 17:38

А, это имеет смысл. Однако я удалил замену значения этого параметра, и теперь таймер вообще не будет тикать. Работаю над этим сейчас.

Schreiberito 01.05.2019 18:45

Остановитесь и обдумайте это. Как вы теперь инициализируете DispatcherTimer motorTimer_1? Вы даете ему интервал, приоритет, делегата, диспетчера? Где? Как? Вы создаете новый DispatcherTimer так же, как и раньше, но просто выбрасываете его вместо того, чтобы назначать параметру? Давайте посмотрим новый код.

15ee8f99-57ff-4f92-890c-b56153 01.05.2019 18:53

```` timeSpan = TimeSpan.FromSeconds(10); { timeRemaining.Text = timeSpan.ToString("c"); //Устанавливает текст в текстовом поле на оставшееся время таймера if (timeSpan == TimeSpan.Zero) { dispatcherTimer.Stop(); } timeSpan = timeSpan.Add(TimeSpan.FromSeconds(-1)); }; dispatcherTimer.Interval = новый интервал времени (0, 0, 1); диспетчерТаймер.Старт(); //Запускаем таймер } ````

Schreiberito 01.05.2019 19:02

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

15ee8f99-57ff-4f92-890c-b56153 01.05.2019 19:02

Что ж, форматирование не сработало, возможно, мне просто нужно опубликовать его в вопросе, чтобы сделать его читабельным. У меня установлен интервал, но нет приоритета, делегата или диспетчера. Похоже, мне нужно копаться в этом больше.

Schreiberito 01.05.2019 19:03

Вы можете отредактировать этот вопрос. Вам не нужно ни во что копаться. Просто установите свойства того же самого DispatcherTimer, который вы фактически используете, и вызовите Stop() для этого вместо другого. \

15ee8f99-57ff-4f92-890c-b56153 01.05.2019 19:03

Я попытался добавить свойства вверху: DispatcherTimer cooktopTimer_1 = new DispatcherTimer (new TimeSpan (0, 0, 1), DispatcherPriority.Normal, делегат {}, Application.Current.Dispatcher); Тем не менее, все еще просто придерживается 10, хотя.

Schreiberito 01.05.2019 19:13

Ну, если ты не сделаешь, как я прошу, к сожалению, я не могу тебе помочь. Естественно, никто не может отлаживать программу, когда все, что они видят, это крошечные фрагменты кода без контекста. Удачи с вашей проблемой. Одна вещь, однако, заключается в том, что я бы посоветовал вам использовать делегат, в котором есть некоторый код, если вы хотите, чтобы что-то происходило при вызове делегата.

15ee8f99-57ff-4f92-890c-b56153 01.05.2019 19:14

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

Schreiberito 01.05.2019 19:48

Так что дайте ему то, что ему нужно, когда вы его создаете. Почему вы чувствуете необходимость создать его неправильно, а затем передать в этот метод? Что вам нужно сделать: Когда кто-то попытается запустить его, вызовите метод, который проверяет, существует ли он еще. Если нет, создайте его правильно и назначать новый экземпляр для motorTimer_1. Как только вы убедитесь, что он существует, запустите его. Собираетесь ли вы использовать несколько одинаковых таймеров (motorTimer_2 и т. д.)?

15ee8f99-57ff-4f92-890c-b56153 01.05.2019 19:54

Я создаю 8 разных экземпляров таймеров, абсолютно одинаковых, за исключением параметров, которые я передаю в этот метод (кнопка, которая запускает/останавливает его, имя таймера, временной интервал и текстовые поля, которые он обновляет). Причина, по которой я создаю его «неправильным», заключается в том, что я впервые работал с таймерами в C#, и все учебники, которые я нашел, чрезвычайно просты для одного таймера, полностью содержащегося в одном методе. Насколько я понимаю, я не могу создать таймер внутри метода, потому что у меня есть другой метод (Остановить все), который также должен получить к ним доступ.

Schreiberito 01.05.2019 20:07

Поэтому создавайте их и храните ссылки где-нибудь. Смотрите мой ответ.

15ee8f99-57ff-4f92-890c-b56153 01.05.2019 20:09
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
13
547
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема в вашем коде заключается в том, что вы инициализируете motorTimer_1 с помощью DispatcherTimer, который ничего не делает, затем вы передаете motorTimer_1 в качестве параметра dispatcherTimer, а затем заменяете значение параметра вновь созданным другим DispatcherTimer.

Новый таймер работает нормально, но когда вы вызываете стоп на motorTimer_1, ничего не происходит, потому что работает не тот. Вы могли бы просто присвоить новый DispatcherTimer непосредственно motorTimer_1 в IndividualTestStart(), но вам пришлось очень постараться параметризовать все в IndividualTestStart(), чтобы он мог работать с разными DispatcherTimers.

Вместо этого мы сделаем следующее: нет причин нужно передать в DispatcherTimer. IndividualTestStart() должен создать DispatcherTimer, чтобы инициализировать его. Хорошо, давайте работать с этим. Он создаст новый и вернуть его.

private DispatcherTimer IndividualTestStart(Button startButton, Button stopButton, 
    TimeSpan timeSpan, TextBox timeRemaining, TextBox cycleCount)
{
    stopButton.IsEnabled = true; //Enables the stop button

    //Set the time to run. This will be set from the database eventually.
    timeSpan = TimeSpan.FromSeconds(10);

    //  Set up the new timer. Updated every second.
    var dispatcherTimer = new DispatcherTimer(new TimeSpan(0, 0, 1), DispatcherPriority.Normal, delegate
    {
        timeRemaining.Text = timeSpan.ToString("c"); //Sets the text in the textbox to the time remaining in the timer
        startButton.IsEnabled = false; //Disables the start test button once the test is started
        if (timeSpan == TimeSpan.Zero) //Checks to seee if the time has run out
        {
            dispatcherTimer.Stop(); //Stops the timer once the time has run out
            startButton.IsEnabled = true; //Enables the start test button
            int initialCycleCount = 0;
            initialCycleCount++;
            cycleCount.Text = initialCycleCount.ToString();
            stopButton.IsEnabled = false;//Disables the stop button

        }
        timeSpan = timeSpan.Add(TimeSpan.FromSeconds(-1)); //Subtracts one second each time the timer "ticks"
    }, Application.Current.Dispatcher);  //runs within the UI thread

    dispatcherTimer.Start(); //Starts the timer 

    return dispatcherTimer;
}

public void motorOnBtn_1_Click(object sender, RoutedEventArgs e)
{
    if (motorTimer_1 == null)
    {
        //  Create/initialize a new timer and assign it to motorTimer_1
        motorTimer_1 = IndividualTestStart(motorOnBtn_1, motorOffBtn_1, 
            motorCycleTime_1, timeUntilmotorCycle_1, motorTestCycles_1);
    }
    else
    {
        //  It's already there, just start it. 
        motorTimer_1.Start();
    }
}

Поскольку это WPF, вам нужно написать класс модели представления TimerThing (придумайте имя получше), которому принадлежит DispatcherTimer, две команды для его запуска и остановки, а также общедоступное логическое свойство, указывающее, запущено оно или нет. IndividualTestStart() должен быть методом этого класса. Родительская модель представления будет иметь ObservableCollection<TimerThing>, содержащую произвольное количество TimerThing, которые будут отображаться в ItemsControl с ItemTemplate, который создает кнопки, привязанные к командам Start и Stop. Приведенный выше код будет выглядеть совсем по-другому, так как ни один код C# ничего не знает о кнопках: вместо этого кнопки в шаблоне элемента XAML будут включаться/отключаться с помощью привязок.

Я начну работать над внедрением этого в свой код, спасибо! Между тем, это вызывает вопрос. У меня сложилось впечатление, что если вы создали таймер в методе, вы не сможете получить доступ к этому таймеру в другом методе. Вот почему я создал таймеры в начале кода вне методов. Я предполагаю, что это не так, и я могу получить доступ к таймеру в любом месте, пока я обращаюсь к нему по имени?

Schreiberito 01.05.2019 20:15

@Schreiberito Пожалуйста, смотрите исправленный код в motorOnBtn_1_Click, в начальной версии было серьезное упущение, которое все сломало.

15ee8f99-57ff-4f92-890c-b56153 01.05.2019 20:21

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

Schreiberito 01.05.2019 20:43

Общий термин для всего, что связано с коллекциями и шаблонами данных, - «MVVM» или «шаблон Model/View/Viewmodel». Кривая обучения крутая, но очень мощная, и многие люди здесь могут помочь вам с трудностями. Повеселись.

15ee8f99-57ff-4f92-890c-b56153 01.05.2019 20:45

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