I'm currently working with a Bluetooth module, for which my application automatically scans in order auto-connect.
What i'm trying to achieve though, is to implement a restriction in terms of the amount of time that the application is allowed to scan for the module. I figured that it made good sense to use system.threading.Timer for this purpose, to run behind code.
if(c = 1)
{
bleText.Text = "Scanning...";
Scan_Function();
}
Private void Scan_Function()
{
//Timer stuff
}
However, i'm unaware if this is the correct way of doing it, and how i might be done.
You don't need a timer, just get the time when task starts and subtract it from the time it ends:
Private void Scan_Function()
{
DateTime start = DateTime.Now;
//Timer stuff
double milliSecondsElapsed = (DateTime.Now - start).TotalMilliSeconds;
}
Of course you can use these 2 lines outside the method too:
DateTime start = DateTime.Now;
Scan_Function()
double milliSecondsElapsed = (DateTime.Now - start).TotalMilliSeconds;
Related
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?
}
}
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.
I have an application in which I have to logout after say x seconds of inactivity.
I therefore have a timer going on and calculating a timespan from the last user acitivity resetted with:
dtLastActivity = DateTime.Now;
So the problem is that I don't think it's the best approach to associate EVERY single event in my program with the afore mentioned code.
But in the end I don't need EVERY event: all what is useful is to track KEYPRESS and MOUSEUP.
Would it be correct to track those two event in the MainWindow?
I have to admit that I still have not put into practice this (but I will) for I am not sure that this is the best approach for the purpose in the title.
Being new to WPF I am also not clear if tracking keyboard and mouse in the mainwindow shall not affect the behaviour in the children (that are the controls that effectively are the target of the event).
Thank you in advance for any help.
---EDIT---
The proposed solutions are very elegant. Particularly this one:
public static class IdleTimeDetector
{
[DllImport("user32.dll")]
static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
public static IdleTimeInfo GetIdleTimeInfo()
{
int systemUptime = Environment.TickCount,
lastInputTicks = 0,
idleTicks = 0;
LASTINPUTINFO lastInputInfo = new LASTINPUTINFO();
lastInputInfo.cbSize = (uint)Marshal.SizeOf(lastInputInfo);
lastInputInfo.dwTime = 0;
if (GetLastInputInfo(ref lastInputInfo))
{
lastInputTicks = (int)lastInputInfo.dwTime;
idleTicks = systemUptime - lastInputTicks;
}
return new IdleTimeInfo
{
LastInputTime = DateTime.Now.AddMilliseconds(-1 * idleTicks),
IdleTime = new TimeSpan(0, 0, 0, 0, idleTicks),
SystemUptimeMilliseconds = systemUptime,
};
}
}
but it is too automatic. I have no control over it.
E.g. if I use it from the beginning it gets idle BEFORE starting because my application has a quite long start time with splash screen, deserialization etc...
The solution proposed by Fruchtzwerg is much more similar to my needs because I get complete control over it. It has also the advantage that if I click on another application the timer is not resetted!!
I usually use the approach described by you. I running a timer and restart every interaction. The events of a window are:
PreviewMouseDown="Window_Action"
PreviewKeyDown="Window_Action"
Restarting the timer:
private void Window_Action(object Sender, InputEventArgs e)
{
IdleTimer.Stop();
IdleTimer.Start();
}
Never had any prolmems with this soultion. Restarting the timer takes under 80 ticks with a stopwatch. So the resources are in my opinion no problem.
Also you can specify the userinteractions by adding terms in your event.
The Preview-Events are not disturbing other events. This tunneling-behavoiur is described here.
I have recently implemented a scrolling text across an area of limited screen estate using a timers repeating every 100ms, and some simple string appending.
However, after this very implementation, I have come to realise that my GUI is getting randomly bugged/corrupted after a certain while. That is to say that some widgets/windows become completely white, and eventually the entire GUI turns white and unclickable.
What is weird is that there is no error debug output at all.
Having said that, I am using Mono with GTK-Sharp for the application. Does anyone have an idea or a possible clue how and why this is happening?
If not, how can I further debug this properly?
Thanks, really appreciate it.
PS: Sometimes, it takes up to 1.5 hours for the thing to start corrupting, it has random timeframes for it to start happening.
This is my the code implemented that caused this issue:
void ScrollSyncTo(object sender, System.Timers.ElapsedEventArgs e)
{
//initial check if it fits nicely alr
if (sync_to_full_txt.Length <= sync_to_max_char)
{
sync_to_timer.Stop();
return;
}
//check for pause
if (sync_to_pause >= 0)
{
sync_to_pause--;
return;
}
//check direction
int temp_psn;
string temp_str;
if (sync_to_direction)
{
temp_psn = sync_to_posn + 1;
if (sync_to_full_txt.Substring(temp_psn).Length < sync_to_max_char)
{
sync_to_pause = sync_to_break_steps;
sync_to_direction = false;
sync_to_posn = sync_to_full_txt.Length - 1;
System.GC.Collect();
return;
}
else
{
temp_str = sync_to_full_txt.Substring(temp_psn, sync_to_max_char);
}
}
else
{
temp_psn = sync_to_posn - 1;
if (temp_psn + 1 < sync_to_max_char)
{
sync_to_pause = sync_to_break_steps;
sync_to_direction = true;
sync_to_posn = 0;
System.GC.Collect();
return;
}
else
{
temp_str = sync_to_full_txt.Substring(temp_psn - sync_to_max_char + 1, sync_to_max_char);
}
}
//lets move it
sync_to.Text = temp_str;
sync_to_posn = temp_psn;
}
To program in GTK with multiple threads, you have to do a couple things to make your program thread-safe. Here is short explanation using C.
I'm more familiar with GTK in C, but I'm assuming it works the same in GTK#. So you have to call GLib.Thread.Init() and Gdk.Threads.Init() at the beginning of your program, bracket your call to Application.Run() with Gdk.Threads.Enter() and Gdk.Threads.Leave(), and also make sure any GTK and GDK calls in background threads (not GTK signal handlers) are between Gdk.Threads.Enter() and Gdk.Threads.Leave().
System.Timers.Timer callbacks come from a threadpool thread, but GTK objects can only safely be accessed from the GTK thread. I would suggest using GLib.Timeout, which runs on the GTK thread.
Is there an object that will event at a given DateTime or DateTimeOffset? I am using a Timer to do this operation now but it requires a bit of calculation on my part, was just thinking there might already be something in place.
I don't see how you have to do any calculation:
public void StartTimer(DateTime target) {
double msec = (target - DateTime.Now).TotalMilliseconds;
if (msec <= 0 || msec > int.MaxValue) throw new ArgumentOutOfRangeException();
timer1.Interval = (int)msec;
timer1.Enabled = true;
}
I like:
System.Timers.Timer _WaitForScheduledTime;
_WaitForScheduledTime = new System.Timers.Timer();
_WaitForScheduledTime.Elapsed += new ElapsedEventHandler(WaitForScheduledTime_OnElapsed);
_WaitForScheduledTime.Interval = _ListOfJobs.IntervalUntilFirstJobIsToRun().TotalMilliseconds;
_WaitForScheduledTime.Start();
...
private void WaitForScheduledTime_OnElapsed(object source, EventArgs e)
{
log.Debug("Ready to run at least one job");
// restart the timer
_WaitForScheduledTime.Interval = _ListOfJobs.IntervalUntilFirstJobIsToRun().TotalMilliseconds;
_WaitForScheduledTime.Start();
}
If you are using ASP.NET you may be able to add an empty object into the Cache with a declared ExpirationDate then handle the CacheItemRemovedCallback. Just a thought, don't know if it will work for you.
If you not using ASP.NET you still may be able to use this trick with another caching framework such as the Enterprise Library Caching Block
Not that I know of. I rolled my own class to do that.