Hello, I am working on my first project in school, which is a simple Brick-Breaker game.
I've got a problem which occours when I click on the "Pause" button, the timer stops, but when I click on the "Continue" Button, the timer continues as if the the game was never paused.
I've extensivly searched for an answer but was not able to find one which was possible for me to intergrate into my program (I've only been programming for 2 months.)
My program is almost ready, and it's all divided into classes and methods, therefore it'll be a bit harder for me to paste exactly the important lines, but I'll give it a try anyways.
I had tried several solutions, like creating a stopwatch and then declaring the timer as
_time.Text = (duration.TotalSeconds - pausingTimer.Elapsed.TotalSeconds).ToString
But unfortunetly that way of thinking got me nowhere so far. These are the lines which affect the pause and continue features of the game.:
//data members (of Game Manager class)
private DispatcherTimer gamingLoopTimer = new DispatcherTimer();
private DateTime _startTime;
private TimeSpan _timeSpan;
private Stopwatch pausingTimer = new Stopwatch();
//ct'or
_timeSpan = new TimeSpan(0, 0, 0, 0, 1);
_difficultyTimeSpan = new TimeSpan(0, 0, 0, 0, 800);
public void StartGame()
{
gamingLoopTimer.Interval = _timeSpan;
gamingLoopTimer.Tick += GamingLoopHandler;
gamingLoopTimer.Start();
increasingDifficultyTimer.Interval = _difficultyTimeSpan;
increasingDifficultyTimer.Tick += IncreasingDifficulty;
increasingDifficultyTimer.Start();
_startTime = DateTime.Now;
private void GamingLoopHandler(object sender, object e)
{
UpdateGameState();
DrawState();
}
private void DrawState()
{
TimeSpan duration = DateTime.Now - _startTime;
_time.Text = (duration.TotalSeconds - pausingTimer.Elapsed.TotalSeconds).ToString
public void StopButton()
{
pausingTimer.Start();
gamingLoopTimer.Stop();
increasingDifficultyTimer.Stop();
_hasStopped = true;
PromptGameStop();
}
private void ContinueToPlay(IUICommand command)
{
pausingTimer.Stop();
pausingTimer.Reset();
gamingLoopTimer.Start();
increasingDifficultyTimer.Start();
_hasStopped = false;
}
note: I've tried to copy only the important code for the question, I hope I didn't delete anything important for the understanding of the answerers.
As stated above, the timer stops, but then continues as if it never stopped.
For example, should I press the "Pause" button at the 5-second mark, and click "Continue" after 15 seconds, the timer will continue from 20.
Thank you for your answers.
Related
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
}
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 TimerThings, 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.
I have a program that works as a back end for a serial terminal. This id intended to be a Fallout prop. I have this working fine with one serial port and one main program.
I would however like to make this is a functional, multi-user environment that opens on a selection on serial ports and has each one running in a seperate thread.
I'm not asking for a Blue Peter mirracle and "heres one I made earlier". I just some help understanding how Treading works properly.
So far I have had one simple threaded application that moved the cursor on the terminal, wrote the current time and the moved the cursor back once every minute.
The code for that is here:
static void StartClock()
{
TimerCallback tmCallback = WriteTime;
Timer timer = new Timer(tmCallback, null, 60000, 60000);
}
static void WriteTime(object WT)
{
string TimeDate = DateTime.Now.ToString();
char[] TimeDateArr = TimeDate.ToCharArray();
string test = "";
Array.Reverse(TimeDateArr);
Array.Resize(ref TimeDateArr, 8);
Array.Reverse(TimeDateArr);
Array.Resize(ref TimeDateArr, 5);
foreach (char c in TimeDateArr)
{
test = test + c.ToString();
}
PositionCursor(75, 1);
write(test);
PositionCursor(2, 23);
}
My issue is not fully understanding how treading works.
If anyone could properly explain what parts of this are doing and maybe how I would look at starting what I want to do.
Thanks in advance
There is a difference between system.Timers.Timer and System.Threading.Timer.
I think you need something like this;
static void Main(string[] args)
{
var timer = new System.Timers.Timer
{
AutoReset = true,
Interval = 100,
Enabled = true
};
timer.Elapsed += TimerOnElapsed;
timer.Start();
Console.ReadKey();
}
private static void TimerOnElapsed(object sender, ElapsedEventArgs elapsedEventArgs)
{
Console.WriteLine("do stuff on a interval");
}
I have a C# program in which, I need the timer to stop if the user stops interacting with the program. What It needs to do is pause, and then restart when the user becomes active again. I have done some research, and found that there is commands such as:
timer.Stop();
and
timer.Start();
But I was wondering if there was like a:
timer.Pause();
And then when the user becomes active again, it picks up where it left off, and doesn't restart. If anyone can help, it would be much appreciated!
Thanks,
Micah
You achieve this by using the Stopwatch class in .NET. By simply stopping and starting you continue the use of the instance of the stopwatch.
Make sure to make use of using System.Diagnostics;
var timer = new Stopwatch();
timer.Start();
timer.Stop();
Console.WriteLine(timer.Elapsed);
timer.Start(); //Continues the timer from the previously stopped time
timer.Stop();
Console.WriteLine(timer.Elapsed);
To reset the stopwatch, just call the Reset or Restart methods, like below:
timer.Reset();
timer.Restart();
I have created this class for this situation:
public class PausableTimer : Timer
{
public double RemainingAfterPause { get; private set; }
private readonly Stopwatch _stopwatch;
private readonly double _initialInterval;
private bool _resumed;
public PausableTimer(double interval) : base(interval)
{
_initialInterval = interval;
Elapsed += OnElapsed;
_stopwatch = new Stopwatch();
}
public new void Start()
{
ResetStopwatch();
base.Start();
}
private void OnElapsed(object sender, ElapsedEventArgs elapsedEventArgs)
{
if (_resumed)
{
_resumed = false;
Stop();
Interval = _initialInterval;
Start();
}
ResetStopwatch();
}
private void ResetStopwatch()
{
_stopwatch.Reset();
_stopwatch.Start();
}
public void Pause()
{
Stop();
_stopwatch.Stop();
RemainingAfterPause = Interval - _stopwatch.Elapsed.TotalMilliseconds;
}
public void Resume()
{
_resumed = true;
Interval = RemainingAfterPause;
RemainingAfterPause = 0;
Start();
}
}
There is not a pause because it is easy to do the equivalent. You can just stop the timer instead of pausing it, then when you need to restart it you just need to specify the amount of time remaining. It might be complicated or it might be simple; it depends on what you are using the timer to do. The fact that what you do depends on what you are using the timer for is probably the reason a pause does not exist.
You might be using the timer to do something repetitively at a regular time period or you might be using the timer to count down to a specific time. If you are doing something (such as every second) repetitively then your requirements might be to restart at the beginning of that time period (a second) or at a portion of that period. What happens if the pause is for more than the time period? Usually the missed events would be ignored but that depends on requirements.
So I am trying to say that you need to determine your requirements. Then if you need help then clarify what you need.
Ich have a little WinForms program, which has 1 Button and 1 Textbox. If i click the button then the programm counting from 1 to 100000 and shows in every step the current time in milliseconds in the textbox. The countingloop is running in a seperate thread.
public partial class Form1 : Form {
public delegate void myDelegate();
public myDelegate mydelegate;
public Form1() {
InitializeComponent();
mydelegate = new myDelegate(b);
}
private void button1_Click(object sender, EventArgs e) {
button2.Focus();
Thread t = new Thread(a);
t.Start();
}
private void Form1_KeyDown(object sender, KeyEventArgs e) {
Console.WriteLine(e.KeyCode);
}
public void a() {
for (int i = 0; i < 100000; i++) {
textBox1.BeginInvoke(mydelegate);
}
}
public void b() {
textBox1.Text = GetCurrentMilli().ToString();
textBox1.Refresh();
}
public static double GetCurrentMilli() {
DateTime Jan1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
TimeSpan javaSpan = DateTime.UtcNow - Jan1970;
return javaSpan.TotalMilliseconds;
}
}
If i run this, the program works, but the gui is freezing till the loop is finished.
But why?
I have called BeginInvoke?!
If i replace
textBox1.BeginInvoke(mydelegate);
with
textBox1.Invoke(new MethodInvoker(b));
then it works without any freeze or problems.
But why?
When you call BeginInvoke you are scheduling a UI update to happen, and then continuing along with your program without waiting for that UI update to happen. When you do this just a few times you're fine, but the problem that you're having is that you're sending in 100,000 requests all at once, and it's going to take the UI some time to get through all of those requests, and nothing else is going to be able to be done in that time because any new UI updates go to the end of the line, and won't be performed until the other requests are finished.
While there are ways to keep your general approach the same and try to let other operations cut to the front of the line, the proper approach is to avoid the problem in the first place. You have no need to be sending 100,000 updates to single textbox at once.
If you want the textbox to have the appearance of a clock, in which it ticks up, then a Timer would be a good tool for the job; you can handle the Tick event to update the textbox every second, quarter second, or some other more "human time" interval.
If the idea is to update the UI with the progress of some long running operation, then you simply want to ensure that you don't update progress quite so often. Update progress every few dozen iterations of your loop, instead of every single one, for example.
You may need to call UpdateLayout in between, not sure if it needs to be invoked to prevent cross-thread exception
public void a() {
for (int i = 0; i < 100000; i++) {
textBox1.BeginInvoke(mydelegate);
textBox1.UpdateLayout();
}
}
I'm looking for a way to add a timer (or stopwatch) that will start counting from 0 the moment the application is launched or a button is clicked, and keeps counting even after the user navigates through different pages, and then be able to display how much time has passed in the last page of the application. I've been messing around with the DispatcherTimer class, but to be honest, I'm having trouble understanding it. Any help, or even a nod in the right direction would be greatly appreciated!
If you want to use a time, you could add one on the page showing time!
Add this code to the constructor or somewhere else where you want to activate the timer. (The App.StartTime is the same as i wrote in the other answer)
DispatcherTimer timer = new DispatcherTimer();
timer.Tick +=
delegate(object s, EventArgs args)
{
TimeSpan time = (DateTime.Now - App.StartTime);
this.timenow.Text = string.Format("{0:D2}:{1:D2}:{2:D2}", time.Hours, time.Minutes, time.Seconds);
};
timer.Interval = new TimeSpan(0, 0, 1); // one second
timer.Start();
You just have to store the time when your app launch and then subtract the current time from the stored value.
in your App.cs store the time when application launch:
private static DateTime _starttime = DateTime.Now;
public static DateTime StartTime
{
get
{
return _starttime;
}
}
In your page or any where you need to get the current time the application has run, you just have to subtract then current time from the stored time. I have used it in a button click handler, see below:
private void timebutton_Click(object sender, RoutedEventArgs e)
{
TimeSpan time = (DateTime.Now - App.StartTime);
this.timenow.Text = string.Format("{0:D2}:{1:D2}:{2:D2}", time.Hours, time.Minutes, time.Seconds);
}