How to use a timer in place of a while loop? - c#

at the moment i am using a while (true) loop to do this. I am not very familiar with timers. can someone tell me how i would convert this to work with a timer?
string lyricspath = #"c:\lyrics.txt";
TextReader reader = new StreamReader(lyricspath);
int start = 0;
string[] read = File.ReadAllLines(lyricspath);
string join = String.Join(" ", read);
int number = join.Length;
while (true)
{
Application.DoEvents();
Thread.Sleep(200);
start++;
string str = join.Substring(start, 15);
byte[] bytes = Encoding.BigEndianUnicode.GetBytes(str);
label9.Text = str;
if (start == number - 15)
{
start = 0;
}
}

Why use a timer? I assume this is because you want to have the app remain responsive during such a supposedly long operation. If so cosider using the same sort of code but in a BackgroundWorker.
Also if you do specifically want to use a Timer, beware which one you use; the Systm.Timer invokes its event in a different thread to the one used by the applications hoting form. The Timer in Forms events in the forms thread. You may need to Invoke() the operations in a timer callback that change the label.

Basically, a timer just sits there and counts, and every X milliseconds it "ticks"; it raises an event, which you can subscribe to with a method that does whatever you want done every X milliseconds.
First, all of the variables you will need inside the loop, that come from outside the loop, will need to have "instance scope"; they must be a part of the object that currently has this method, and not "local" variables like they are now.
Then, your current method will need to perform all of the steps prior to the while loop, setting whose "instance" variables I mentioned, and then create and start a Timer. There are several Timers in .NET; the two that would be most useful would likely be either the System.Windows.Forms.Timer or the System.Threading.Timer. This timer will need to be given a handle to the method it should call when it "ticks", and should be told how often to "tick".
Finally, all the code inside the while loop, EXCEPT the calls to Application.DoEvents() and Thread.Sleep(), should be placed in the method that the Timer will run when it "ticks".
Something like this ought to work:
private string[] join;
private int number;
private int start;
private Timer lyricsTimer;
private void StartShowingLyrics()
{
string lyricspath = #"c:\lyrics.txt";
TextReader reader = new StreamReader(lyricspath);
start = 0;
string[] read = File.ReadAllLines(lyricspath);
join = String.Join(" ", read);
number = join.Length;
lyricsTimer = new System.Windows.Forms.Timer();
lyricsTimer.Tick += ShowSingleLine;
lyricsTimer.Interval = 300;
lyricsTimer.Enabled = true;
}
private void ShowSingleLine(object sender, EventArgs args)
{
start++;
string str = join.Substring(start, 15);
byte[] bytes = Encoding.BigEndianUnicode.GetBytes(str);
label9.Text = str;
if (start == number - 15)
{
start = 0;
}
}

This runs every 200 ms. But the suggestion to try Google before asking a question here is a good one.
using Timer = System.Windows.Forms.Timer;
private static readonly Timer MyTimer = new Timer();
...
MyTimer.Tick += MyTimerTask;
MyTimer.Interval = 200; // ms
MyTimer.Enabled = true;
...
private void MyTimerTask(Object o, EventArgs ea)
{
...
}

Simply define a new timer:
Timer timer1 = new Timer();
timer1.Interval = 1; // Change it to any interval you need.
timer1.Tick += new System.EventHandler(this.timer1_Tick);
timer1.Start();
Then define a method that will be called in every timer tick (every [Interval] miliseconds):
private void timer1_Tick(object sender, EventArgs e)
{
Application.DoEvents();
Thread.Sleep(200);
start++;
string str = join.Substring(start, 15);
byte[] bytes = Encoding.BigEndianUnicode.GetBytes(str);
label9.Text = str;
if (start == number - 15)
{
start = 0;
}
}
*Remember to define the variables outside the method so you will be able to access them in the timer1_Tick method.

Related

c# - Timer with different parameters at each time

I have a list of few questions saved in a JSON file. I would like to send one different question every 10 seconds.
I launched a timer every 10 seconds, but the int "position" cannot be incremented at each time. How could I do ?
public override void OnStart()
{
dynamic data = Newtonsoft.Json.JsonConvert.DeserializeObject(File.ReadAllText("QCM.js"));
int pos = 0;
Timer aTimer = new Timer(2000);
aTimer.Elapsed += (sender, e) => SendData(pos, data);
pos++;
aTimer.Start();
static void SendData (int pos, dynamic data)
{
PackageHost.WriteInfo(data.Data[pos].Label);
}
The pos variable is captured by the lambda, you can use
aTimer.Elapsed += (sender, e) => SendData(pos++, data);
//pos++;
Make that pos a static variable, and increment it in SendData.
Be sure to end the timer when you run out of data.

How can i add a time elapsed progrerss to my backgroundworker dowork event?

In top of form1
label5.Text = "00:00:00";
In the dowork event
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
DirectoryInfo diri = new DirectoryInfo(#"d:\c-sharp");
WalkDirectoryTree(diri);
}
WalkDirectoryTree method
int tfiles = 0;
int tdirs = 0;
void WalkDirectoryTree(System.IO.DirectoryInfo root)
{
System.IO.FileInfo[] files = null;
System.IO.DirectoryInfo[] subDirs = null;
string[] workerResult = new string[4];
try
{
files = root.GetFiles("*.cs");
tdirs ++;
workerResult[1] = root.FullName;
workerResult[3] = tdirs.ToString();
backgroundWorker1.ReportProgress(0,workerResult);
}
catch (UnauthorizedAccessException e)
{
}
catch (System.IO.DirectoryNotFoundException e)
{
}
if (files != null)
{
foreach (System.IO.FileInfo fi in files)
{
tfiles += files.Length;
if (files.Length > 0)
{
try
{
int Vara = File.ReadAllText(fi.FullName).Contains("Form1") ? 1 : 0;
if (Vara == 1)
{
workerResult[2] = files[0].FullName;
}
}
catch (FileNotFoundException e)
{
}
}
workerResult[0] = tfiles.ToString();
backgroundWorker1.ReportProgress(0, workerResult);
Thread.Sleep(10);
}
subDirs = root.GetDirectories();
foreach (System.IO.DirectoryInfo dirInfo in subDirs)
{
WalkDirectoryTree(dirInfo);
}
}
}
In the constructor i start the backgroundworker
InitializeComponent();
label1.Visible = false;
label2.Visible = false;
label3.Visible = false;
label4.Visible = false;
label5.Text = "00:00:00";
pbt.Size = new Size(984, 23);
pbt.Location = new Point(12, 358);
this.Controls.Add(pbt);
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.RunWorkerAsync();
I want to make that once the backgroundworker start the whole process start in the dowork event report to label5 the time elapsed.
First how can i do it ? and should i use a timer or stopwatch ?
Since you are wanting to measure the elapsed time taken by a process, by definition you should be using the System.Diagnostics.Stopwatch class. MSDN defines it as:
Stopwatch Class
Provides a set of methods and properties that you can use to accurately measure elapsed time.
However, you will also need a System.Windows.Forms.Timer control on your form in order to update the field while the work is in progress. The timer's Interval property controls how often you want to update the field, but don't rely on this to determine the actual value to display. Instead, use the Elapsed property of the stopwatch.
Drop a Timer onto your form.
Create an instance of the stopwatch class in your C# code:
private readonly Stopwatch _stopwatch = new Stopwatch();
Just before you call RunWorkerAsync(), call timer1.Start()
Inside the background worker's DoWork event:
_stopwatch.Restart();
// do your work
_stopwatch.Stop();
In the timer's Tick event, update your label with the value of the stopwatch's Elapsed property. Format it however you like.
lblElapsed.Text = _stopwatch.Elapsed.ToString(#"hh\:mm\:ss\.f");
In the RunWorkerCompleted event, call timer1.Stop()
I've posted a complete working example here.
I would capture the current time on a variable or field and start a timer before the invocation of RunWorkerAsync. On each tick of the timer update the label with the elapsed time (current time minus captured starting time). Stop the timer when the worker ends using RunWorkerCompleted event.
If you're talking about displaying only the total time it took for the BackgroundWorker to do its job (i.e. not incremental updates):
Grab a timestamp (e.g. DateTime.UtcNow, if you don't need sub-millisecond precision) just prior to invoking RunWorkerAsync. Pass this value into the RunWorkerAsync method (using the overload that accepts an object parameter). Catch the RunWorkerCompleted event in your form, and retrieve the timestamp from the UserState property of those event args. Set your label to the delta of the current time minus the UserState's timestamp.
For example:
backgroundWorker1.RunWorkerAsync(DateTime.UtcNow);
// elsewhere in your form:
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
_myLabel.Text = DateTime.UtcNow - (DateTime)e.UserState;
}

Pausing a BackgroundWorker from another method

I have a program that is continuously running.
When I start the program, I have a BackgroundWorker (InitialStart.cs):
BackgroundWorker recordingSyncWorker = new BackgroundWorker();
recordingSyncWorker.DoWork += new DoWorkEventHandler(RecordingSyncCheck);
recordingSyncWorker.WorkerSupportsCancellation = false;
recordingSyncWorker.WorkerReportsProgress = false;
recordingSyncWorker.RunWorkerAsync();
void RecordingSyncCheck(object sender, DoWorkEventArgs e)
{
cHandler ch = new cHandler();
Timer theTimer;
int seconds = 1;
if (taskSeconds != null && taskSeconds != "")
seconds = Convert.ToInt32(taskSeconds);
int milliseconds = seconds * 1000;
theTimer = new Timer(10000);
theTimer.Elapsed += new ElapsedEventHandler(ch.SyncMethod);
theTimer.Interval = milliseconds;
theTimer.Enabled = true;
}
And I have two methods in another class (cHandler.cs):
SyncMethod(object source, System.Timers.ElapsedEventArgs e)
{
// random code
}
private string SDCardCheck(object whatever)
{
//more code
}
SDCardCheck gets called thru WCF, so it's like there is another instance of cHandler.cs running. Is there a way for me to pause the BackgroundWorker when I call SDCardCheck?
Don't use a BackgroundWorker just to start a timer. Starting a timer is not a long running operation; it can be done directly from the UI thread.
Your other method can disable the timer to stop it from firing, and then enable it again to allow it to continue firing, in order to effectively pause its execution.

C# timer stop after some number of ticks automatically

How to stop a timer after some numbers of ticks or after, let's say, 3-4 seconds?
So I start a timer and I want after 10 ticks or after 2-3 seconds to stop automatically.
Thanks!
You can keep a counter like
int counter = 0;
then in every tick you increment it. After your limit you can stop timer then. Do this in your tick event
counter++;
if(counter ==10) //or whatever your limit is
yourtimer.Stop();
When the timer's specified interval is reached (after 3 seconds), timer1_Tick() event handler will be called and you could stop the timer within the event handler.
Timer timer1 = new Timer();
timer1.Interval = 3000;
timer1.Enabled = true;
timer1.Tick += new System.EventHandler(timer1_Tick);
void timer1_Tick(object sender, EventArgs e)
{
timer1.Stop(); // or timer1.Enabled = false;
}
i generally talking because you didn't mention which timer, but they all have ticks... so:
you'll need a counter in the class like
int count;
which you'll initialize in the start of your timer, and you'll need a dateTime like
DateTime start;
which you'll initialize in the start of your timer:
start = DateTime.Now;
and in your tick method you'll do:
if(count++ == 10 || (DateTime.Now - start).TotalSeconds > 2)
timer.stop()
here is a full example
public partial class meClass : Form
{
private System.Windows.Forms.Timer t;
private int count;
private DateTime start;
public meClass()
{
t = new Timer();
t.Interval = 50;
t.Tick += new EventHandler(t_Tick);
count = 0;
start = DateTime.Now;
t.Start();
}
void t_Tick(object sender, EventArgs e)
{
if (count++ >= 10 || (DateTime.Now - start).TotalSeconds > 10)
{
t.Stop();
}
// do your stuff
}
}
Assuming you are using the System.Windows.Forms.Tick. You can keep track of a counter, and the time it lives like so. Its a nice way to use the Tag property of a timer.
This makes it reusable for other timers and keeps your code generic, instead of using a globally defined int counter for each timer.
this code is quiet generic as you can assign this event handler to manage the time it lives, and another event handler to handle the specific actions the timer was created for.
System.Windows.Forms.Timer ExampleTimer = new System.Windows.Forms.Timer();
ExampleTimer.Tag = new CustomTimerStruct
{
Counter = 0,
StartDateTime = DateTime.Now,
MaximumSecondsToLive = 10,
MaximumTicksToLive = 4
};
//Note the order of assigning the handlers. As this is the order they are executed.
ExampleTimer.Tick += Generic_Tick;
ExampleTimer.Tick += Work_Tick;
ExampleTimer.Interval = 1;
ExampleTimer.Start();
public struct CustomTimerStruct
{
public uint Counter;
public DateTime StartDateTime;
public uint MaximumSecondsToLive;
public uint MaximumTicksToLive;
}
void Generic_Tick(object sender, EventArgs e)
{
System.Windows.Forms.Timer thisTimer = sender as System.Windows.Forms.Timer;
CustomTimerStruct TimerInfo = (CustomTimerStruct)thisTimer.Tag;
TimerInfo.Counter++;
//Stop the timer based on its number of ticks
if (TimerInfo.Counter > TimerInfo.MaximumTicksToLive) thisTimer.Stop();
//Stops the timer based on the time its alive
if (DateTime.Now.Subtract(TimerInfo.StartDateTime).TotalSeconds > TimerInfo.MaximumSecondsToLive) thisTimer.Stop();
}
void Work_Tick(object sender, EventArgs e)
{
//Do work specifically for this timer
}
When initializing your timer set a tag value to 0 (zero).
tmrAutoStop.Tag = 0;
Then, with every tick add one...
tmrAutoStop.Tag = int.Parse(tmrAutoStop.Tag.ToString()) + 1;
and check if it reached your desired number:
if (int.Parse(tmrAutoStop.Tag.ToString()) >= 10)
{
//do timer cleanup
}
Use this same technique to alternate the timer associated event:
if (int.Parse(tmrAutoStop.Tag.ToString()) % 2 == 0)
{
//do something...
}
else
{
//do something else...
}
To check elapsed time (in seconds):
int m = int.Parse(tmrAutoStop.Tag.ToString()) * (1000 / tmrAutoStop.Interval);

C# Threading - an array of threads, where each thread contains a form with an image

I have an array of five threads. Each thread contains the same form, each form is put on to the screen in a different location (still working on that method :P).
I am trying to have each form load its contents (an image) before the other forms have finishing being placed. At the moment this works for the first form, but the others are blank or disappear :P
Originally each form would be placed but the method would need to finish before all the forms contents were displayed.
Any help would be appreciated, thanks :)
public partial class TrollFrm : Form
{
int number = 0;
public TrollFrm()
{
InitializeComponent();
startThreads();
}
private void TrollFrm_Load(object sender, EventArgs e)
{
}
private void TrollFrm_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = true;
}
public void startThreads()
{
Thread[] ThreadArray = new Thread[5];
for (int i = 0; i < 5; i++)
{
ThreadArray[i] = new Thread(new ThreadStart(createForm));
ThreadArray[i].Start();
}
}
public void createForm()
{
Form frm = new TrollChildFrm();
Random randomX = new Random();
Random randomY = new Random();
number++;
int xValue;
int yValue;
if (number % 2 == 0) //number is even.
{
xValue = (Convert.ToInt32(randomX.Next(1, 1920))) + 200;
yValue = (Convert.ToInt32(randomY.Next(1, 1080))) - 200;
}
else //number is not even.
{
xValue = (Convert.ToInt32(randomX.Next(1, 1920))) - 200;
yValue = (Convert.ToInt32(randomY.Next(1, 1080))) + 200;
}
frm.Show();
frm.Location = new Point(xValue, yValue);
Thread.Sleep(1000);
}
Your forms are not displaying correctly because they are not running on a thread with a message loop. The general rule is that all UI element accesses must occur on the main UI thread.
Since you have a call to Thread.Sleep(1000) I am going to assume that you want to wait 1 second between the initial display of each form. In that case I would use a System.Windows.Forms.Timer who's Tick event will call createForm directly. Enable the timer, let 5 Tick events come through, and then disable the timer. I see no need to create any threads at all.
The reason your forms aren't displaying is because you are running inside one method on the main UI thread. Instead, you could create a method that spawns a new form and launch that at certain intervals on another thread (making sure the form handling is done on the main UI thread). So you could do something like:
(Pseudo Code)
private const int TIME_THRESHOLD = 100;
int mElapsedTime = 0;
Timer mTimer = new Timer();
.ctor
{
mTimer.Elapsed += mTimer_Elapsed;
}
private void mTimer_Elapsed(...)
{
mElapsedTime++;
if (mElapsedTime >= TIME_THRESHOLD)
{
mElapsedTime = 0;
SpawnForm();
}
}
private void SpawnForm()
{
// Make sure your running on the UI thread
if (this.InvokeRequired)
{
this.BeginInvoke(new Action(SpawnForm));
return;
}
// ... spawn the form ...
}
This is just an example of what I was proposing - it would not look exactly like this in the code, but this should give you an idea of the execution steps.
I would suggest to use Thread.Sleep(1000) in this manner
Caller section
for (int i = 0; i < 5; i++)
{
ThreadArray[i] = new Thread(new ThreadStart(createForm));
ThreadArray[i].Start();
}
Thread.Sleep(1000);
Also in the method that executing the work for the thread.
while(!something)
{
Thread.Sleep(1000)
}

Categories

Resources