How to see if a value changed within an amount of time? - c#

I'm using an asynchronous method that sets a value. I want to see if the value remains the same within 10 seconds. If the value didn't change in this amount of time, it should enable a flag to do something else.
Is there a simple way to do it?
The timer should start when the value is changed and be checked (let's say maybe not every time which would be overkill but every 0.5 seconds) until the timer reached 10 seconds and then execute a method or change the value of a flag to false for example.
As I tried with another async method to be triggered when the value changed it didn't work. And it seemed to me to be very complicated to do.
/// <summary>
/// Asynchronously sends the commands to CWI
/// </summary>
private async void SendCommandToCWI(object sender, EventArgs e)
{
await Task.Delay(1);
System.Windows.Application.Current.Dispatcher.Invoke(() =>
{
//Here is some logic that will calculate many things to get the value of _axisX and _axisY.
//I deleted this part to show the code as it was unnecessary.
if (!(_axisX == 0 && _axisY == 0) && (PortVM != null) && PortVM.IsOpen)
{
CommandSender.AxisX(_axisX);
Thread.Sleep(50);
string indata = PortVM.ReadExisting();
//Debug.Print("Data Received:");
//Debug.Print(indata);
Console.WriteLine(_axisY);
Console.WriteLine(_axisX);
CommandSender.AxisY(_axisY);
}
else
{
PanelX = 0;
PanelY = 0;
_TimerInside.Stop();
_axisX = 0;
_axisY = 0;
CommandSender.AxisX(0);
CommandSender.AxisY(0);
CommandSender.AxisX(_axisX);
CommandSender.AxisY(_axisY);
}
});
}
So basically I want to see if every time I calculate _axisX and _axisY that after 10 seconds if the results remains the same it should whatever call a method or set a flag from true to false.

Related

Autoclicker calculation

I'm making autoclicker program and I already have an issue. I want my program to be able to change the clicks per second field just how the user wants it. So I made this.
private void textBoxCps_TextChanged(object sender, EventArgs e)
{
try
{
time = Convert.ToDouble(textBoxCps.Text);
time = 1000 / time;
Math.Round(time);
}
catch (Exception)
{
}
}
The math is right(I think...)
while (IsRunning)
{
if ((Control.ModifierKeys & Keys.Alt) != 0)
{
DoMouseClicks();
Thread.Sleep(Convert.ToInt32(time));
}
else
{
}
}
When I try to put 1 CPS into the textbox it does 1 click per second, the same for 2 and 3 but when it's 4 and higher I'm getting 3.80 and lower CPS.
So the operator types some text that should represent a period of time (TimeSpan), and after running is started, you want to call method DoMouseClicks every TimeSpan, until running is stopped.
One of the problems is, that while you are doing this procedure you want your user input to be responsive.
Instead of Sleep, you should use one of the windows timers. There are several of them, and each have their advantages and disadvantages. In your case, the timer that you use depends on the accuracy that you need. See this article for a comparison between the various timers
Is it a problem if the clicks are a bit delayed if the user thread is busy? If not, the easiest is a System.Timers.Timer
System.Timers.Timer timer = new System.Timers.Timer()
timer.Elapsed += TimerElapsed;
private void TimerElapsed(object sender, ...)
{
DoMouseClicks();
}
To change the interval:
TimeSpan TimerInterval
{
get => TimeSpan.FromMilliseconds(this.timer.Interval);
set => this.Timer.Interval = value.TotalMilliseconds;
}
I decided to use a TimeSpan as interval time. This way you code changes are minimal if in future versions you decide to let the operator type his interval times in seconds, or in time format ("01:00")
To start and stop the timer:
private bool IsTimerStarted
{
get => this.timer.Enable;
set => this.timer.Enabled = value;
}
Now we are ready to react on operator input. You decided to act on TextBoxChanged. Are you sure you want this? What happens if an operator wants to type "1000", to indicate one second time interval. He starts by typing "1", you immediately start the mouse clicks with a frequency of 1 msec. Is this what you want?
Another problem: if the operator makes a typing error: "10)0", instead of "1000"?
A proper user interface would let the operator indicate that he finished typing the interval by pressing a button. When the button is pressed you read the text. If there is an error, you notify the operator, if not, you start the timer.
An alternative is to disable the button as long as the text box contains invalid text. Although this seems nice, the disadvantage is that the operator does not know why his button is not enabled.
private void OnButtonStart_Clicked(object sender, ...)
{
TimeSpan intervalTime = this.ReadTextBoxInterval();
this.TimerInterval = intervalTime;
this.IsTimerStarted = true;
// if desired: show the operator that the action is running
}
private void OnButtonStop_Clicked(object sender, ...)
{
this.IsTimerStarted = false;
// if the timer was handling event Elapsed, it is finished neatly.
// if desired show the operator that the action is stopped.
}
I decided to separate the action from the interpretation of the operator input. This way, code changes are minimal if you decide to change the operator input from msec to seconds, or even time format ("00:01"). Or if you decide to use a ComboBox instead of an edit box.
TimeSpan ReadTextBoxInterval()
{
string textBoxText = this.TextBoxInterval.Text;
return IntervalFromMsecText(textBoxText);
}
TimeSpan IntervalFromMsecText(string intervalText)
{
if (Double.TryParse(intervalText, NumberStyles.Any, CultureInfo.CurrentCulture,
out double msecInterval))
{
// input is a proper double
return TimeSpan.FromMilliseconds(msecInterval);
}
else
{
// invalid input. Notify the operator?
}
}

How to Make looping Execute When Statement Is False in c#?

I Make WinForms App for execute ssis package , and i want to make timer with datepicker so when i choose datepicker at 5pm the method will be executed at 5pm. I Have difficulty to make that happen first i tried this with do while but it will just stop executing when the statement is false and will always executing when statement is true, what i want to create is otherwise, i want to the looping is like checking not executing , so it will always looping for checking and will be executed only when statement is true
do
{
Executed();
}
//Label3 is DateTimeNow
while (dateTimePicker1.Text == label3.Text);
so the logic is something like that, but the opposite way, the code will looping until the statement is true when normally the statement start from true and will stop looping when statement false, and what i try to achive is the statement is start from false and will keep checking till statement is true. Can we do that ? thanks
Instead of having a loop to check whether the value of DateTimePicker is desired, you should use a Timer and handle its Tick event to check if the DateTime.Now is the desired time:
bool handled = false;
private void timer1_Tick(object sender, EventArgs e)
{
var d1 = DateTime.Now;
var d2 = dateTimePicker1.Value;
if (d1.Year == d2.Year && d1.Month == d2.Month && d1.Day == d2.Day &&
d1.Hour == d2.Hour && d1.Minute == d2.Minute)
{
if (!handled) //Allow running once
{
handled = true;
DoSomething();
}
}
}
Note 1: To make above example working, make sure you set the Interval property of the timer to 30000 to run every 30 seconds and also Start the timer whenever you want the scheduler start monitoring. Then the DoSomething method will run at exact time (up to minute level) which you set using DateTimePicker. You can change the criteria based on your requirement, for example to make it run every day at the specified time, you can remove d1.Day == d2.Day.
Note 2: :Scheduling libraries like Quartz are created to let you create scheduled task in your application easily.
You can use the not operator "!"
while (dateTimePicker1.Text != label3.Text);

New to threading, need help making a static variable thread safe with background worker

As the title suggests, I'm new to the concept of threading and I'm learning as I go. I'm working on a program as part of a research project involving a 3D printer. I have two pieces of hardware I need to interface with: a small stage that moves up and down, and a force sensor that can detect when an object on the stage makes contact with the sensor which acts as the signal to stop moving the stage. As I said, I'm new to the whole threading concept, so I'm not even sure if I'm designing this correctly, if I should use backgroundworker or the Thread class, how to ensure thread-safety, etc.
I"m writing the program in C# using Windows Forms and decided to use two background worker controls in Visual Studio/.NET Framework, one to monitor the force sensor reading and the other to control the stage moving up and down.
It has to be fast and accurate; the stage needs to stop moving the moment a pre-defined sensor value is detected. I have two static classes, a ZStageControl static class and a ForceSensorControl static class.
ForceSensorControl has a method called UpdateSensor() which returns the current value of the force sensor, and the ZStageControl has a private static bool variable, forceDetected (set to false by default), a public property ForceDetected that gets/sets this variable, and a method called GoodToMove. GoodToMove is defined as follows:
public static bool GoodToMove()
{
if (forceDetected == true ||
Position() < MinHeight ||
Position() > MaxHeight)
return false;
else
return true;
}
My sensor update backgroundworker dowork code is defined as follows:
private void sensorUpdateBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
double currentForceValue;
while (ForceSensorControl.IsConnected() == true)
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
try
{
currentForceValue = Double.Parse(ForceSensorControl.UpdateSensor());
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
disconnectForceSensor();
return;
}
if (currentForceValue >= forceSensorStopValue)
{
if (this.ForceDetected != null)
{
this.ForceDetected(this,
new ForceDetectedEventArgs(ZStageControl.Position(), currentForceValue));
}
}
else if (ZStageControl.ForceDetected == true)
ZStageControl.ForceDetected = false;
forceSensorValueLabel.Text = currentForceValue.ToString() + "g";
}
}
}
So as long as the sensor remains connected, continuously loop and update the force sensor vlaue. If it detects the proper force value, it fires the ForceDetected event. If it reads the value as less than the force sensor stop value, but ForceDetected is still set to true, it simply sets to false (since when the force is detected, it will stop the stage from moving and then return it to its default position, so it should reset the force detected variable).
The event code is defined as follows:
public void FormMain_ForceDetected(object sender, ForceDetectedEventArgs e)
{
if (ZStageControl.ForceDetected == true)
return;
ZStageControl.ForceDetected = true;
feedbackRichTextBox.Text += "\nForce Detected at position " +
e.ForceDetectedPosition.ToString() + " with a value of " +
e.ForceDetectedValue.ToString() + "\n";
ScrollToEndOfFeedbackBox(feedbackRichTextBox);
soundPlayer.Play();
}
The thread to move the Z-Stage up or down is defined as follows:
private void zStageMoveBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
ZStageMoveDirections direction = (ZStageMoveDirections)e.Argument;
while (ZStageControl.IsConnected == true)
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
System.Threading.Thread.Sleep(zStageSpeed);
if (direction == ZStageMoveDirections.Down)
{
ZStageControl.MoveDown(true);
}
if (direction == ZStageMoveDirections.Up)
{
ZStageControl.MoveUp(true);
}
zStagePositionUpdateLabel.Text = ZStageControl.Position().ToString();
}
}
}
The code that calls the DoWork event for the Z-Stage move is controlled by an if statement that checks if ZStageControl.GoodToMove() is true. So while GoodToMove() returns true, the Z-Stage thread can fire.
The issue I'm having is that I'm not sure if I'm designing this right, if I'm using the backgroundworker properly, and I know my variables are not thread-safe because at certain points GoodToMove() returns true and other times it returns false, even though there is clearly no force being detected. It seems to have a mind of its own. I just know nothing about thread-safety. Should I simply use the THread class instead of the background worker, is there a certain way to ensure the forceDetected variable/GoodToMove() method operates properly across these threads?
I think your approach is inherently flawed.
You seem to be designing a system with a constantly looping monitor and then a check of that monitor when you want to execute a "move."
This is inherently problematic because you've created a race condition between your safety check operation and your move operation.
Consider this:
1 // check if move is ok -- PASS
(async) // move suddenly becomes not ok!
2 // move is executed
Instead you should think about this problem as entirely synchronous (as validation checks and executions should be entirely atomic). Whenever a move is requested you should check if it's permitted and then decide whether or not to execute.
1 // exclusive lock
2 // check if move is ok -- PASS
3 // execute move
4 // release lock

C# 10 second timer on combox selected Index

After being out of scripting for ages I have decided to learn a programming language and I have gone for C#. I'm getting along pretty well but now for the first time I seem to have been faced with a problem that I have not been able to solve with google.
I am making a simulated aircraft system as a learning exercise and I want to invoke a loop when an option is selected from a drop down combobox.
I have a combobox/list with three options which simulates the starter switch, the values are (0)Off, (1)On, (2)Ignition Only . In the real aeroplane, when 'On' is selected the switch locks in place for 10 seconds and then releases. So what I am trying to achieve is :
private void comboBox2_SelectedIndexChanged(object sender, EventArgs e)
{
if (starterRight.SelectedIndex == 0)
{
//Starter is off
eng2Start.Value = 0;
}
if (starterRight.SelectedIndex == 1)
{
//starter is on
//Start Timer
eng2Start.Value = 1;
if (eng2Tourqe >= 6000)
{
//open fuel valve
// set Hot Start counter to 0
}
else
{
//ensure fuel valve stays closed
// set Hot Start counter to x+1
}
// End of Timer
// set selected index back to 0
(starterRight.SelectedIndex == 0)
}
}
I have googled and googled and the more I read the more I am getting lost in this. I have found answers containing a mass of code which I am not able to fully decipher just yet.
Is it possible to do what I want to do?
Thanks in advance for your time.
You can Add Timer to your Form and Set the Interval property to 10000(10 seconds).
from code:
if (starterRight.SelectedIndex == 1)
{
//starter is on
//Start Timer
timer1.Enabled=true;
}
//in timer tick Event write the following:
private void timer1_Tick(object sender, EventArgs e)
{
timer1.Enabled=false;
//Statements to start aircraft
}
You could achieve this by setting it to true (or selected, or whatever you want) sleeping for 10 seconds, like this:
Thread.Sleep(10000) ;
and then set it back to false (or unselect, or whatever you want)
Another way to go would be to start a background thread that will sleep for ten seconds, and then call a method that will "unset" the button, this way, not blocking the GUI ...
Or depending on what you're using, I could probably come up with other options, but i'll take it you're trying to learn the basics atm ... :)
See this one msdn timer
And you can use Threed.Sleep(10000);
I think this should works. I didn't compile it, but with this you lock the swtich, do your stuff checking a timer that when arrives to 10 sec, re-enable your switch.
private void comboBox2_SelectedIndexChanged(object sender, EventArgs e)
{
if (starterRight.SelectedIndex == 0)
{
//Starter is off
eng2Start.Value = 0;
}
if (starterRight.SelectedIndex == 1)
{
//starter is on
starterRight.enable = false;
StopWatch sw = new StopWatch();
sw.Start();
eng2Start.Value = 1;
if (eng2Tourqe >= 6000)
{
//open fuel valve
// set Hot Start counter to 0
}
else
{
//ensure fuel valve stays closed
// set Hot Start counter to x+1
}
if (sw.ElapsedMilliseconds <= 10000)
{
do
{
//Dummy Loop
}
while (sw.ElapsedMilliseconds > 10000)
sw.Stop();
}
else
{
// set selected index back to 0
sw.Stop();
starterRight.Enabled = true;
(starterRight.SelectedIndex == 0)
}
}
}
You can use a Timer and the Tick event. Disable your switch, and when the Timer tick, Enabled it.
Timer timerSwitchOn;
public SomeConstructor()
{
timerSwitchOn = new Timer(){Interval = 10*1000}; // 10 seconds
timerSwitchOn.Tick += new EventHandler(timerSwitchOn_Tick);
}
private void comboBox2_SelectedIndexChanged(object sender, EventArgs e)
{
if (starterRight.SelectedIndex == 1)
{
//starter is on
starterRight.Enabled = false;
timerSwitchOn.Start();
}
}
void timerSwitchOn_Tick(object sender, EventArgs e)
{
timerSwitchOn.Stop();
starterRight.Enabled = true;
// set selected index back to 0
starterRight.SelectedIndex = 0;
}
In my initial question I said I had wanted to invoke a loop, I meant a timer but it seems that you all figured that out.
Thank you for the rapid answers, I am going to get stuck into them this weekend and see if I can solve my problem.

Change Label.Text based on the current time?

How might I be able to change the Text property of a label depending on what the current time is?
Thank you
To clarify:
I'd like the text of a label to read open between 10am and 5pm and then read closed between 5:01 pm to 9:59am.
Use a Timer. In the Timer.Tick handler, modify the label's Text property using a simple if/else statement based on DateTime.Now.
int hour = DateTime.Now.Hour;
if (hour >= 10 && hour < 17)
//Open 10:00am through 4:59pm
LabelStatus.Text = "Open";
else
//Closed 5:00pm through 9:59am
LabelStatus.Text = "Closed";
Below is a method to do this using a separate thread that updates the label. This way the thread will run in the background, and constantly check that the label is at the correct status. Make sure when closing the form you stop the thread, either by using Thread.Abort() and catching the exception that I believe is always thrown, or by adding a flag as the condition in the while loop, and lower the flag to stop the thread.
As long as no other object accesses the label, there shouldn't be any need to lock any part of the thread.
public delegate void DelLabelText(Label l, string s);
public DelLabelText delLabelText;
public Form1()
{
InitializeComponent();
delLabelText = Label_Text;
// Initialize text
lblOpenStatus.Text = "Closed";
// Create and start thread
Thread threadUpdateLabel = new Thread(UpdateLabel_Threaded);
threadUpdateLabel.Start();
}
// Thread function that constantly checks if the text is correct
public void UpdateLabel_Threaded()
{
while (true)
{
Thread.Sleep(5000);
// 24 hour clock so 17 means 5
if ((DateTime.Now.Hour >= 10 && DateTime.Now.Hour < 17) || (DateTime.Now.Hour == 17 && DateTime.Now.Minute == 0 && DateTime.Now.Second == 0))
{
if (lblOpenStatus.Text.ToLower() == "closed")
{
Label_Text(lblOpenStatus, "Open");
}
}
else
{
if (lblOpenStatus.Text.ToLower() == "open")
{
Label_Text(lblOpenStatus, "Closed");
}
}
}
}
// Set the text using invoke, because text is changed outside of main thread
public void Label_Text(Label label, string text)
{
if (label.InvokeRequired)
{
label.Invoke(delLabelText, new object[] { label, text });
}
else
{
label.Text = text;
}
}
Add a timer to your form and set its interval to 1000 ms..
Declare a invisible TextBox having the Miliseconds of the current time updated by the Timer on Every Tick..
now on the TextBox.TextChanged event of the Textbox Add a Function to Convert the Milliseconds to Time...
Next Method is add a Timer and set the interval to 1 ms...
Update the time from there..
Next Method, is adding a BackgroundWorker and use it as a Timer to update the Time...
If you find any of the above methods useful...Comment and I will post codes! :)

Categories

Resources