I have this code:
private void timer1_Tick(object sender, EventArgs e)
{
MessageBox.Show(Thread.CurrentThread.ManagedThreadId.ToString());
}
the timer is enabled, with interval = 100.
This result in an infinite number of message boxes to appear over each other, when I was expecting them to simply BLOCK the next event until the current messagebox is closed.
In more complicated applications this could lead to unpreditable results, and its as if more than 1 thread have access to the same function, but actually it is the same thread.
Why is this happening ?
The message box is a modal dialog which pumps the message queue. And so that allows for the timer tick messages to fire, since they are posted to the GUI thread's message queue.
This is always the case for a modal dialog that is shown in the GUI thread. Since each thread has only one message queue, the modal dialog's message pump will pull of the timer tick messages.
It is happening exactly how it should. The tick event is powered by the message loop (unless you're using a threaded variant) and will be called repeatedly unless you block the message loop in some way (think Thread.Sleep or non message based code execution).
The message box doesn't block, it's just another window and as long as the message pump of the application is functioning so will the window, and so as each tick happens new dialogs can be created and stacked up.
A quick solution to this is something like:
private void timer1_Tick(object sender, EventArgs e)
{
timer1.Stop();
MessageBox.Show(Thread.CurrentThread.ManagedThreadId.ToString());
timer1.Start();
}
This would stop the timer, show a dialog and allow the timer to recover after the dialog is closed. This means you'd only get the one dialog and not a perpetual stack of them.
Related
I'm trying to have serial data sent out continuously while a check button is being pressed in Visual Studio. So far, this is what I've come up with:
private void checkBox1_CheckedChanged_1(object sender, EventArgs e)
{
while (checkBox1.Checked)
{
serialPort1.Write("D");
Task.Delay(100);
if (checkBox1.Checked != true)
{
break;
}
} `
For some reason, whenever I launch the program and check the box, the program
freezes. I can't exit the program or minimize it or anything. It just stops in its tracks.
The user interface in Windows is based on messages. Your while loop runs in the thread where those messages would be handled. While your code runs, no messages are handled. The user interface cannot be redrawn and cannot react to user input.
Better approach: Use a Timer component. The Tick event of the Timer will be executed every n milliseconds according to the Interval property of the Timer. In the Tick event, you can check the Checkbox state and then do something or not depending on whether the checkbox is checked.
This is a good approach if "do something" is a very short activity. For longer activities, you nee a bit more complex setup that is beyond the scope of a SO question unless you provide more details.
You're blocking the UI thread because your event is being handled synchronously. Refer to this answer for some tips on async/await programming: How do I update the GUI from another thread?
Why will this click event not display the first toast message?
I created a break point and it hits the line to display "Waiting on User Input..." but never displays. I only get a 5 second wait and then an Approved or Declined toast notification.
private void Button_Credit_Click(object sender, RoutedEventArgs e)
{
myToast.Show("Waiting on User Input...");
System.Threading.Thread.Sleep(5000);
if (pc.BuildTransaction())
myToast.Show("Approved");
else
myToast.Show("Declined");
}
You shouldn't use Thread.Sleep, but instead utilize Task.Delay, so you're not blocking the current thread during your specified delay.
If you block your current thread, which in this situation is much likely your UI thread, how do you expect it to be able to dispatch your toast notification?
I wrote a single threaded program (winforms meh) and am expecting it to behave like this:
Mainform starts Progress display form
Progress form is rendered fully
Progress form receieves event operationStarted which adds a picture of spinning circle to the form
Long lasting operation starts
Progress form receives event operationCompleted or operationFailed and sets appropriate image
What happens is messy.
Mainform starts Progress display form
Progress form is not rendered fully!
Program hangs for a while
When long lasting operation is complete UI updates
Why the lag with updating windows form?
This is reduced code if necessary
private bool Run(int commandIndex, string fullCommand)
{
if (operationStarted != null)
operationStarted(commandIndex);
// start long lasting external process
if (exitCode != 0)
{
if (operationFailed != null)
operationFailed(commandIndex, Error);
return false;
}
if (operationCompleted != null)
operationCompleted(commandIndex);
return true;
}
operationStarted, operationFailed & operationCompleted are set correctly to update the appropriate images.
This is vastly simplified but I think it should suffice.
Windows is driven by messages which is handled in a queue system.
When you show a window, one or more messages is put into a queue and has to be processed.
One of these messages is going to be a paint message. In response to this message your program is supposed to paint the window (or something inside it) on the screen.
The way the queue system is processed is that your form is owned by a thread that is continuously doing something like:
while (true)
{
var message = GetNextMessage();
if (message == none) break;
ProcessMessage(message);
}
One of the messages this loop handled was a message instructing your program that the user clicked on a button a form.
In response to this, .NET routes this message as an event to your event handler, typically something like "button1_Click", which then executes.
Until your event handler, this click method, returns, this loop is not processing any messages.
As such, if that button click event is doing something lengthy you're said to be "blocking the UI", which is basically "you're not returning in an orderly fashion back to the message loop".
In the UI thread I have a piece of code that goes like this:
SomeForm form = new SomeForm();
(...)
form.Show();
SomeForm class particularly has a System.Windows.Forms.Timer instance as a member that is being initialized by auto-generated code of InitializeComponent() that looks like this:
this.UploadStatusTimer.Enabled = true;
this.UploadStatusTimer.Interval = 1000;
this.UploadStatusTimer.Tick += new System.EventHandler(this.UploadStatusTimer_Tick);
form.Show() will in the end raise Form.Load event that is being handled by SomeForm_Load(object sender, EventArgs e).
My question is: is there a possibility that UploadStatusTime_Tick was being processed before SomeForm_Load?
InitializeComponent() is called by the constructor of the Form, so it is possible that UloadStatusTimer_Tick is already called, before you call form.Show().
If you want the timer to start after you call form.Show(), set UploadStatusTimer.Enabled = false in the designer, override OnShow and use this method to set this.UploadStatusTimer.Enabled = true.
What you are asking is "can it take longer than one second from the time I construct my form for the Load event to fire?"
Beyond the theoretical answer of "yes, this is always possible" it really comes down to how long (...) takes in your example code. The timer is going to start counting down as soon as Enabled is set to true (when it is constructed).
It's important to note that UI interactions are processed via a message pump. So thinking of the winforms timer, the timer itself is off running in the background (outside of .net even; it is using the native windows timer) and when the timer expires it sends a message to your application, which then queues a message on the message pump that says "hey, timer tick happened." Same thing applies to your form load event, it is triggered via a message on the message pump. So if the timer expires before the form "loads" then the timer message will be in front of the 'form load' message on the queue and get processed first.
If you're interested in learning more, there many articles or stack overflow questions on the winforms message pump (or message loop as some may call it).
To ensure that the timer does NOT go off before Form_Load, disable it in the designer and call timer.Start(); in the Form_Load event.
To ensure that it does go off before Form_Load, move the code in the timer_Tick function to a central method and call that from the constructor.
Hi
I'm opening a form like this from my main form when the user makes a selection of a menu item.
private void commToolStripMenuItem_Click(object sender, EventArgs e)
{
Command_Form Command_Form1 = new Command_Form();
Command_Form1.ShowDialog();
// Command_Form1.Dispose(); this didn't help
}
Inside the form "Command_Form1"
I close it like this when the user clicks on the close button
private void Close_button_Click(object sender, EventArgs e)
{
this.Close(); //I get the exception here
}
This process works fine once but on the second closing of the form
(Which I hope is a completely different/new instance of the form) I get the error in the title of this post.
This is the output in the debug window.
A first chance exception of type 'System.InvalidOperationException' occurred in System.Windows.Forms.dll
All the topics that list this error go on about not trying to do anything to a form that has not been displayed but this happens when I click on a button in the form.
It would seem to me that pretty much ensures the form has been displayed if I'm able to click its button.
The other posts I've found that list this type of error go on about making thread safe calls so I tried this as an experiment but it didn't make any difference.
private void Close_button_Click(object sender, EventArgs e)
{
if (this.InvokeRequired)
{
CloseCallback d = new CloseCallback(Close_button_Click);
Invoke(d, new object[] { sender, e });
}
else
{
this.Close();
I have multiple threads in my application but they are created by the controls I'm using not by me explicitly.
I am passing data from a serial port to/from the form by Marshling the received/sent data via a delegate[s].
It makes sense that the serial port would run on a different thread than the form but why would a button click on a form be in a diffrent thread than the form????
The whole thread thing is very confuzing
How do I figure out what threads originated where and what is going on in the threads that I didn't create explicitly?
Why would I need to invoke the form's close method via a delegate?
Heck is there anything I can do in this multi threading environment that is thread safe How in do I know if what I'm doing is unsafe/safe if I don't know what/where/why/who/when is creating threads?
My guess is your close() call is not throwing that exception, but something that happens after close(). Have you stepped into the code with the debugger to see when it is fired?
As to when you need to invoke...There is only one thread allowed to make changes and access dynamic properties on the GUI, call it the GUI thread. The GUI thread is responsible for updating layout, firing events like buttons, etc. If you ever access the GUI from another thread (like a timer event) you need to use invoke() to queue your function to be run on the GUI thread. BeginInvoke will also queue the function but is asynchronous (will only queue the function to be run on GUI thread, but will not wait for it to finish).
Close_button_click will only be called by your gui thread when the button click event fires(unless you explicitly call it somewhere else in your code behind, not recommended!), so invokeRequired=false in your code above, and the invoke code is never executed.