C# and WinForms: 'Integrity' of Form.Show() call - c#

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.

Related

How to ensure Form is completely closed and removed from display before continuing?

I have tried what I saw in this post, which did not answer my question. See my code and further explanation below.
// In MyForm : Form
private void SetupForImportantTask()
{
// Does a ton of stuff to set up for ImportantTask, then...
this.Close();
}
private void MyForm_FormClosed(object sender, FormClosedEventArgs e)
{
// otherForm is an instance of OtherForm : Form
otherForm.ImportantTask(variousData);
}
// In OtherForm class...
public void ImportantTask(object variousData) {
// Does a bunch of stuff that takes a long time
// Provides UI feedback to notify the user a process in under way
}
Explanation: As you can see in the code, the idea is to do a bunch of setup for ImportantTask in MyForm, then call back into OtherForm with the setup information established after MyForm has already closed.
What I am seeing instead:
Even though I am not calling ImportantTask until the Closed event on MyForm has already fired, meaning semantically that the Form is already closed, MyForm remains open while the UI thread hangs, until ImportantTask is complete. The UI notification of the long-running process is never displayed, and MyForm only closes after ImportantTask is complete.
If MyForm is not closed when the Closed event fires, how else can I determine that the Form is actually closed and cleared from the screen?
Or:
What silly thing have I missed?
To answer your question, a form will disappear from screen after Form_Closed event has fired, therefore after calling each method that has registered to that event. The Dispose() method is called right after firing the event (from ReferenceSource, check the end of this method).
If you want to make sure a form has disappeared, you have the IsHandleCreated property, which tells you if there is a handle associated with the form (from MSDN).
About application design, a Form should be doing only what is has been designed for : display graphical elements and handling user input.
User Input should be filtered and your form should be firing events that a controller class would catch and manage on another thread.
When controller is done with user input, it should tell the form that it is OK to refresh the display.
Your design as it is now is broken, if you call from a Form a method of another Form, until that method returns you are still inside the calling method of the first Form.
In other words, method A does not finish until method B ( called by method A ) returns the control flow to its caller.
There are various ways you can properly do this, you can simply hide your first form changing its visibility instead of closing it, or you can run the importanttask method on other form async, or you can even simply post a message to second form and terminate yoiur first form then second form will respond to that message.
of course, pay attention at objects life cycle as well and in the end the method you decide to use depends on the rest of the application and on your taste.

continue of timer after closing the form

var startTime = DateTime.Now;
var timer = new Timer() { Interval = 1000 };
timer.Tick += (obj, args) =>
label14.Text =
(TimeSpan.FromMinutes(Convert.ToDouble( comboBox3.Text)*60) - (DateTime.Now - startTime))
.ToString("hh\\:mm\\:ss");
MessageBox.Show("Timer started");
timer.Enabled = true;
im strating a timer in a specific form when pressing a button, i want the timer to continue counting time after closing the form in order to give me a notification.
but when closing the form the timer stops,
any ideas?
You can't "Close" the form and have the Timer object still work (if you're calling the timer on the main form). (That's like saying I can't click the button and have a function run after closing the form). However, on the OnFormClosing argument, you could have the form.Visible = false and cancel the actual closing of the form. See here: Timer doesn't fire after Form closed
If you want to truly close the form and have it run, one option could be to look at possibly creating a Task Scheduler object that would complete the task at a certain time.
A quick hit: call "Hide()" instead - that will keep the timer running.
Now that's out the way, You can still make your timer static - ideally put it in a completely separate class, or, if you insist, make it static on your main form. Then have your notification code sit on your main form.
You can still add a listener to the Tick event on that specific form and just remember to remove it when you hide the form (i.e. Tick -= your_label_event_handler)

Does System.Windows.Forms.Timer send WM_TIMER message?

Does System.Windows.Forms.Timer send WM_TIMER message ?
Basically I want to set a timer that should generate
WM_TIMER
message for every 5 seconds. I am using
System.Windows.Forms.Timer
and the
Tick
event is handled. But I am not getting WM_TIMER message in my WndProc().
Yes, WM_TIMER is what makes a Winforms Timer tick. Unobserved in your code however, it creates its own window, it doesn't use yours. It is an invisible one, the underlying .NET class is TimerNativeWindow, a private class of the Timer class. You can't ever override its WndProc(). Technically you could subclass it with NativeWindow after digging out the handle with Reflection, but that way lies dragons and should never be necessary.

Messagebox not blocking events on a windows.forms

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.

No Load Complete event for windows form

In windows form on click on Next I need to display other form and start some processing. Am coding in .Net C#
The problem is before the form is complete visible, the method gets triggered and the processing starts and the UI looks like it crashed. Processing started even before controls are loaded. and once processing is done all controls are visible.
The actual output must be all controls should be loaded and then processing must start.
I need to call the method to start processing after the form (user control) is visible and is loaded completely.
I tried this and this, but no luck.
Added code:
private void FeatureRemovalControl_Load(object sender, EventArgs e)
{
pictureBox2.Image = Properties.Resources.line;
prgbar.Value = 0;
//code to load images and some other stuff
StratProcess();
}
You're calling StartProcess (which seems to block until it's finished) from your UI thread. Because WinForms repaints occur on that thread, nothing is painted, and it appears that your process has hung. You should look at using a BackgroundWorker, or other way to call StartProcess asynchronously.
Best way, if you ask me, would be to start processing asynchronously, so that you maintain full control of the UI and process at the same time.
http://msdn.microsoft.com/en-us/library/2e08f6yc(v=vs.71).aspx
Try calling that method at the end of the FormLoad event, the control should have finished loading by then. If it hasn't that you may need perform some checks and possibly create a custom event that fires when you're happy that it is ready.
Another solution is to have a button that the user must press to trigger the processing, which they will only be able to click once everything has loaded
EDIT: The reason it look's like it's happening is because you're starting the process in one of the control's load method, which I assume is not the last control to load, so it's starts processing before the other controls are given a chance to load. Make StratProcess method public and call it in the FormLoad method of the parent form instead, like so:
private void ParentForm_Load(object sender, EventArgs e)
{
FeatureRemovalControl.StratProcess(); // Should it be called StartProcess instead?
}
Beware though this is still doing the processing on the UI thread, so the screen may appear to 'hang' whilst this is happening so I advise you move it to a background thread as others have suggested.

Categories

Resources