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





Проблема в вашем коде заключается в том, что вы инициализируете 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 Пожалуйста, смотрите исправленный код в motorOnBtn_1_Click, в начальной версии было серьезное упущение, которое все сломало.
Спасибо за помощь. Похоже, мне нужно больше узнать о классах и привязках, чтобы понять, на что вы меня указываете. Я поработаю над этим сегодня вечером и сохраню это, чтобы вернуться к нему, когда я лучше разберусь!
Общий термин для всего, что связано с коллекциями и шаблонами данных, - «MVVM» или «шаблон Model/View/Viewmodel». Кривая обучения крутая, но очень мощная, и многие люди здесь могут помочь вам с трудностями. Повеселись.
Вы передаете
motorTimer_1вIndividualTestStart()в качестве параметраdispatcherTimer. Затем вы заменяете значение параметра вновь созданнымDispatcherTimer, который вы инициализируете и запускаете.motorTimer_1никогда не запускается и никогда не является ссылкой наDispatcherTimer, который фактически запущен.