Timer strange behaviour - c#

I have a Windows.Forms.Timer used in a form that works if I set its Enabled property to true in the properties window, and that is the only time it works. If I leave it disabled then enable it only when I need to, it doesn't tick.
private void btnRename_Click(object sender, EventArgs e)
{
timerUpdateProgress.Enabled = true;
timerUpdateProgress.Start();
pbProgress.Maximum = clbFiles.CheckedItems.Count;
var renameTask = Task.Factory.StartNew(() => doRename(true, tbCurrentDirectory.Text, clbFiles.CheckedItems, rules));
if(renameTask.Result.Count > 0)
{
timerUpdateProgress.Enabled = false;
new ExceptionsWindow(renameTask.Result).ShowDialog();
}
timerUpdateProgress.Enabled = false;
loadFiles(tbCurrentDirectory.Text);
}
private void timerUpdateProgress_Tick(object sender, EventArgs e)
{
pbProgress.Value = progress; //I have a breakpoint on this line
}
All I'm trying to do is display the progress of an operation with a progress bar. Enabling and starting the timer does nothing, the tick never happens. Why is this happening?
Update: stepping through the code after adding a sleep of 2000ms after enabling and starting the timer shows it still does not tick (I have a breakpoint in the tick handler).
More clarification: When the timer is enabled in the property window, the tick handler is always being called, and that's without calling Start(). My breakpoint is triggered all the time just by enabling the timer. I should also note that I'm using .NET 4.

EDIT:
After getting an idea from the comments - it seems you do not need the timer at all.
You can update the progress bar Value as and when the value of progress is updated.
That way the transition from 0 - 100% might also seem smoother.
According to me you need disable the timer.
Just use
timer.Stop();
And then timer.Start() when needed again.
Additionally, if you have disabled timer progress, then you also must do
timerUpdateProgress.Enabled = true

How long did "Task.Factory.StartNew" take ? (If this is syncronous)
If above lambda expression is asyncronous, I see whether renameTask.Result.Count is bigger than 0 or not, progress bar = false...

Related

timer.Elapsed actions not firing

I have a button that I want to disabled after 4 failed submit attempts. I am using System.Timers timer to count to 15 seconds, then trying to re-enable the button after those 15 seconds.
Here's my code:
if (SessionManager.getRetries > 3)
{
Message.Text = "Too many failed attempts. Please retry in 15 seconds.";
buttonOne.Enabled = false;
HttpContext.Current.Session["RetryCount"] = 0;
System.Timers.Timer myTimer = new System.Timers.Timer();
myTimer.AutoReset = false;
myTimer.Interval = 15000;
myTimer.Enabled = true;
myTimer.Start();
myTimer.Elapsed += myTimer_Elapsed;
}
}
void myTimer_Elapsed(object sender, ElapsedEventArgs e)
{
buttonOne.Enabled = true;
}
So far my program will correctly count the # of submissions tried (SessionManager.getRetries). After 4 failed attempts, it will enter this if statement. It then creates the timer, sets the interval, starts it, and knows that the time elapsed. It even goes to the buttonOne.Enabled = true statement, but it doesn't actually enabled my button. (This was observed through the use of breakpoints in visual studio).
Is there something I am missing here? Maybe elapsed events don't work the way I want them to?
Any help would be appreciated.
Timer event should be firing, but it has no way to enable button on HTML page as request is completed by that point.
You should move timer to JavaScript on the page. You still need to keep logic that verifies that retries are not more frequent as it is very easy to bypass JavaScript or any other client side verification.
As posted earlier, the problem was not that the events weren't firing, it was that there was no way to show the button as enabled on the client side via the method I was trying previously because the timer only exists server-side.
BUT
I found an easier way than coming up with some sloppy Javascript :)
By using a update panel and asp timer. By placing a asp timer inside of the update panel, and setting the timer to disabled as default, I can then manipulate the timer. Then, when the timer ticks it is automatically updated via the update panel :)
Great code samples here:
ASP.NET Timer Event

Stop a running loop over action in form

I have a program that run in a loop. it's this
private void ReadCamAuto_Click(object sender, EventArgs e)
{
this.serialPort1.DataReceived -= new System.IO.Ports.SerialDataReceivedEventHandler(this.DataReceivedHandler);
RunReadCamAuto = true;
while (RunReadCamAuto)
{
serialPort1.WriteLine("2,2,2,2");
CreatePic(4, 4);
}
this.serialPort1.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(this.DataReceivedHandler);
}
but the problem is then I'm in the While loop I cant press any other Button in my program so it is not possible to stop. I have no idea how to stop it ?
I tried to press a button who set the RunReadCamAuto to false and Console.ReadKey()
I'm Using:
c# Form App
MS VS 2010
You cannot expect user interface to work while the main thread is busy doing some work in a loop. Use BackgroundWorker object to fire desired loop in it - it's automatically invoked on other thread and from your main thread you can easily send the message to stop its work.
You need to assign your method to BackgroundWorker's DoWork event and then from your form just call myBackgroundWorker.RunWorkerAsync(). Then by calling myBackgroundWorker.CancelAsync() you will change its CancellationPending property to true, which you can be constantly checking in your loop to break execution.
Please see here.

sleep not behaving as expected [duplicate]

This question already has answers here:
Implementing a pause in WPF
(3 answers)
Closed 9 years ago.
I have a WPF app and I want to sleep for a second before displaying certain info on screen. So its.
1. Click a button.
Sleep 1 sec.
Display a label.
Sleep 1 sec.
Display a label.
etc etc
private void RunTest()
{
clearTable();
System.Threading.Thread.Sleep(1000);
this.Cursor = Cursors.Wait;
Label_OS_Result.Content = operatingSystem;
Image_OS.Visibility = Visibility.Visible;
System.Threading.Thread.Sleep(1000);
Label_CPU_Result.Content = procName;
Image_CPU.Visibility = Visibility.Visible;
System.Threading.Thread.Sleep(1000);
}
But when I click my button it seems to wait for a few seconds and then displays everything all at once.
Whats going on here??
It is working as it is expected.
Thread.Sleep stops the execution of the current thread for specified amount of time. So, when you change the visibility of an image, it will make further calls to change the visibility in the framework, then it will try to draw it on screen (invalidates). When you sleep the thread before this operation finishes it will not have enough time to finish this operation. You are simply blocking the UI thread responsible of drawing something on the screen.
Beware that Thread.Sleep may not be the solution, it is better for you to have a look at DispatcherTimer or BackgroundWorkers.
You don't want to Thead.Sleep() on the thread displaying your GUI.
Instead, you should try await Task.Delay(). This is similar to sleep, but it won't block the GUI thread.
This will allow all the rendering to still happen, while delaying the visiblity changes for your labels.
It is working as intended.
It may not be what you expected, but the problem here is your expectations.
What happens when you fiddle with properties on most visual controls, that should end up changing the appearance of the control, is first to make the internal adjustments to the controls properties (ie. data), and then trigger a redraw. To trigger the redraw, a message is usually posted to the message queue of the thread that owns this visual control.
This thread usually processes messages one at a time, be it a button click, mouse movement, or the paint messages that was just posted because you changed the image.
However, that thread is basically written like this (pseudo-code):
while (true)
{
var message = GetNextMessageFromQueue();
ProcessMessage(message);
}
The last time this loop was active, it started processing a message that ended up calling your code, the one that is now sleeping.
So basically, to get the message pump (the typical name of the code that implements this loop) to continue pumping messages, and thus process your paint message, is not to sleep.
You might want to separate your processing out to a different thread, or some other asynchronous way of doing things "in the background".
Note that you will get the same problem if you start doing any kind of lengthy processing in response to a button click or similar, without doing it on a background thread (or again, some other asynchronous way). The GUI will appear to have frozen.
This problem, however, is so common that Microsoft ended up building in special support for it in Windows. It used to be that a window just seemed to hang. Now, however, if the message queue "fills up", Windows will fade out the windows and tack on a caption to it indicating that it has stopped responding. Not a solution, but slightly better.
Sleep function is behaving correct.
Better you use a Timer to do so,
// Declare it in the constructor of the class
int level = 0;
Timer timer = new Timer
timer.Interval = 1000;
timer.Tick +=new EventHandler(timer_Tick);
private void timer_Tick(object sender, EventArgs e)
{
timer.Stop();
if (level == 0)
{
Label_OS_Result.Content = operatingSystem;
Image_OS.Visibility = Visibility.Visible;
++level;
}
else if (level == 1)
{
Label_CPU_Result.Content = procName;
Image_CPU.Visibility = Visibility.Visible;
++level;
}
else if (level > 1)
{
this.Cursor = Cursors.Default;
return;
}
timer.Start();
}
private void RunTest()
{
clearTable();
//System.Threading.Thread.Sleep(1000);
timer.Start();
this.Cursor = Cursors.Wait;
}

Timer/Refresh functionality for text box

In my application, I have two text boxes accompanied with two labels: "Connected" and "Not Connected". As seen in my code, if a connection is established, the "Connected" text box will fill with Green, indicating a network connection. It will be red if not.
The functionality of connection detection is working just fine, however, I have to re-open the application for it to detect the change. I am looking for a way to refresh the application every 5-10 seconds or so automatically to detect any change in connectivity. I don't want to flush out the contents of any other field or box, just the color text boxes. A soft polling loop so to speak. How would I go about doing this using the Timer method. Should I create a new thread in which to run the timer and refresh the box?
Thanks.
if (System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable() == false)
{
noConnect.Select(); //if not connected, turn box red
noConnect.BackColor = Color.Red;
}
else
{
netConnect.Select(); // if connected, turn box green
netConnect.BackColor = Color.Lime;
}
//need to refresh box/application without losing other box/field contents
//in order to constantly check connectivity around 5-10 seconds or so
//constantly check connectivity
Something like this would work
public Form1()
{
InitializeComponent();
var timer = new Timer();
timer.Tick += new EventHandler(timer_Tick);
timer.Interval = 10000; //10 seconds
timer.Start();
}
void timer_Tick(object sender, EventArgs e)
{
if (your_function_call())
{
netConnect.BackColor = Color.Green;
}
else
netConnect.BackColor = Color.Red;
}
The timer_Tick would be repeatedly called every interval and you can poll your status and update controls. Because the timer call back is called in the UI-thread you can update any UI elements.
From Timer Class
A Timer is used to raise an event at user-defined intervals. This
Windows timer is designed for a single-threaded environment where UI
threads are used to perform processing. It requires that the user code
have a UI message pump available and always operate from the same
thread, or marshal the call onto another thread. When you use this
timer, use the Tick event to perform a polling operation or to display
a splash screen for a specified period of time. Whenever the Enabled
property is set to true and the Interval property is greater than
zero, the Tick event is raised at intervals based on the Interval
property setting.
This solution uses System.Windows.Forms.Timer that calls the tick on UI-thread. If you use System.Timers.Timer the callback won't be on UI-thread.
just create the timer. it well run on his own thread without you doing any thing else.
You can create a timer somewhere in your application
var timer = new System.Timers.Timer();
timer.Interval = 5000; // every 5 seconds
timer.Elapsed = (s, e) => {
// Your code
};
timer.Start();
Note: please be aware that your code in the Elapsed event handler can/will run on another thread!

Why is this C# timer code not working?

I need to be able to disable a button for 1.5 seconds at a time for an application I'm writing. An image is displayed, a user clicks a button, and then another image is displayed. I need to make sure that the user doesn't click the button again too quickly.
So, when the image is displayed, I call this function:
//when a new image is displayed, start the timer and disable the 'done' button
//for 1.5 seconds, to force people to stop pressing next so quickly
System.Timers.Timer mTimer;
void TimerStart() {
Done.IsEnabled = false;
mTimer = new System.Timers.Timer();
mTimer.Interval = 1500;
mTimer.Start();
mTimer.Elapsed += new System.Timers.ElapsedEventHandler(TimerEnd);
}
The TimerEnd code looks like:
void TimerEnd(object sender, EventArgs eArgs) {
if (sender == mTimer){
Done.IsEnabled = true;
mTimer.Stop();
}
}
The 'Done.IsEnabled' line gets hit, but the button is not reenabled and the timer doesn't stop firing. What am I doing wrong here? If it matters, this is a WPF app.
Use DispatcherTimer instead
DispatcherTimer timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(someInterval);
timer.Tick += new EventHandler(someEventHandler);
timer.Start();
private void someEventHandler(Object sender, EventArgs args)
{
//some operations
//if you want this event handler executed for just once
// DispatcherTimer thisTimer = (DispatcherTimer)sender;
// thisTimer.Stop();
}
Basically you are trying to debounce the button, to prevent too quick clicks. Rather than use a timer save the previous click time in millis, if the button is clicked again within a short time ignore the next event.
The timer event is raised on a different thread. When working with the winforms controls, you need to make sure you Invoke them from the same thread where they were called.
When working with WPF there is no guarantee that updates made to UI controls on non-UI threads will work as expected. In many cases you will get an exception when you do this.
In your Timer elapsed handler you need to use the BeginInvoke/EndInvoke paradigm and put your button enabling logic in there to ensure that this code runs on the UI thread instead of Begin/End Invoke
There is a SynchnornizationContext available as well which can be accessed by calling SynchronizationContext.Current . You'll need to cache this before you make the timer call since SynchronizationContext.Current will be null in non-UI threads.
This link talks about this as well.

Categories