How to stop timer affacted by button click? - c#

i am working on a winform application in which i have a timer.it is being used for showing stopwatch on the form. When i fire a button than my timer is interrupted. i want my timer to be uninterrupted while button is clicked. My code is as followed:-
private void button1_Click(object sender, EventArgs e)
{
if (!_timerRunning)
{
// Set the start time to Now
_startTime = DateTime.Now;
// Store the total elapsed time so far
_totalElapsedTime = _currentElapsedTime;
_timer.Start();
_timerRunning = true;
}
SqlConnection Con = new SqlConnection("Data Source=69.162.83.242,1232;Initial Catalog=test1;Uid=test;pwd=1234#Test;MultipleActiveResultSets=true;Connect TimeOut=60000;");
//SqlConnection Con = new SqlConnection("Data Source=ADMIN-PC\\YASH;Initial Catalog=test;Integrated Security=True; Connect TimeOut=600");
Con.Open();
string messageMask = "{0} # {1} : {2}";
string message = string.Format(messageMask, label6.Text, DateTime.Now.ToShortTimeString(), richTextBox2.Text);
richTextBox1.AppendText(Environment.NewLine + message);
SqlCommand cmd, cmd1;
cmd = new SqlCommand("Update Chat set UserInitial=#message,Updated=1 where ExpertName ='" + label6.Text + "'", Con);
cmd.Parameters.AddWithValue("#message", message);
cmd.ExecuteNonQuery();
Con.Close();
richTextBox2.Text = String.Empty;
richTextBox1.ScrollToCaret();
}
private void timer1_Tick(object sender, EventArgs e)
{
richTextBox1.ScrollToCaret();
count = count + 1;
count1 = count1 + 1;
timerSinceStartTime = new TimeSpan(timerSinceStartTime.Hours, timerSinceStartTime.Minutes, timerSinceStartTime.Seconds + 1);
// The current elapsed time is the time since the start button was
// clicked, plus the total time elapsed since the last reset
_currentElapsedTime = timerSinceStartTime + _totalElapsedTime;
// These are just two Label controls which display the current
// elapsed time and total elapsed time
if (count1 == 180)
{
MessageBox.Show("You are Automaticlly hired by User");
if (label7.Visible == true)
{
label7.Visible = false;
count = 0;
timerSinceStartTime = new TimeSpan(00, 00, 00);
label3.Visible = true;
}
}
label3.Text = timerSinceStartTime.ToString();
// If we're running on the UI thread, we'll get here, and can safely update
// the label's text.
richTextBox1.ScrollToCaret();
}
how to solve it??
thanks in Advance

Your problem stems from the fact you're using System.Windows.Forms.Timer which is not threaded and relies on the message pump. While your program is busy in the UI thread the message pump won't be processed.
You can improve this by moving to a timer that supports threads. I prefer System.Timers.Timer but there's also System.Threading.Timer.
With System.Timers.Timer the tick event is raised on a background thread if you don't pass any sync object in so that any code within the event handler will be handled in a separate thread.
Of course, to update the form we have to marshal back to the UI thread so we'll also need to use Control.Invoke().
This is very rough, but something like this:
System.Timers.Timer timer = new System.Timers.Timer();
timer.Elapsed += new ElapsedEventHandler(OnTimer);
timer.Interval = 1000;
timer.AutoReset = false;
timer.Enabled = true;
public void OnTimer(object sender, ElapsedEventArgs e)
{
// Do something busy like dancing
// Update form
Invoke((MethodInvoker)delegate() {
UpdateForm();
});
// Restart timer
((System.Timers.Timer)sender).Start();
}
public void UpdateForm()
{
// Code to update the form
}
Note I use AutoReset = false so that if the tick event takes longer than the timer interval you won't get overlap. You may or may not want this it entirely depends on what you're doing.

You can try this,
private bool bStopTimer = true;
private void StartTimer()
{
System.Threading.Thread thread = new System.Threading.Thread(new System.Threading.ThreadStart(this.ThreadTimer));
thread.IsBackground = true;
thread.Start();
}
private void ThreadTimer()
{
while (bStopTimer)
{
System.Threading.Thread.Sleep(1000); //interval in millisecond
lock(lblLabel.Text)
{
lblLable.Text = System.DateTime.Now.ToString("HH:mm:ss");
}
}
}
Update
place this line before Application.Run(new frmForm);
System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;

Related

Timer doesn't work due to unresponsive UI

The C# window which performs a data pull from SQL stored procedure, doesn't show 'Time Elapsed' because the Timer control doesn't seem to work.
One of my applications, that uses Timer control - doesn't seem to keep the timer ticking when it's processing.
If I perform Timer.Start() on Form_Load, it seems to work fine. However Timer.Start() prior to starting of a data pull (which takes about 2-3 minutes) seems to not-work.
Timer is enabled.
private void btnCalculate_Click(object sender, EventArgs e)
{
tmrTime.Start();
if (txtEmployeeNumber.Text.Trim() != "")
{
dtStart = DateTime.Now;
connectDB(); //Connects to Database, Executes a Stored Procedure, Prepares a response String, and assigns response to a Textbox. All of which takes 2-3 minutes.
}
else
{
MessageBox.Show("Please enter a value!");
}
tmrTime.Stop();
}
private void tmrTime_Tick(object sender, EventArgs e)
{
txtTimer.Text = "Time Elapsed : " + (DateTime.Now - dtStart).Seconds + " second(s)";
}
Should do this
var sw = Stopwatch.StartNew();
// here execute your DB call
sw.Stop();
txtTimer.Text = string.Format("Time Elapsed : {0}", sw);
Now, if you do this via background thread, your screen should be responsive. Just make sure to synchronize control (text box). You can start with BackgroundWorker and do this on DoWork. Then on complete, read data and set control value
UPDATE
If you want time of execution show on form, do this. This is all you need
public partial class Form1 : Form
{
Timer _timer = new Timer();
private DateTime _startTime;
public Form1()
{
InitializeComponent();
_timer.Interval = 1000;
_timer.Tick += _timer_Tick;
}
void _timer_Tick(object sender, EventArgs e)
{
var span = (DateTime.Now - _startTime);
label1.Text = string.Format("Elapsed: {0}", span);
}
private void button1_Click(object sender, EventArgs e)
{
label1.Text = "";
_startTime = DateTime.Now;
_timer.Start();
var bgw = new BackgroundWorker();
bgw.RunWorkerCompleted += bgw_RunWorkerCompleted;
bgw.DoWork += bgw_DoWork;
bgw.RunWorkerAsync();
}
void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
_timer.Stop();
}
void bgw_DoWork(object sender, DoWorkEventArgs e)
{
// run query here
}
}
Maybe better solution would be to use Stopwatch?
Check here: https://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch(v=vs.110).aspx
EDIT:
After Steve's comment - I added some usability for Stopwatch class
static void Main(string[] args)
{
var sw = new Stopwatch();
sw.Start();
DoSomething();
sw.Stop();
Console.WriteLine($"DoSomething() code took {sw.ElapsedMilliseconds}ms to run.");
sw.Restart();
DoSomethingElse();
sw.Stop();
Console.WriteLine($"DoSomethingElse() code took {sw.ElapsedMilliseconds}ms to run.");
}
Note - watch out for weird calculations while debugging - it will continue to count as you put a breakpoint at spots in your code.

Threading-Having difficulty. What am I doing wrong?

I've created a thread (or I'm trying to) which will autosave every so many minutes. Whenever I click the button to start the thread, the program doesn't autosave as instructed. So I'm reaching out for help. Here's the code:
private Thread saver;
...
saver.SetApartmentState(System.Threading.ApartmentState.STA);
saver = new Thread(new ThreadStart(SaveRegularly));
saver.Start();
Here's my SaveRegularly method:
private bool stopAndDie = false;
private void SaveRegularly()
{
//DateTime saveDueAt = DateTime.Now.AddMinutes(0.25);
//do
//{
//Thread.Sleep(1000);
//if (DateTime.Now >= saveDueAt)
//{
if (SaveDoc.FileName != "") //ADDED THIS TODAY (24/09)
{
CreateWordDocument(FilePath, SaveDoc.FileName, pathImage);
MessageBox.Show("Updated");
return;
}
else
{
if (SaveDoc.ShowDialog() == DialogResult.OK)
{
CreateWordDocument(FilePath, SaveDoc.FileName, pathImage);
MessageBox.Show("New Save");
return;
}
}
timer1.Start();
}
This is for the FormClosing Event, so the thread stops.
stopAndDie = true;
saver.Join(2000);
timer1.Stop();
When I run the program and I click the save button, I receive an error at the SaveFileDialog line (if (SaveDoc.ShowDialog() == DialogResult.OK)).Here is the error I receive.
Set the thread to STA mode.
saver.SetApartmentState(System.Threading.ApartmentState.STA);
But why aren't you using timers if you want to schedule something periodically?
Something like this:
System.Timers.Timer timer = new System.Timers.Timer(5 * 60 * 1000);
timer.Elapsed += (s, e) =>
{
//Invoke your show dialog on the UI thread here
};
timer.Start();
And when you want it to stop just call timer.Stop();

C# Timer Event not firing off

I can't get the timer to tick every time when i create a new command object I am wondering what is causing this. I am new to C# so if i could get help as to why this is happening it would be greatly appreciated.
This should trigger, but doesnt
command Cmd = new command("!example", 10);
Here's the code.
public class Timeout
{
public Timeout() { }
public static List<command> timeouts = new List<command>();
public class command
{
public string cmd;
public int seconds;
private System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer() { Interval = 1000 };
public command(string cmd, int seconds)
{
Debug.WriteLine("created, " + cmd + ", " + seconds);
this.cmd = cmd;
this.seconds = seconds;
this.timer.Tick += new EventHandler(Timer_Tick);
timer.Start();
}
private void Timer_Tick(object sender, EventArgs e)
{
Debug.WriteLine("tick -> " + seconds);
if (seconds > 0)
seconds--;
else
{
timer.Tick -= Timer_Tick;
timeouts.Remove(this);
Debug.WriteLine("removed");
}
}
}
}
actually you can do this way.
call the timer once you create the object
command cmd =new command("!example",10);
//then am calling the timer event
timer = new Timer(3000); // Set up the timer for 3 seconds
timer.Elapsed += new ElapsedEventHandler(timerElapsed);
//_timer_Elapsed is the event name
timer.Enabled = true;
public static void timerElapsed(object sender, ElapsedEventArgs e)
{
//do something here
}
please find the link here for more reference.hope my comment helps you :)

Dispatcher timer is firing twice :(

i have problems with this timer, my function in the Tick event are appearing twice.. i want it to appear only once..
public void timerStart()
{
DispatcherTimer updaterTimer = new DispatcherTimer();
updaterTimer.Tick += new EventHandler(updaterTimer_Tick);
updaterTimer.Interval = new TimeSpan(0,0,0,0,300);
updaterTimer.Start();
}
private void updaterTimer_Tick(object sender, EventArgs e)
{
updaterTimer.Stop();
checkSigningAvailable();
updaterTimer.Start();
}
This is the method that is checked every tick of the timer,
public void checkSigningAvailable()
{
if (dt_signing_in.CompareTo(DateTime.Now) < 0)
{
if (!InPopAlready)
{
InPopAlready = true;
disableSigningIn("False", this.event_id);
}
}
}
And the messagebox in the bottom is appearing twice after calling this function above
public void disableSigningIn(string Out,string event_id)
{
System.Console.WriteLine("POPED "+ InPopAlready);
connection.Open();
string sign = "True," + Out;
string query = "update data_storage set data_details = '" + sign + "' where data_name = 'Signing';";
NpgsqlCommand command = new NpgsqlCommand(query, connection);
command.ExecuteNonQuery();
connection.Close();
sign_in.Content = "Sign-in Time : Over";
string query2 = concatQuery(getIDnumberAttendance(event_id));
updateAbsences(query2);
MessageBox.Show("Signing in is over!", "No more signing in!", MessageBoxButton.OK, MessageBoxImage.Information);
}
You are adding " += new EventHandler " and adding and adding new EventHandlers all over new EventHandlers but never remove them..
All the previous one gets fired each Time the Timer Starts again.
You can reproduce this behaviour if you implement a counter, then you will see that is doubles with each new added and raised Event.
(Edit: Just was confused because the "new" keyword, but actually I will not delete the answer since I am pretty sure that in some cases it will exactly be the issue)
The following may help:
How to remove all event handlers from an event
And here the most easy solution:
(You may polish it by using delegates)
Declaration in Class:
private System.Windows.Threading.DispatcherTimer P5DispatcherHelpsystemTimer = new System.Windows.Threading.DispatcherTimer();
private EventHandler P5DispatcherTimerHandler;
Dispatcher Timer Method:
private void InitializeHelpsystemCronjobs(System.Windows.Controls.Canvas sub_CanvasElement)
{
P5DispatcherTimerHandler = (sender, e) => P5DispatcherHelpsystemTimerTick(sender, e, sub_CanvasElement);
P5DispatcherHelpsystemTimer.Tick += P5DispatcherTimerHandler;
P5DispatcherHelpsystemTimer.Interval = new TimeSpan(0, 0, 1);
P5DispatcherHelpsystemTimer.Start();
}
Dispatcher TimerTick Method:
private void P5DispatcherHelpsystemTimerTick(object sender, EventArgs e, System.Windows.Controls.Canvas sub_CanvasElement)
{
P5DispatcherHelpsystemTimer.Stop();
{
// Do stuff
}
P5DispatcherHelpsystemTimer.Start();
}
// Somewhere when an Trigger Event or Action etc. happens and the Timer shall start:
InitializeHelpsystemCronjobs(HelpsystemHelpCanvas);
// Somewhere when it sahll stop:
P5DispatcherHelpsystemTimer.Stop();
P5DispatcherHelpsystemTimer.Tick -= P5DispatcherTimerHandler;
(If you have more complex situation you definitely need delegate List<>)
For me, it was not starting, stopping or the Timer at all. It was the DI/IOC container resolving two instances of the ViewModel which started a new refresh timer in the constructor. Check to make sure that you are always seeing the same ViewModel instance and not actually two separate ones, firing two separate Timers.
The code below fires the MessageBox only once:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.timerStart();
}
DispatcherTimer updaterTimer;
private bool InPopAlready;
DateTime dt_signing_in;
public void timerStart()
{
updaterTimer = new DispatcherTimer();
updaterTimer.Tick += new EventHandler(updaterTimer_Tick);
updaterTimer.Interval = new TimeSpan(0, 0, 0, 0, 300);
updaterTimer.Start();
}
private void updaterTimer_Tick(object sender, EventArgs e)
{
updaterTimer.Stop();
checkSigningAvailable();
updaterTimer.Start();
}
public void checkSigningAvailable()
{
if (dt_signing_in.CompareTo(DateTime.Now) < 0)
{
if (!InPopAlready)
{
InPopAlready = true;
// Calling your method and showing MessageBox
MessageBox.Show("Signing in is over!", "No more signing in!", MessageBoxButton.OK, MessageBoxImage.Information);
}
}
}
}
I tend to write my "once-off" timer code like this:
var updaterTimer = new DispatcherTimer();
updaterTimer.Interval = new TimeSpan(0, 0, 0, 0, 300);
EventHandler tick = null;
tick = (s, e) =>
{
updaterTimer.Stop();
updaterTimer.Tick -= tick;
/* execute once-off code here */
};
updaterTimer.Tick += tick;
updaterTimer.Start();
Then I don't need to fluff with making new methods - it's all in one local code block.

Stop audio recorder on its own after time delay in c# ( using NAudio)

I am making an audio recorded using NAudio in C# and i need to remove the stop button used and simply stop the recording on its own after some time delay.
The code for the record event is
private void cmbRecord_Click(object sender, EventArgs e)
{
outputFilename = "file address";
waveInStream = new WaveIn(44100,2);
writer = new WaveFileWriter(outputFilename, waveInStream.WaveFormat);
waveInStream.DataAvailable += new EventHandler<WaveInEventArgs>(waveInStream_DataAvailable);
waveInStream.StartRecording();
// Just controling the objects on the screen.
cmbRecord.Enabled = false;
cmbStop.Enabled = true;
}
void waveInStream_DataAvailable(object sender, WaveInEventArgs e)
{
writer.WriteData(e.Buffer, 0, e.BytesRecorded);
int secondsRecorded = (int)(writer.Length / writer.WaveFormat.AverageBytesPerSecond);
}
The stop button is given as
private void cmbStop_Click(object sender, EventArgs e)
{
waveInStream.StopRecording();
waveInStream.Dispose();
waveInStream = null;
writer.Close();
writer = null;
cmbRecord.Enabled = true;
cmbStop.Enabled = false;
}
I need to stop the recording automatically inside the cmbRecord_Click event.
Thanks in advance.
use a Timer, set the Interval and copy the code in cmbStop_Click event over to timer's OnTick event. Enable the timer in the mbRecord_Click event and & remember to disable the timer in cmbStop_Click event
Edit:
Create a new timer and set its value
//put this line in your form class level
System.Windows.Forms.Timer mytimer=new System.Windows.Forms.Timer(); //create a new Timer
//put these two into your form constructor just after InitializeComponent();
mytimer.Interval=1000; //set the interval to 1 second.
mytimer.Tick += new EventHandler(mytimer_Tick);
Enable the timer in the mbRecord_Click event
private void cmbRecord_Click(object sender, EventArgs e)
{
outputFilename = "file address";
waveInStream = new WaveIn(44100,2);
writer = new WaveFileWriter(outputFilename, waveInStream.WaveFormat);
waveInStream.DataAvailable += new EventHandler<WaveInEventArgs>(waveInStream_DataAvailable);
waveInStream.StartRecording();
// Just controling the objects on the screen.
cmbRecord.Enabled = false;
cmbStop.Enabled = true;
//Enable the timer to fire
mytimer.Enabled = true;
}
Stop recording after 1 second..
void mytimer_Tick(object sender, EventArgs e)
{
waveInStream.StopRecording();
waveInStream.Dispose();
waveInStream = null;
writer.Close();
writer = null;
cmbRecord.Enabled = true;
cmbStop.Enabled = false;
//disable the timer here so it won't fire again...
mytimer.Enabled = false;
}
One thing you may want to bear in mind - there will be a DataAvailable callback after the call to StopRecording (or during, depending on the callback model used), so you might want to delay closing the WaveFileWriter until you have written everything.
Have a look at the VoiceRecorder sample project which uses NAudio and stops recording after 60 seconds. I explain in this article how recording is automatically stopped.
long maxFileLength = this.recordingFormat.AverageBytesPerSecond * 60;
int toWrite = (int)Math.Min(maxFileLength - writer.Length, bytesRecorded);
if (toWrite > 0)
writer.WriteData(buffer, 0, bytesRecorded);
else
Stop();

Categories

Resources