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
Related
My question is how to update UI controls (such as ProgressBar) from another thread while UI thread is busy for querying the database (running a time-consuming stored procedure) ?
I checked these questions and still no solution is found for me.
Updating UI continuously while the main thread is busy
How to update the GUI from another thread in C#?
Run multiple UI Threads
Cross-thread cross-form. Display a splash screen with a progress bar
I know one option is to do time-consuming work using BackgroundWorker and update ProgressBar using ReportProgress method, but I have a problem in this option because the UI thread is responsible for instantiate and show another form after querying the database like this:
Form2 f2=new Form2();
f2.show();
I recommend you use BackgroundWorker and put the construction and presentation of the Form2 object in the BackgroundWorker's RunWorkerCompleted event handler, which executes on the UI thread when the BackgroundWorker is finished. Definitely don't try to update the UI from a background thread. The GUI classes are not threadsafe.
i have a class which, when a certain part of the gui is clicked will
-create a backgroundworker and do the following taks
-create a new object(this is a new windows form)
-call a method on it which gets some data
-populate the new windows form gui with that data
The problem is there is a gui component on the form which cant be created from outside of the main programme thread, if i do try i get the error
Active x .... cannot be instantiated because the
current thread is not in a
single-threaded apartment.
is there help people can offer so i can structure this?
in my do work
Don't create GUI components in a background thread. Use the background thread to get and process data, then render them in the UI in the main thread. I know that this in inconvenient, because
creating lots of UI elements can also take a lot of time and
creating them in the UI thread requires you to split your code into UI part and data processing part,
but there's not really a way around it. .NET UI components are not designed to be handled in background threads.
To perform only certain operations of your code in the main thread, you can use
someUIControl.Invoke(...) (WinForms) or
Dispatcher.Invoke(...) (WPF)
in the DoWork event handler of your BackgroundWorker. Alternatively, you can perform the UI operations in the RunWorkerCompleted event handler of your BackgroundWorker, which always executes in the UI thread.
The UI should only be managed by the UI thread.
One possible solution would be to load the data asynchronously with the BackgroundWorker, and when it is done use the Result property of the DoWorkEventArgs to pass the results back to the UI thread and then display the new form.
I am currently creating a chat system. The receiving end of the client side is managed by a separate thread so that when it receives a message from another client, a new Form is loaded bearing the message of the sender. The problem is, the newly loaded form is frozen and is not responding [due to the blocked methods I use (?)]. How can I solve that problem? I am new to C# so please put in the code snippet.
It is frozen because you created it on another thread and that thread didn't call Application.Run(). Which is required to 'pump the message loop'. More here.
Don't create windows on another thread. Use BackgroundWorker or Control.BeginInvoke or Dispatcher.BeginInvoke to let the UI thread of your program create the window.
I followed this background worker example with code which worked great for me.
http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx
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.
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.