C# UserControl BeginInvoke Problem - c#

I have got a C# user control, which has got it's own background worker thread. This worker thread is started in the constructor of the control and stopped when the control is disposed.
The thread periodically calls the BeginInvoke-Method with a delegate, but sometimes the exception "Invoke or BeginInvoke cannot be called on a control until the window handle has been created." occoures.
Now I ask you, how can I check whether calling BeginInvoke is possible from my worker thread to do no invoking as long as the control isn't completely created?
This problem only occoures when compiling a release. Not in debug mode.
with best regards

The worker thread should be created inside... (you have two options):
A handler of Control.HandleCreated event
Overriding Control.OnHandleCreated
What you need to know is that a control may not be fully created (ready to be used) even after the constructor is done executing.

Related

Is it safe to instantiate a form and call ShowDialog from within BeginInvoke?

Is it safe to instantiate a form and call ShowDialog from within BeginInvoke?
BeginInvoke run the task on the same thread on which the control had been created.
So as far as i know should be ok ...
I am just asking if such creation may lead to some hangs, deadlocks, etc..
This is ambiguous, sure sounds like you instantiate the form first and then call BeginInvoke(). No, that's not okay. It will look like it will work since ShowDialog() pumps a message loop. But you'll have a raft of very nasty glitches. The mild stuff is the window not being modal to the other windows in the app. And not having a Z-order relationship with the other windows in your app which can cause it to easily disappear behind another window. Nastier stuff is that the thread probably isn't an STA thread, things like drag + drop, the clipboard and the shell dialogs will not work. The really nasty stuff is getting the SystemEvents class to start firing events on the wrong thread, that problem lasts past the dialog and crashes or hangs your app at unpredictable times later.
Only ever create a form instance on the UI thread. Which means that you must use the BeginInvoke() method of another instance of a form, one that was created earlier. If you are desperate to find one then Application.OpenForms[0] may give you one.
Is it safe to call ShowDialog inside BeginInvoke, it would be a problem if you would call ShowDialog from a background thread.

Open new form from inside each thread?

I'm using the following code to open a new form (that is for user input) in my function:
Form4 f4 = new Form4();
f4.mainform = this;
f4.get_Text(matchString);
f4.ShowDialog();
It's working perfectly when not threading, but when I try to run the function on two threads I only get 1 form popup. How can I adjust it so that it will support more than one thread?
You can open a form from any thread, you just need to start a message loop on the new thread, such as:
Application.Run(f4)
The Run method will not return until the form is closed. It can cause issues, though, so you need to be careful and know what you are doing. Unless it's a real pain to do, I would sooner consider redesigning your code to be more asynchronous. For instance, you could create a event handler method to listen for the form's closing event.
The WIN32 Message pump runs on one thread -- the GUI thread. As soon as you .ShowDialog(), the c# stops until the user closes the dialog. Even if you use .Show() to avoid a "stop and wait for the user to push ok", you still must handle all GUI events on the GUI thread by .Invoke()ing to the GUI thread.
The way to support multi-threaded-ness is by doing non-GUI work on alternate threads.
ShowDialog does pump messages so it would technically work on a separate thread without needing a dedicated message loop. However, what you currently have looks like a recipe for disaster because that form appears to hold a reference to another form via f4.mainform = this and it is presumably trying to access it. You simply cannot do this without littering (and I mean that literally) your code with a bunch of Invoke or BeginInvoke calls.
Furthermore, running UI forms on a thread other than the main UI thread generally does not work well. There are a few obscure problems you can run into. For example, since there would be two UI threads in play it is possible to have 2 active modal dialog boxes open. One might be hidden behind the other and the end user would not see it. This reason, among others, is why it is not generally recommended to use more than one UI thread.
My advice is to figure out a way to make this work with a single UI thread. Your life will be simplier if you do.

Creating a WinForm on the main thread using a backgroundworker

I've got a background worker and I'm trying to get it to create an instance of a form, but I don't want the background worker thread to own the object, but would like the main thread to own it. Where do I start with this?
You can use the Invoke and BeginInvoke functions to get the code to execute on the GUI thread. You could get your other thread to raise an event, then handle it in your main form, then your main form could invoke that call back onto its own thread (using InvokeRequired then Invoke) to launch the new form.
If you're using a background worker you may be able to put the OnProgressChanged method to use to signal back to your application to do something.
Also, take a look at this excellent book

BackgroundWorker and resource managemnet in c#

Let suppose I create a background worker in a form as a component.And start it.
Now if I close the form then BackgroundWorker will be still running.
Will you explain that however form has been closed and all resources created within the form object have been closed but BackgroundWorker is still running. What is reason behind this?. Is this because of it is runnibg on a different thread.
And when it resources will be regained by CLR.
The background worker isn't by default connected to the form or thread it's created in.
A background worker is an object like any other object. It will get collected when there are no more active references to it.
So it really depends on how and where the object was created, and mostly - who is still has references to it.
What people tend to forget is that the events are also references. So if there's another object somewhere that is listening to the worker's events, the worker will still be referenced and so it won't be collected.
Note:
Form.Close() removes the dialog from sight and calls the Closing() and Closed() methods. You can still access the form and bring it back later on.
Form.Dispose() destroys the dialog and frees its resources back to the operating system. It does not call the form’s Closing() and Closed() methods. Once disposed, you may not recall a form. The Dispose() will also call the Dispose() method of all the Form's components.
The background worker will be disposed with the form, unless you deliberately suppress dispose. If this is the case then it should be garbage collected at an indeterminate time. I say should because things could potentially hold reference to the background worker. As for the thread, I believe it will be cleaned in the dispose, which should be called from the form when it closes.
If the form is the main form, and on closing causes the main foreground thread to close, then all background threads will close / die also.
When you close your form and dispose it, BackgroundWorker will dispose too, but it does not stop the thread running. So it will be completely destroyed only after the DoWork finishes.
You can solve this by cancelling the closing of the Form and calling CancelAsync on the background worker to signal that you want it to finish. Wait until it finishes and only after that you should actually close the form.

How to show progress status for a long-time-consuming function?

I have a windows form simply like this: 1) a button when clicked will perform an operation taking a long time to complete, 2) a label showing how much percentage of the progress is going on.
In the long operation I mentioned, I write the code to update the Text property of the label but it doesn't work!
Please help me to show the progress status correctly.
You can take a look at the BackgroundWorker class (see the MSDN overview). It allows you to run some long-running operation in background and report progress updates (percentage) and completion from the background task to the user interface. Note that you'll need to calculate the progress percentage yourself.
However, the BackgroundWorker class takes care of other tricky aspects, such as sending your progress reports to the main GUI thread (where you can safely update the user interface).
Your going to want to create a worker thread that performs the task and occasionally reports its update to the form thread. If you do all of your work in the UI thread, your UI will be locked and won't update the progress/label correctly.
Before you start the worker thread, calculate the total number of steps you believe the process will take. Start the worker thread. After each unit of work, you Invoke an update method on the UI thread to increment the process.
You'll want to look at the BackgroundWorker class.
If your application will have several of these, I recommend creating a process interface (e.g. IProgressProcess). This interface will contain methods for executing a process and reporting updates. You will create all of your process classes by implementing from this interface. Write a control that contains a progress bar and accepts an IProgressProcess through a constructor or property. It can then use your custom process to execute and move along the progress bar. Then you can have your custom progress control send events when the process is complete or canceled.
This usually happens if you try to update the UI on the same thread where the operation is occurring. There are a couple of different ways that you could accomplish this.
You can update the UI with the BeginInvoke method.
You can use a BackgroundWorker component.
The reason that you don't see any change, is that the change causes a message to redraw the label, but the main thread is busy working so it doesn't respond to the message.
The simplest solution would be to just call the Application.DoEvents after updating the label. That works as a quick fix for your immediate problem, but it still will leave the application unresponsive in any other way.
The good solution would to start the operation in a separate thread. That way your main thread is free to handle messages while the operation is running. However working in a separate thread means a litte more work when communicating with the UI. If you want to update controls, you have to use the Invoke method to start a method that runs in the main thread so that it has access to the controls. Alternatively you can just update a variable in the thread, and have a timer control that periodically checks for changes in the variable and updates the label accordingly.

Categories

Resources