Остановка 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 
        }

person Schreiberito    schedule 01.05.2019    source источник
comment
Вы передаете motorTimer_1 в IndividualTestStart() в качестве параметра dispatcherTimer. Затем вы заменяете значение параметра вновь созданным DispatcherTimer, который вы инициализируете и запускаете. motorTimer_1 никогда не запускается и никогда не является ссылкой на DispatcherTimer, который фактически запущен.   -  person 15ee8f99-57ff-4f92-890c-b56153    schedule 01.05.2019
comment
А, это имеет смысл. Однако я удалил замену значения этого параметра, и теперь таймер вообще не будет тикать. Работаю над этим сейчас.   -  person Schreiberito    schedule 01.05.2019
comment
Остановитесь и обдумайте это. Как вы теперь инициализируете DispatcherTimer motorTimer_1? Вы даете ему интервал, приоритет, делегата, диспетчера? Где? Как? Вы создаете новый DispatcherTimer так же, как и раньше, но просто выбрасываете его вместо того, чтобы назначать параметру? Давайте посмотрим новый код.   -  person 15ee8f99-57ff-4f92-890c-b56153    schedule 01.05.2019
comment
```` 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); диспетчерТаймер.Старт(); //Запускаем таймер } ````   -  person Schreiberito    schedule 01.05.2019
comment
Пожалуйста, добавьте его к вопросу, чтобы я мог его прочитать.   -  person 15ee8f99-57ff-4f92-890c-b56153    schedule 01.05.2019
comment
Что ж, форматирование не сработало, возможно, мне просто нужно опубликовать его в вопросе, чтобы сделать его читабельным. У меня установлен интервал, но нет приоритета, делегата или диспетчера. Похоже, мне нужно копаться в этом больше.   -  person Schreiberito    schedule 01.05.2019
comment
Вы можете отредактировать этот вопрос. Вам не нужно ни во что копаться. Просто установите свойства того же самого DispatcherTimer, который вы фактически используете, и вызовите Stop() для этого вместо другого. \   -  person 15ee8f99-57ff-4f92-890c-b56153    schedule 01.05.2019
comment
Я попытался добавить свойства сверху: DispatcherTimer cooktopTimer_1 = new DispatcherTimer (new TimeSpan (0, 0, 1), DispatcherPriority.Normal, делегат {}, Application.Current.Dispatcher); Тем не менее, все еще просто придерживается 10, хотя.   -  person Schreiberito    schedule 01.05.2019
comment
Ну, если ты не сделаешь, как я прошу, к сожалению, я не могу тебе помочь. Естественно, никто не может отлаживать программу, когда все, что они видят, это крошечные фрагменты кода без контекста. Удачи с вашей проблемой. Одна вещь, однако, заключается в том, что я бы посоветовал вам использовать делегат, в котором есть некоторый код, если вы хотите, чтобы что-то происходило при вызове делегата.   -  person 15ee8f99-57ff-4f92-890c-b56153    schedule 01.05.2019
comment
Я не совсем понимаю, о чем вы спрашиваете. Я учусь на ходу. Теперь у меня есть остальная часть кода, добавленная в нижней части вопроса. основываясь на том, что я знаю, я должен указать эти параметры при первой инициализации. Однако проблема в том, что я не могу дать ему параметры вне метода, поскольку делегат содержится внутри метода.   -  person Schreiberito    schedule 01.05.2019
comment
Так что дайте ему то, что ему нужно, когда вы его создаете. Почему вы чувствуете необходимость создать его неправильно, а затем передать в этот метод? Что вам нужно сделать: Когда кто-то попытается запустить его, вызовите метод, который проверяет, существует ли он еще. Если нет, создайте его должным образом и назначьте новый экземпляр для motorTimer_1. Как только вы убедитесь, что он существует, запустите его. Собираетесь ли вы использовать несколько одинаковых таймеров (motorTimer_2 и т. д.)?   -  person 15ee8f99-57ff-4f92-890c-b56153    schedule 01.05.2019
comment
Я создаю 8 разных экземпляров таймеров, абсолютно одинаковых, за исключением параметров, которые я передаю в этот метод (кнопка, которая запускает/останавливает его, имя таймера, временной интервал и текстовые поля, которые он обновляет). Причина, по которой я делаю это неправильно, заключается в том, что я впервые работал с таймерами в C#, и все учебники, которые я нашел, чрезвычайно просты для одного таймера, полностью содержащегося в одном методе. Насколько я понимаю, я не могу создать таймер внутри метода, потому что у меня есть другой метод (Остановить все), который также должен получить к ним доступ.   -  person Schreiberito    schedule 01.05.2019
comment
Поэтому создавайте их и храните ссылки где-нибудь. Смотрите мой ответ.   -  person 15ee8f99-57ff-4f92-890c-b56153    schedule 01.05.2019


Ответы (1)


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

Новый таймер работает нормально, но когда вы вызываете stop на 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 будут включаться/отключаться с помощью привязок.

person 15ee8f99-57ff-4f92-890c-b56153    schedule 01.05.2019
comment
Я начну работать над внедрением этого в свой код, спасибо! Между тем, это вызывает вопрос. У меня сложилось впечатление, что если вы создали таймер в методе, вы не сможете получить доступ к этому таймеру в другом методе. Вот почему я создал таймеры в начале кода вне методов. Я предполагаю, что это не так, и я могу получить доступ к таймеру в любом месте, пока я обращаюсь к нему по имени? - person Schreiberito; 01.05.2019
comment
@Schreiberito Пожалуйста, смотрите исправленный код в motorOnBtn_1_Click, в начальной версии было серьезное упущение, которое все сломало. - person 15ee8f99-57ff-4f92-890c-b56153; 01.05.2019
comment
Спасибо за помощь. Похоже, мне нужно больше узнать о классах и привязках, чтобы понять, на что вы меня указываете. Я поработаю над этим сегодня вечером и сохраню это, чтобы вернуться к нему, когда я лучше разберусь! - person Schreiberito; 01.05.2019
comment
Общий термин для всего, что связано с коллекциями и шаблонами данных, — MVVM или шаблон Model/View/Viewmodel. Кривая обучения крутая, но очень мощная, и многие люди здесь могут помочь вам с трудностями. Развлекайся. - person 15ee8f99-57ff-4f92-890c-b56153; 01.05.2019