Latency issues with time between 2 events - c#

I had a task to make reflex meter app, and I got and exe as an example. I made it work but I don't get the same results from example I was given and my app, it's like I have 60-70 ms lost somewhere. App is supposed to show a text at random time between 0.5 and 5 seconds and when text shows, the user is supposed to click a button that will stop the stopwatch class I was using here and write it into last and best times.
First I was saving TotalMilliseconds , seconds , milliseconds and minutes as double , and now as TimeSpan, I felt as when I saved it in TimeSpan it reduced time but not enough to be close as example app or even online reflex app. I was thinking about delay between events or even mouse click, but I don't think its supposed to be like 50 60 ms. And if that is the problem how to measure those.
These are start events
private void Start_B_Click(object sender, EventArgs e)
{
Random rnd = new Random();
RndTimer.Interval = rnd.Next(500, 5000);
RndTimer.Start();
}
Stopwatch s = new Stopwatch();
private void RndTimer_Tick(object sender, EventArgs e)
{
NOW_L.Visible = true;
s.Reset();
s.Start();
Random rnd = new Random();
RndTimer.Interval = rnd.Next(500, 5000);
}
and this is button click event
public double o;
private void Click_B_Click(object sender, EventArgs e)
{
if (NOW_L.Visible == true)
{
s.Stop();
TimeSpan ts = s.Elapsed;
NOW_L.Visible = false;
if (LtimeRez_LB.Text == "00:00:00" || ts.TotalMilliseconds < class1.m)
{
LtimeRez_LB.Text = ts.Minutes.ToString() + ":" + ts.Seconds.ToString + ":" +
ts.Milliseconds.ToString();
BesttimeRez_LB.Text = ts.Minutes.ToString() + ":" + ts.Seconds.ToString + ":" +
ts.Milliseconds.ToString();
class1.m = ts.TotalMilliseconds;
o = class1.m;
}
else if (ts.TotalMilliseconds > o || ts.TotalMilliseconds == o)
{
LtimeRez_LB.Text = ts.Minutes.ToString() + ":" + ts.Seconds.ToString + ":" +
ts.Milliseconds.ToString();
}
NOW_L.Visible = false;
}
}
LtimeRez variable is label that is displaying last result and BestTimeRez is best time result, also I used public static double variable called m

Use the MouseDown event of the Button instead of the Click event. The Click event will only be triggered some time later than when the user pressed the mouse button on the control because it first waits for the user to also release the mouse button and because it also has to perform some internal tasks first (redrawing the button, validation checks).
Additional notes on the code:
Don't create a new instance of the Random class each time. Create one instance once and reuse it all the time. See How do I generate a random int number in C#?
In the Timer Tick function, only start the Stopwatch after setting the timer interval. The button will actually only become visible when the code leaves that function and has a chance again to process Windows messages.
Please give o and m some meaningful names. You don't need both variables. They always have the same value. You only need one of them.
In CLick_B_Click, you don't need the if in the else part.
In the current version of the code, when the user does not click immediately, the timer click event can happen multiple times before the user clicks the button, resetting the stopwatch too early...

One problem I am seeing here is string concatenation in you code. In C# world, while concatenating you should use String.Format() method. Using plus operator to join the string will add delay. So use below line to form string -
LtimeRez_LB.Text = String.Format("{0}:{1}:{2}", ts.Minutes, ts.Seconds, ts.Milliseconds);
~Nilesh

Related

How to save int in SharedPreferences c# when app is going to be closed?

I want to save number of clicks in SharedPreferences in moment when app going closed. Now I have function for that connected with one button
private void SaveClicks (){
var prefs = Application.Context.GetSharedPreferences("Name",FileCreationMode.Private);
var prefEditor = prefs.Edit();
prefEditor.PutInt("Key", nametest);
prefEditor.Apply();
}
"clicks" is name of int where I storage numbers of clicks in one of buttons
In what way I can do it automatically when app is going closed? Using onDestroy will be good solution?
//update
So I wrote that code:
protected override void OnDestroy()
{
var prefs = Application.Context.GetSharedPreferences("Name", FileCreationMode.Private); // 1
var prefEditor = prefs.Edit(); // 2
prefEditor.PutInt("Key", nametest); // 3
prefEditor.Apply(); // 4
}
And for counting clicks I have something like that
var prefs = Application.Context.GetSharedPreferences("Name", FileCreationMode.Private); // 1
var value1 = prefs.GetInt("key", 0);
if (clicks + value1 <= 499)
{
clicks++;
textViewBattlepackCount.Text = (clicks + value1).ToString() + " clicks!";
progressBarName1.Progress = progressBarName1.Progress + 1;
nametest= clicks + value1;
if (clicks + value1 == 500)
{
AlertDialog.Builder alertDialog = new AlertDialog.Builder(this);
alertDialog.SetTitle("You won!");
alertDialog.SetMessage("message");
alertDialog.SetNeutralButton("Ok", delegate
{
alertDialog.Dispose();
});
alertDialog.Show();
clicks = 0;
nametest= 0;
textViewTXTCount.Text = "0";
progressBarName1.Progress = progressBarName1.Progress = 0;
}
But the clicks in onDestroy() are storage only sometimes, one time there is correct number but another time after kill activity and restart app there is old number of clicks. I dont know why.
Sorry for chaotic description
It depends your requirement:
If u just want to store the numbers of click when the activity be killed. Using OnDestory()
If u want to store the numbers of click when the activity is in the background(e.g. you press the home button or another activity started), please using onPause();
onSaveInstanceState() can also be invoked before the activity destroyed, it can restore some temporary data (e.g. the text in EditText).
For your next question.
The SharedPreferences "key" should be covered when you call onDestory(), If not, please track the value of your "nametest" using debug
BTW
prefEditor.PutInt("Key", nametest);
var value1 = prefs.GetInt("key", 0);
Please using the same "Key" - -!!

Error message "Cannot evaluate expression because the current thread is in a stack overflow state"

I'm trying to create a recursive call to a method but receive error:
Cannot evaluate expression because the current thread is in a stack
overflow state
Just a bit of a background, I'm migrating a PowerBuilder app. to a C#.NET windows app., the PB app. has a timer that is done programmatically which will execute the main method at a specific time. The PB code runs on two machines, one timer is set at the '0' mark and on machine #2, it is set at the 30 second mark.
PB code below:
ue_wait event:
gi_offset = //Global variable set at the application open event, equivalent to program.cs - main event. Will be 0 or 30 depending on the machine.
li_difference = Integer( String( Now(), 'ss')) //Gets the seconds from the current date time.
DO UNTIL li_difference = gi_offset
ls_status = 'current second: ' + String( Now(), 'ss') + ' starting on:' + String( gi_offset)// Builds a string to display in a static text control in PB, label in C#.
IF st_status.Text <> ls_status THEN st_status.Text = ls_status
Yield()
li_difference = Integer( String( Now(), 'ss'))
LOOP
//execute main processing method.
ue_action().
//End of event
ue_action event
Do main processing.
Call ue_wait()
My C# code below:
private void Form1_Shown(Object sender, EventArgs e)
{
ue_wait();
}
private void wf_actions_Load(object sender, EventArgs e)
{
//Should fire after all of the form has loaded.
Shown += Form1_Shown;
}
private void ue_wait()
{
long todays_date_in_seconds = DateTime.Now.Second;
long ll_global_offset = 0;
string ls_status = "";
todays_date_in_seconds = DateTime.Now.Second;
while (!(todays_date_in_seconds == ll_global_offset))
{
ls_status = "Current second: " + DateTime.Now.Second.ToString() + " starting on: " + ll_global_offset.ToString();
lbl_status.Text = ls_status;
todays_date_in_seconds = DateTime.Now.Second;
}
ue_action();
}
private void ue_action()
{
//After the main processing is done, it goes back to ue_wait().
ue_wait();
}
So I have tried the two possibilities that I found on the Inet:
this.Shown += new System.EventHandler(this.Form1_Shown);
this.Activated += AfterLoading;
However when calling ue_action I get the error below in the ue_wait event for both...
{Cannot evaluate expression because the current thread is in a stack
overflow state.}
Fails on the first line: long todays_date_in_seconds = DateTime.Now.Second;
I found the .NET timer but it does not allow you to set the Start at a specific point in time, ie: seconds, Timer.Start() = 0 mark or Timer.Start() = 30 second mark (30000 milliseconds). The interval is one part that would work as I could set it to execute every 60 seconds.
After doing some googling, because there is 'recursive' programming, this is causing the 'Stack Overflow', how can I avoid the 'Stack Overflow' in the .NET environment or would there be another way to do what I need to do in the C#.NET environment?
The simplest approach would be to use a 1s System.Windows.Forms.Timer, that's a no brainer:
// timer initialization, somewhere
timer = new System.Windows.Forms.Timer();
timer.Interval = 1000;
timer.Tick += Timer_Tick;
DateTime? _lastHandledTimestamp = null;
private void Timer_Tick(object sender, EventArgs e)
{
// get current timestamp
var currentTimestamp = DateTime.UtcNow;
var currentSecond = currentTimestamp.Second;
// not the correct second yet?
if (currentSecond <= TARGET_SECOND)
return;
// truncate seconds and check if we already handled this hh:mm
var flooredToNearestMinute = currentTimestamp.AddSeconds(-currentSecond);
if (_lastHandledTimestamp.HasValue &&
_lastHandledTimestamp.Value >= flooredToNearestMinute)
return;
// if we're here, we are good to go
_lastHandledTimestamp = flooredToNearestMinute;
DoStuff();
}
If you want to avoid triggering the tick event every second, use a System.Threading.Timer instead, and use its Timer.Change method to calculate the next time it needs to fire on each iteration.
Groo, thanks for the input on the timer, I tweaked it for what I need to do.
private void timer1_Tick(object sender, EventArgs e)
{
string ls_status = "";
var currentSecond = DateTime.Now.Second;
ls_status = "Current second: " + currentSecond.ToString() + " starting on: " + Il_offset.ToString();
lbl_status.Text = ls_status;
if (currentSecond == Il_offset && Ib_processing_completed)
{
//Main processing method
ue_action();
}
}
In the Tick event, I populate an instance variable of offset in the PageLoad, in this case it will be 1 or 31 and set a Boolean variable to true in the ue_action event after successful processing.
To get rid of the original problem, instead of doing recursive programming and looping, the Tick event was recommended instead which meets my needs.
Thank you, the .NET learning curve begins.
William.

calculate difference in times over days c#

I am trying get setup a Recording Time label so that when a user clicks a button it starts and when they click another button it stops.
I have tried two different things which have not worked.
Setting a Ticker and increment a value by 1 and displaying it.
This did not work as i am also doing other things in the ticker which means it might take 1.5 seconds but i'm increment by 1, therefore the longer the recording goes on the more inaccruate it is.
Getting the TimeOfDay when the stream starts and on the ticker method getting the TimeOfDay and subtracting them.
This is not working because if the recording is left overnight the time turns into minuses I.E -67647.74 seconds.
private void StreamClick_Click(object obj)
{
_streamStartTime = DateTime.Now.TimeOfDay;
}
private void LiveVideoStream_Tick(VideoCaptureDevice cam)
{
_currentRecordTime = DateTime.Now.TimeOfDay - _streamStartTime;
RecordTime = _currentRecordTime.ToString();
}
Does anyone have any other ideas how I can display a nice timer.
Your _streamStartTime should be a DateTime too. Then in your Click event handler, assign DateTime.Now to it, don't use TimeOfDay only:
private void StreamClick_Click(object obj)
{
_streamStartTime = DateTime.Now;
}
Then in your calculation, you simply need to negate the two DateTime to get TimeSpan. Use the TimeSpan to produce your time string:
private void LiveVideoStream_Tick(VideoCaptureDevice cam)
{
TimeSpan _currentRecordTime = DateTime.Now - _streamStartTime;
string RecordTime = _currentRecordTime.TotalDays.ToString() + " " + _currentRecordTime.Hours.ToString() + ":" +
_currentRecordTime.Minutes.ToString() + ":" + _currentRecordTime.Seconds.ToString();
}
Do not use DateTime.Now because the system clock can jump backwards or forwards on rare occasions. DateTime.UtcNow is a lot safer - no daylight saving - but still not bulletproof.
You should use StopWatch instead.

Logic trouble with loop

I am creating a windows form that is a random number guessing game. I've made these before in C++ and never had an issue, however I have a big one here- I have no idea how to get the user back to input a number after the loop has began running. Here is my code:
private void btnGuess_Click(object sender, EventArgs e)
{
int guess = 0;
int count = 0;
int accumulator = 0; // accumulator
Random rand = new Random();
int number = rand.Next(1, 100);
txtAnswer.Focus();
while (guess != number)
{
guess = int.Parse(txtAnswer.Text);
if (guess < number)
{
MessageBox.Show("Too Low! Guess again!");
txtAnswer.Text = "";
txtAnswer.Focus();
count++;
accumulator++;
}
else if (guess > number)
{
MessageBox.Show("Too High! Try again!");
txtAnswer.Text = "";
txtAnswer.Focus();
count++;
accumulator++;
}
else
{
MessageBox.Show("Correct! you guessed the number in " + accumulator + " tries!");
break;
}
}
}
}
}
I just filled the while loop arguments with something for you guys, even though i know it won't work. Basically, I need to run the loop, get feedback (if the users guess was too high or low) then get the user to be able to input another number BEFORE the loop runs again. I don't know how to get that to happen with a text box control which is where the input will be. Any ideas?
You should not loop inside in the btnGuess_Click. Instead you need to store the state (the number, count, and the accumulator variables) in the scope of the form itself.
Initialize the random number when the form loads, or using some kind of start button.
Then inside the guess button handler, read the text box value and compare it to the number variable, such as what you are doing currently.
What you are building is more a console style application. So there is 1 main loop that is executing all the code.
In forms applications it is an event driven environment. So the user gets a form, presses a button, the form is evaluated and then the method handling ends.
So you have on a class level some variables for counts, in the constructor you add the initialization and the method for submit will be something like
private void btnGuess_Click(object sender, EventArgs e)
{
//Increment counters
//Check
//Show feedback
//Leave the button click code
}
For some more info, check this out:
https://msdn.microsoft.com/en-us/library/dd492132.aspx

How to check if an incident happened during a time frame in C#?

I am developing software that adds if a button is clicked 5 times, a variable is incremented by '1'
IF A then B++
everything is good, but now I want the system to reset its counter if that 5 times did not happen within 10 seconds. I.e the speed of clicking matters.
If I click too slow, the increment should not happen even though I clicked 5 times as it exceeds that 10 secs period.
Any suggestion?
This could be done much nicer but it should work:
DateTime time = new DateTime();//time of first click
int counter = 0;
void button_click(object sender, EventArgs e)
{
if(counter == 0)
{time = DateTime.Now}
else if(counter == 5)
{
if( DateTime.Now.Subtract(time).Duration().Seconds <= 10)
{/*Do some cool stuff*/}
else
{counter = -1;}
}
counter++;
}
I'd do something like this:
const int ClicksRequired = 5;
readonly TimeSpan ClickTimeSpan = new TimeSpan(0, 0, 10);
Queue<DateTime> _clicks = new Queue<DateTime>();
private void clickTarget_MouseUp(object sender, MouseEventArgs e)
{
var currentTime = DateTime.Now;
_clicks.Enqueue(currentTime);
if (_clicks.Count == ClicksRequired)
{
var firstTime = _clicks.Dequeue();
if (currentTime - firstTime <= ClickTimeSpan)
{
MessageBox.Show("Hello World!");
_clicks.Clear();
}
}
}
I use Queue to keep track of clicks because you don't know which mouse click will actually be the first click until you have five clicks in the time window. You need to know the time of the fifth click back in time and that click changes with each subsequent click.
I use MouseUp instead of Click because Click might not fire the correct number of times if clicks occur within the system double-click interval (because those get routed to DoubleClick).

Categories

Resources