Reputation: 29
When I click my stop button, my timer is still counting down, even though I tell it to stop.
My current relevant code:
I'm naming the timers here, as I need to access them for a stop/start all button as well.
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);
When I click the on button, the IndividualTestStart method is called & passed the relevant parameters:
public void motorOnBtn_1_Click(object sender, RoutedEventArgs e)
{
IndividualTestStart(motorOnBtn_1, motorOffBtn_1, motorTimer_1, motorCycleTime_1, timeUntilmotorCycle_1, motorTestCycles_1);
}
When I click the off button, I'm wanting to stop that timer so the cycle never finishes:
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
}
This is called when I click start. I'll eventually have something similar for the stop button, but I'm taking things one step at a time:
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
}
}
When I click the stop button, I expect the timer in the textbox to stop counting down. However, it just keeps on ticking. When I click stop, the start button is re-enabled, so I know that it's triggering the code in the event handler. But it isn't stopping the timer.
Not starting a new timer now. New code:
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
}
Upvotes: 0
Views: 859
Reputation: 37059
The problem in your code is that you initialize motorTimer_1
with a DispatcherTimer
that doesn't do anything, then you pass motorTimer_1
in as the dispatcherTimer
parameter, and then you replace the value of the parameter with a newly created, different DispatcherTimer
.
The new timer works fine, but when you call stop on motorTimer_1
, nothing happens, because that's not the one that's running. You could simply assign the new DispatcherTimer
directly to motorTimer_1
in IndividualTestStart()
, but you've gone to great trouble to parameterize everything in IndividualTestStart()
so it can work with different DispatcherTimers.
Instead, here's what we'll do: There is no reason to pass in a DispatcherTimer
. IndividualTestStart()
must create the DispatcherTimer
in order to initialize it. OK, let's run with that. It will create a new one and return it.
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();
}
}
Since this is WPF, you'll want to write a viewmodel class TimerThing
(think of a better name) that owns a DispatcherTimer, two commands to start it and stop it, and a public bool property that indicates whether it's running or not. IndividualTestStart() should be a method of that class. The parent viewmodel will have have an ObservableCollection<TimerThing>
containing an arbitrary number of TimerThing
s, which will be displayed in an ItemsControl with an ItemTemplate that creates buttons bound to the Start and Stop commands. The above code will look very different, since none of the C# code will know anything about buttons: Instead, the buttons in the item template XAML will be enabled/disabled by bindings.
Upvotes: 1