How to execute the loop for specific time - c#

How can i execute the a particluar loop for specified time
Timeinsecond = 600
int time = 0;
while (Timeinsecond > time)
{
// do something here
}
How can i set the time varaible here, if i can use the Timer object start and stop method it doesnot return me time in seconds
Regards
NewDev

May be the following will help:
Stopwatch s = new Stopwatch();
s.Start();
while (s.Elapsed < TimeSpan.FromSeconds(600))
{
//
}
s.Stop();

If you want ease of use:
If you don't have strong accuracy requirements (true millisecond level accuracy - such as writing a high frames per second video game, or similar real-time simulation), then you can simply use the System.DateTime structure:
// Could use DateTime.Now, but we don't care about time zones - just elapsed time
// Also, UtcNow has slightly better performance
var startTime = DateTime.UtcNow;
while(DateTime.UtcNow - startTime < TimeSpan.FromMinutes(10))
{
// Execute your loop here...
}
Change TimeSpan.FromMinutes to be whatever period of time you require, seconds, minutes, etc.
In the case of calling something like a web service, displaying something to the user for a short amount of time, or checking files on disk, I'd use this exclusively.
If you want higher accuracy:
look to the Stopwatch class, and check the Elapsed member. It is slightly harder to use, because you have to start it, and it has some bugs which will cause it to sometimes go negative, but it is useful if you need true millisecond-level accuracy.
To use it:
var stopwatch = new Stopwatch();
stopwatch.Start();
while(stopwatch.Elapsed < TimeSpan.FromSeconds(5))
{
// Execute your loop here...
}

Create a function for starting, stopping, and elapsed time as follows:
Class CustomTimer
{
private DateTime startTime;
private DateTime stopTime;
private bool running = false;
public void Start()
{
this.startTime = DateTime.Now;
this.running = true;
}
public void Stop()
{
this.stopTime = DateTime.Now;
this.running = false;
}
//this will return time elapsed in seconds
public double GetElapsedTimeSecs()
{
TimeSpan interval;
if (running)
interval = DateTime.Now - startTime;
else
interval = stopTime - startTime;
return interval.TotalSeconds;
}
}
Now within your foreach loop do the following:
CustomTimer ct = new CustomTimer();
ct.Start();
// put your code here
ct.Stop();
//timeinsecond variable will be set to time seconds for your execution.
double timeinseconds=ct.GetElapsedTime();

use Timers in c#
http://msdn.microsoft.com/en-us/library/system.windows.forms.timer.aspx

It's ugly .... but you could try this:
DateTime currentTime = DateTime.Now;
DateTime future = currentTime.AddSeconds(5);
while (future > currentTime)
{
// Do something here ....
currentTime = DateTime.Now;
// future = currentTime.AddSeconds(5);
}

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Accord.Video.FFMPEG;
namespace TimerScratchPad
{
public partial class Form1 : Form
{
VideoFileWriter writer = new VideoFileWriter();
int second = 0;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
writer.VideoCodec = VideoCodec.H264;
writer.Width = Screen.PrimaryScreen.Bounds.Width;
writer.Height = Screen.PrimaryScreen.Bounds.Height;
writer.BitRate = 1000000;
writer.Open("D:/DemoVideo.mp4");
RecordTimer.Interval = 40;
RecordTimer.Start();
}
private void RecordTimer_Tick(object sender, EventArgs e)
{
Rectangle bounds = Screen.GetBounds(Point.Empty);
using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
{
using (Graphics g = Graphics.FromImage(bitmap))
{
g.CopyFromScreen(Point.Empty, Point.Empty, bounds.Size);
}
writer.WriteVideoFrame(bitmap);
}
textBox1.Text = RecordTimer.ToString();
second ++;
if(second > 1500)
{
RecordTimer.Stop();
RecordTimer.Dispose();
writer.Close();
writer.Dispose();
}
}
}
}

Instead of such an expensive operation I'd recommend this: It's nasty but it's better to sit than running for doing nothing heating the cpu unnecesarily, the question is may be academic.
using System.Threading;
Thread.Sleep(600000);

Related

How to display Timer with day, hour etc

I'm trying to create a Timer which records the users 'Time Played' as you can expect the Timer should be ticking every second. I want it to be displayed as:
0d 12h 11m 23s
This is what I have so far:
private void TimePlayedTimer_Start()
{
timePlayedStr = "00:00:00:00";
timePlayed = new DispatcherTimer();
timePlayed.Tick += timePlayedTimer_Tick;
timePlayed.Interval = new TimeSpan(0, 0, 0, 1);
timePlayed.Start();
}
timePlayedStr is what is retrieved from the localStorage but in this example I have just set it to "00:00:00:00" to make it easier to understand
Then I have a tick event:
void timePlayedTimer_Tick(object sender, object e)
{
DateTime newDateTime = Convert.ToDateTime(timePlayedStr).AddSeconds(1);
string newDateTimeStr = newDateTime .ToString("dd:HH:mm:ss");
}
So I basically want it to add a second every tick then when it gets to 60 seconds it'll add a minute, then hour then day, but then I want it displayed like:
0d 12h 11m 23s
Does anyone know what I am doing wrong?
To display your "time" in the "0d 12h 11m 23s" format, use
string newDateTimeStr = newDateTime.ToString("d'd ' H'h ' m'm ' s's'");
the parts between the ' are used verbatim, not interpreted as placeholder.
EDIT
When you have a TimeSpan, use this to get to your display format:
string displayTimeStr = storedTimespan.ToString(#"d\d\ h\h\ m\m\ s\s");
here all non-format characters (including spaces) need to be escaped by a backslash, which itself doesn't need to be escaped because of the #verbatim string.
Two Steps:
1.
Save the time when you have started playing.
2. Create a timer with a update function and substract the actual time with the time started. then you get a TimeSpan which is the time played.
using System.Timers;
public class Test
{
DateTime StartTime { get; set; }
TimeSpan TimePlayed { get; set; }
Timer Timer { get; set; }
public Test()
{
Timer = new Timer() {Interval = 1000};
Timer.Elapsed += Update;
Timer.Start();
StartTime = DateTime.Now;
}
private void Update(object sender, ElapsedEventArgs e)
{
TimePlayed = DateTime.Now - StartTime;
}
}
For sure you can do .ToString(...) and get the format you like - as you did in your code.
I am no App developer so i don't know how C# works on phone. but if you quit the app you should save the time. a super easy way should be saving the time in a file like this:
private const string FileNameAndLocation = "yourfilename.txt";
private void AppClosing()
{
using (StreamWriter sw = new StreamWriter(FileNameAndLocation))
{
sw.WriteLine(StartTime.ToString());
}
}
private void AppStarting()
{
if (!File.Exists(FileNameAndLocation))
{
StartTime = DateTime.Now;
return;
}
using (StreamReader sr = new StreamReader(FileNameAndLocation))
{
var line = sr.ReadLine();
StartTime = Convert.ToDateTime(line);
}
}

Accurate measurement of download speed of a webclient

I am using C# and the WebClient class.
This is the code I am using, inspired by another post here on SO. This code worked well for large files, it accurately displayed the download speed. However, there is now the limitation of downloading individual files, many of which are small, with small being .5-5 MB. This has caused the speed counter to skyrocket, often into the hundreds of thousands of KBps. I'm not sure what else to try to combat this. I added a second progress bar showing individual file downloads which helps improve the image a bit, but the download speed counter should really be fixed. Is there a different class to use that would solve this problem?
The WebClient in this code is disposed of properly elsewhere.
private class NetSpeedCounter
{
private double[] DataPoints;
private DateTime LastUpdate;
private int NumCounts = 0;
private int PrevBytes = 0;
public double Speed { get; private set; }
public NetSpeedCounter(WebClient webClient, int maxPoints = 10)
{
DataPoints = new double[maxPoints];
Array.Clear(DataPoints, 0, DataPoints.Length);
webClient.DownloadProgressChanged += (sender, e) =>
{
var msElapsed = DateTime.Now - LastUpdate;
int curBytes = (int)(e.BytesReceived - PrevBytes);
PrevBytes = (int)e.BytesReceived;
double dataPoint = ((double)curBytes) / msElapsed.TotalSeconds;
DataPoints[NumCounts++ % maxPoints] = dataPoint;
Speed = DataPoints.Average();
};
}
public void Reset()
{
PrevBytes = 0;
LastUpdate = DateTime.Now;
}
}
I download the files with this code, which is started afterwards by a call to DownloadFileAsync. This code just downloads them in a chain, one after another, asynchronously.
This is setting up for starting the download
Queue recordQ = new Queue(files);
progressBar.Value = 0;
progressBar.Maximum = recordQ.Count;
UpdateStatusText("Downloading " + recordQ.Count + " files");
var record = recordQ.Dequeue();
speedUpdater.Start();
CheckAndCreate(record.AbsolutePath);
Adding the event handler
wc.DownloadFileCompleted += (sender, e) =>
{
var nr = recordQ.Dequeue();
CheckAndCreate(nr.AbsolutePath);
this.Invoke((MethodInvoker)delegate
{
UpdateStatusText("Downloading " + recordQ.Count + " files", lblStatusR.Text);
});
counter.Reset();
// download the next one
wc.DownloadFileAsync(nr.DownloadPath, nr.AbsolutePath);
}
counter.Start();
wc.DownloadFileAsync(record.DownloadPath, record.AbsolutePath);
This last call is what starts everything off.
DateTime.Now is not accurate enough for some scenarios where timespans are recorded frequently(Eric Lippert mentions that they have a precision of 30 ms here), since DateTime.Now will return the previously used DateTime.Now when called quickly in succession. This might result in discrepencies in your speed counter due to inaccurate increases when downloads are finished very quickly. I'd recommend using StopWatch API for that purpose.
EDIT
I have created the following test Winforms application based on your code that works fine for small files. I'm getting a reasonable 200 kbps over my intranet for 5 files that are about 2MB each. Just make sure you're calling the stopwatch classes at the right places.
To replicate, create a winforms app, create 3 labels of Id lblSpeed, lblStatus, lblFile and copy\paste the code and rename the URI's below to the files you want to test on.
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
Queue<Record> recordQ;
WebClient wc;
NetSpeedCounter counter;
//We store downloaded files in C:\TestDir (hardcoded in the Record class below)
public Form1()
{
InitializeComponent();
recordQ = new Queue<Record>();
//replace the URI string below. Nothing else to replace.
//recordQ.Enqueue(new Record(#"URI1", "SQLtraining.exe"));
//recordQ.Enqueue(new Record(#"URI2", "Project Mgmt.pptx"));
//first uri to process. Second param is the file name that we store.
Record record = new Record(#"URI0","Agile.pptx"); // replace the URI
//Initialize a webclient and download the first record
using (wc = new WebClient())
{
counter = new NetSpeedCounter(wc);
wc.DownloadFileCompleted += (sender, e) =>
{
if (recordQ.Count == 0)
{
UpdateStatusText("Done");
return;
}
var nr = recordQ.Dequeue();
//just create directory. the code uses the same directory
CheckAndCreate(nr.Directory);
//need not even use invoke here. Just a plain method call will suffice.
this.Invoke((MethodInvoker)delegate
{
UpdateStatusText("Left to process: " + recordQ.Count + " files");
});
counter.Reset();
counter.Start();
//continue with rest of records
wc.DownloadFileAsync(nr.DownloadPath, nr.GetFullPath());
this.lblFile.Text = nr.DownloadPath.OriginalString;
};
//just update speed in UI
wc.DownloadProgressChanged += wc_DownloadProgressChanged;
counter.Start();
//display URI we are downloading
this.lblFile.Text = record.DownloadPath.OriginalString;
//start first download
wc.DownloadFileAsync(record.DownloadPath, record.GetFullPath());
}
}
void wc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
this.lblSpeed.Text = counter.Speed.ToString();
}
public void UpdateStatusText(string msg)
{
this.lblStatus.Text = msg;
}
public void CheckAndCreate(string absPath)
{
if (!Directory.Exists(absPath))
Directory.CreateDirectory(absPath);
}
}
public class NetSpeedCounter
{
private int NumCounts = 0;
private int PrevBytes = 0;
private Stopwatch stopwatch;
public double Speed { get; private set; }
double[] DataPoints;
public NetSpeedCounter(WebClient webClient, int maxPoints = 10)
{
DataPoints = new double[maxPoints];
stopwatch = new Stopwatch();
Array.Clear(DataPoints, 0, DataPoints.Length);
webClient.DownloadProgressChanged += (sender, e) =>
{
var msElapsed = DateTime.Now - LastUpdate;
stopwatch.Stop();
int curBytes = (int)(e.BytesReceived - PrevBytes);
PrevBytes = (int)e.BytesReceived;
//record in kbps
double dataPoint = (double)curBytes / (stopwatch.ElapsedMilliseconds);
DataPoints[NumCounts++ % maxPoints] = dataPoint;
//protect NumCount from overflow
if (NumCounts == Int32.MaxValue)
NumCounts = 0;
Speed = DataPoints.Average();
stopwatch.Start();
};
}
public void Start()
{
stopwatch.Start();
}
public void Reset()
{
PrevBytes = 0;
stopwatch.Reset();
}
}
public class Record
{
public string Directory;
public string File;
public Uri DownloadPath;
public Record(string uriPath, string fileOutputName)
{
this.Directory = #"C:\TestDir\";
this.DownloadPath = new Uri(uriPath);
this.File = fileOutputName;
}
public string GetFullPath()
{
return this.Directory + this.File;
}
}
}
I have come up with a different way of doing it.
Instead of adding a data point for each ProgressChanged event, I now increment a counter with the amount of bytes. This counter stays across multiple files, and then I simply take a datapoint using a timer, and get the time in between using a System.Diagnostic.Stopwatch
It works very good, the accuracy is much much better, I would highly recommend doing it this way.
Here is some code
class NetSpeedCounter
{
private Stopwatch watch;
private long NumCounts = 0;
private int PrevBytes = 0;
private double[] DataPoints;
private long CurrentBytesReceived = 0;
public double Speed { get; private set; }
private System.Timers.Timer ticker = new System.Timers.Timer(100);
public NetSpeedCounter(WebClient webClient, int maxPoints = 5)
{
watch = new System.Diagnostics.Stopwatch();
DataPoints = new double[maxPoints];
webClient.DownloadProgressChanged += (sender, e) =>
{
int curBytes = (int)(e.BytesReceived - PrevBytes);
if (curBytes < 0)
curBytes = (int)e.BytesReceived;
CurrentBytesReceived += curBytes;
PrevBytes = (int)e.BytesReceived;
};
ticker.Elapsed += (sender, e) =>
{
double dataPoint = (double)CurrentBytesReceived / watch.ElapsedMilliseconds;
DataPoints[NumCounts++ % maxPoints] = dataPoint;
Speed = DataPoints.Average();
CurrentBytesReceived = 0;
watch.Restart();
};
}
public void Stop()
{
watch.Stop();
ticker.Stop();
}
public void Start()
{
watch.Start();
ticker.Start();
}
public void Reset()
{
CurrentBytesReceived = 0;
PrevBytes = 0;
watch.Restart();
ticker.Start();
}
}

Selecting a length of time with numericUpDowns and windows forms

I'm building an auto clicker application that makes the mouse click at a set interval of time.
Notice the interval configuration area. I have tried to write some logic that automatically simplifies the amount of time entered. The minutes box goes up to 60, the seconds box goes up to 60, and the milliseconds box goes up to 1000. I have a class set up to handle that logic, but it's probably not the right way to do that (I'm still new at programming).
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace AutoClicker {
public static class TotalTime {
public static int Interval(NumericUpDown m_, NumericUpDown s_, NumericUpDown ms_) {
int m = (int)m_.Value;
int s = (int)s_.Value;
int ms = (int)ms_.Value;
int total = 0;
total = total + (m * 60000);
total = total + (s * 1000);
total = total + ms;
return total;
}
public static void ChangeLogic(NumericUpDown m_, NumericUpDown s_, NumericUpDown ms_) {
int interval = Interval(m_, s_, ms_);
if (ms_.Value == 1000)
{
ms_.Value = 500;
s_.UpButton();
ms_.Value = 0;
}
if (s_.Value == 60 && m_.Value < 60)
{
if (ms_.Value == 0)
{
ms_.Value = 1;
s_.Value = 0;
m_.UpButton();
ms_.Value = 0;
}
else
{
s_.Value = 0;
m_.UpButton();
if (ms_.Value == 1)
ms_.DownButton();
}
}
if (ms_.Value == -1)
{
ms_.Value = 999;
s_.DownButton();
}
if (s_.Value == -1 & m_.Value > 0)
{
s_.Value = 59;
m_.DownButton();
if (ms_.Value == 1)
ms_.DownButton();
}
}
}
}
The ChangeLogic method is called each time the value in any of the boxes is updated.
There's lots of bugs in the selection logic. For example, when the up button for seconds is held down, the program crashes. If seconds = 59 and minutes = 0, and the seconds up button is pressed, the warning "you can't have a time less than 250 milliseconds" shows up and minutes is adjusted to 2.
I'm really confused. Can anyone help me? Thanks!
So, it looks like your intent is to have it so that when you up the milliseconds it then rolls up to the seconds once it hits 1000, then when your seconds hit 60 it rolls up to your minutes, etc etc.
Here is how I would accomplish this. First set all of your NUDs to max value of 99999. Then use code that looks something like this:
(Note the use of the intervalUpdating variable. This will make it so that you can hold that up button and while the intervalChanged() method is executing it wont try to execute it again.)
private void nudSeconds_ValueChanged(object sender, EventArgs e)
{
intervalChanged();
}
private void nudMilliseconds_ValueChanged(object sender, EventArgs e)
{
intervalChanged();
}
private bool intervalUpdating = false;
private void intervalChanged()
{
if (intervalUpdating)
{
return;
}
intervalUpdating = true;
if (nudMilliseconds.Value >= 1000)
{
var val = (int)nudMilliseconds.Value / 1000;
nudSeconds.Value += val;
nudMilliseconds.Value = (nudMilliseconds.Value - (val * 1000));
}
if (nudSeconds.Value >= 60)
{
var val = (int)nudSeconds.Value / 60;
nudMinutes.Value += val;
nudSeconds.Value = (nudSeconds.Value - (val * 60));
}
intervalUpdating = false;
}

How to improve this C# animation code

I have the code below which is an implementation of a marquee label. I'd like the marquee label to run at the most efficient rate possible on the computer while maintaining a constant speed across different computers. I'd like the amount of "frames" that are skipped to be minimized so that the program takes full advantage of the computer it's being run on. But at the same time I don't necessarily want to consume 100% of the CPU (are those statements contradictory? I'm not sure).
Currently I'm sleeping 10 milliseconds for each iteration of the animation loop. This feels wasteful to me and it seems like it might slow down the animation on slower computers that might need those extra 10 milliseconds. I'm not sure what the best value is to use in the sleep method or even if I should sleep at all. I've read some about Sleep(0) and Sleep(1) and Yield and SpinWait, but I can't make sense of it all.
Also is it a bad thing to call Invalidate too much? Can I overload it by calling it too much?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;
using System.Diagnostics;
using Timer = System.Timers.Timer;
using System.Threading;
namespace Scoreboard
{
public class MarqueeLabel : Label
{
private float _marqueeOffset;
private float _marqueeMeasurement;
public MarqueeLabel()
{
UseCompatibleTextRendering = true;
this.SetStyle(ControlStyles.DoubleBuffer, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.UserPaint, true);
Thread t = new Thread(ThreadRun);
t.IsBackground = true;
t.Start();
}
public void ThreadRun()
{
long time = DateTime.Now.Ticks;
long diff = 0;
while (true)
{
float step = -((float)diff / (20 * TimeSpan.TicksPerMillisecond)); //change "frame" based on the elapsed time
_marqueeOffset = _marqueeOffset >= -_marqueeMeasurement ? _marqueeOffset + step : Width;
Invalidate();
Thread.Sleep(10); // how long should i wait here?
long temp = DateTime.Now.Ticks;
diff = temp - time;
time = temp;
}
}
protected override void OnPaint(PaintEventArgs e)
{
StringFormat stringFormat = new StringFormat();
stringFormat.FormatFlags = StringFormatFlags.NoClip | StringFormatFlags.NoWrap;
stringFormat.Trimming = StringTrimming.None;
stringFormat.Alignment = StringAlignment.Near;
Rectangle rect = ClientRectangle;
rect.X += (int)_marqueeOffset;
e.Graphics.DrawString(Text, Font, new SolidBrush(ForeColor), rect, stringFormat);
}
protected override void OnTextChanged(EventArgs e)
{
base.OnTextChanged(e);
MeasureText();
}
protected override void OnFontChanged(EventArgs e)
{
base.OnFontChanged(e);
MeasureText();
}
void MeasureText()
{
_marqueeMeasurement = CreateGraphics().MeasureString(Text, Font).Width;
}
}
}

Thread.Sleep() in C#

I want to make an image viewer in C# Visual Studio 2010 which displays images one by one after seconds:
i = 0;
if (image1.Length > 0) //image1 is an array string containing the images directory
{
while (i < image1.Length)
{
pictureBox1.Image = System.Drawing.Image.FromFile(image1[i]);
i++;
System.Threading.Thread.Sleep(2000);
}
When the program starts, it stops and just shows me the first and last image.
Thread.Sleep blocks your UI thread use System.Windows.Forms.Timer instead.
Use a Timer.
First declare your Timer and set it to tick every second, calling TimerEventProcessor when it ticks.
static System.Windows.Forms.Timer myTimer = new System.Windows.Forms.Timer();
myTimer.Tick += new EventHandler(TimerEventProcessor);
myTimer.Interval = 1000;
myTimer.Start();
Your class will need the image1 array and an int variable imageCounter to keep track of the current image accessible to the TimerEventProcessor function.
var image1[] = ...;
var imageCounter = 0;
Then write what you want to happen on each tick
private static void TimerEventProcessor(Object myObject, EventArgs myEventArgs) {
if (image1 == null || imageCounter >= image1.Length)
return;
pictureBox1.Image = Image.FromFile(image1[imageCounter++]);
}
Something like this should work.
Yes, because Thread.Sleep blocks the UI thread during the 2s.
Use a timer instead.
If you want to avoid using Timer and defining an event handler you can do this:
DateTime t = DateTime.Now;
while (i < image1.Length) {
DateTime now = DateTime.Now;
if ((now - t).TotalSeconds >= 2) {
pictureBox1.Image = Image.FromFile(image1[i]);
i++;
t = now;
}
Application.DoEvents();
}

Categories