Change Label.Text based on the current time? - c#

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! :)

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 see if a value changed within an amount of time?

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.

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.

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).

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.

Categories

Resources