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.
Related
I am developing one chat application in windows phone. I am using Deployment.Current.Dispatcher.BeginInvoke method to update the UI, but at the time of using Dispatcher.BeginInvoke the screen will struck. How to solve this or any way to update the UI without stuck?
If you use the dispatcher then you will execute the given code in the UI thread. And while you execute code in the UI thread, the UI is stuck. There's no way around that, so you must make sure to execute only the absolute minimum amount of code in the UI thread. The common pattern is to retrieve/compute the data in a background thread, then switch to the UI only to update the controls. The BackgroundWorker class is a convenient helper to reach this result.
I have to render about 10'000 wpf controls, and I don't want to freeze my application during this action. Is it possible to do it in another thread?
I tried to use
myStackPanel.Dispatcher.BeginInvoke(
System.Windows.Threading.DispatcherPriority.SystemIdle,
new NextPrimeDelegate(this.AddButton));
and another variants of Dispatcher. But it always freeze my application. I'd like to show animated waiting screen during creating hundred controls, but it's always freeze, because it's dispatcher's thread.
thanks for help
Andrew.
WPF controls must be created on the thread associated with the dispatcher where they will be presented. The call to Dispatcher.BeginInvoke schedules the specified action to run on the dispatcher thread at a later time, not on a background thread.
If you have a lot of UI controls to create and want to display an animation during their creation, then you will need to segment the work to be done into small units that can be quickly processed. You can then call BeginInvoke at a priority lower than normal to process each unit of work group individually.
The fact that you need to create 10,000 controls is extreme and you should probably investigate virtualizing the controls.
In my Silverlight application, I have an operation that takes a couple seconds and strongly interacts with the GUI (creation of display objects in a big "for" statement)
At first I thought of using the BackgroundWorker to avoid freezing the interface. But I cannot update the GUI directly, so I used the Dispatcher.BeginInvoke, but it still freezes the interface (since the long actions are on the gui part).
What I'd want is display a BusyIndicator while it loads my objects but I want the user to be able to continue working while it loads.
What else can I do? Any suggestions?
Even a busy icon won't help you here. Busy icons, or any other graphics item, require the UI thread to pump messages in order to not "freeze" the UI. If your long running operations are running on the UI thread then even the busy cursor will "freeze".
You need to either
Move the expensive long running logic to a background thread
Break up the UI logic into chunks and let the UI refresh in between them.
Creating UI items in the BackgroundWorker is just wrong. Creating UI elements requires switching back to the UI thread if run from a BackgroundWorker. That is just making things worse than creating them on the main thread.
I assume that lots of the work in the BackgroundWorker is not creating the elements but some additional processing that happens to create UI elements in the middle of everything else.
If that is the case you need to break out the actual generation of UI elements. Replace the generation of UI elements with dummy-classes that contains all specifications required to build all elements. Then you return that collection of specifications (the dummy-classes) and generate the actual elements in the BackgroundWorker.RunWorkerCompleted event.
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
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.