I'm assuming it's possibly to do so as programs like google chrome have gone one better and put each tab on a separate process.
So how can i put a GUI control such as a datagridview on a separate thread?
That is not the control that is in a seperate thread, but the request launched through the control.
Let's say you have two tabs opened on different addresses. You click on a link that directs you to another site on the first tab. Meanwhile, you click another link on the second tab.
First, you need to know that a thread might be launched when you click the link on the first tab, making it GUI responsive. This is the same with the second tab, when you clicked the link in it.
Second, we now have one thread (the main thread, also called the GUI-thread) which job is to handle the user interaction. Another thread processing the request from the link on the first tab, and another thread from the link on the second tab.
Third, while your link requests for both tabs are being processed, you might let's say open a new tab and doing a search on Google! Then, this requires your GUI to be responsive, even while the application, the browser, is occupied with your requests.
Fourth, on the background-threads' return, they will return to the main thread reporting the result of their work, that is, the Web response they obtained requesting to solve the DNS linked the the links clicked.
An interesting way to make it possible in C#, and keeping it as easy as possible, is through the BackgroundWorker class.
Each instance of a BackgroundWorker represents a thread. So, you need to instantiate as much of BackgroundWorker as it is required by the application when a mouse-click is captured, when a user clicks a link. The request is then sent to the DoWork() event which is raised when a call to RunWorkerAsync() method is made.
Here's an interesting tutorial on how to use the BackgroundWorker
This Microsoft article explains roughly how Windows Explorer does exactly what you ask:
http://msdn.microsoft.com/en-us/library/ms741870.aspx#multi_browser
You basically have one thread per top level window and all of the events for that window are fired on the same thread.
I don't think that you'll need a Thread for every single control else you'll have a huge number of threads and then you may start to run into all sorts of trouble.
Here's a couple of websites to get you started:
http://www.albahari.com/threading/
http://msdn.microsoft.com/en-us/library/aa645740(VS.71).aspx
Related
I have a word add-in, written in C#. When the user picks an option from the ribbon a custom task pane (user control) opens within the application (Word).
From this task pane, they press run, and the active document gets analyzed in a series of fairly complex ways. Checks such as interrogating any bold text in the document and many more. When running the whole process can take anything from 5 seconds to 1 minute, depending on the document. This is fine, no-one has an issue with this.
The problem comes when we try and implement a cancel button. To do this I have tried using a background worker. Everything works.... except that when communicating with the document from the thread (background worker) it is around 7-8 times slower than it was when running from the main thread. I have not been able to find much info on this, any advice or help would be greatly appreciated.
I have tried other avenues (open xml) but these are not viable options (we have to deal with .doc as well as .docx)
Thanks
To give an example:
I have a button on the taskpane (Run).
That calls private void btnRun_Click
That in turn, sets off the background worker backgroundWorker1.RunWorkerAsync();
In the do work method of the background worker, I have code such as:
myClass.Method()
In myClass would be a line of code such as:
For each Word.Field in ActiveDocument.Fields
That might take, say, 1 second to run from the main button click thread, and up to 30 seconds to run from the background worker. All other code works in good time, it is only code that accesses the Word document that seems to have problems
That's because the background thread is running is a different COM apartment than Word's STA.
Another approach you might want to consider is to show the dialog, then proceed with the processing in the same thread, having Windows messages pumped from time to time (e.g. at the beginning of long, possibly nested loops).
When the user presses the button, you set a flag, that you should check regularly throughout the code (possibly right after where you process messages).
You may need to implement UI modality yourself:
Display your window with e.g. Word as the owning window, and make sure it's focused
Disable the owning window
When you're done processing:
Enable the owning window
Close your window
Don't pump messages between steps 1 and 2 of either stage.
My app consists of 3 tabs, each tab has a DGV, tab 1 and 2 do not contain that much data within the DGV but in tab 3 it can be between 100-5000 rows
The problem im having is that when i start my app, and move to tab 3 it takes a while before anything is displayed..
Im looking for a way to display a loading form to the user while the data is being added to the DGV..
How would i accomplish something like this?
Start loading data on a background thread and monitor the progress(displayed as progress bar).If you are doing it on main thread than you'll hang your interface.
Theres one good article but it is in VB.
Long running operations should be running in a seperate worker thread, commonly BackgroundWorker class. This prevents the UI from locking up during said operation. You can also choose to display a loading dialogue while this thread runs.
The other answers here are correct. But since you specifically asked about a loading window, I remembered a very nice example in Code Project.
In a project I was involved with, we took this example and made it independent. We added static methods called Start and Stop, and the Start method would create a thread, and then load the window, while the Stop method signaled the form it needs to close gracefully.
Hope this helps!
Sorry if the title is a bit nondescript, I couldn't really word it right.
Basically, what I have is the following scenario:
I have a user-interface (WinForm) that allows users to pick multiple files to download, and then hit the "Download" button to commence downloading. All the downloads are processed asynchronously to avoid locking the form. However, while I don't want the form to lock up with a "Not Responding" message, I also don't want the user to be able to modify form fields while the download is running.
Ideally, I wanted to spawn a modal dialog which let's the user know the state of the download (i.e similar to firefox, except with a modal dialog). This kills 2 birds with one stone as it allows the user to get a good view of the download progress, while also stopping the user interacting with the parent form while the dialog is active.
However, to properly give the user an idea of the download progress I'd need to update the dialog during runtime. This is where I've hit a wall. My current idea is to expose some public methods of my dialog class to send it updates when files complete, and call them from within the background download thread (with proper delegates to update controls, etc)
I'm pretty sure this would work as I want, but I was just wondering if there are any more elegant solutions to this problem. Don't feel limited to the dialog approach, I'm open to all approaches that may offer a better alternative.
Cheers,
J
Alternative 1
You may consider using a BackgroundWorker, it will take of setting a new thread to do the job and provides an event based mechanism to report progress and also a method to request to cancel the operation (it is up to you if you want to use that).
To set the task for your BackgroundWorker you will need to attach a handler to the event DoWork and then call RunWorkerAsync().
Alternative 2
Another alternative is to use IObservable<T> to create a mechanism to respond to the progress of the download, then you could do the binding with using Reactive.
I take you are new to Reactive. In that case, this is best introduction available (in my opinion):
http://channel9.msdn.com/Blogs/codefest/DC2010T0100-Keynote-Rx-curing-your-asynchronous-programming-blues
If you had the freedom to not disable the UI... You could have the progress reported at a status bar, or dedicate a secondary form (which you could let the user close and get back with a NotifyIcon) where you have the current and any pending works.
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.
I'm building a UI for a program, and I can't figure out why my progress bar won't become visible after the convert button is clicked.
private void convertButton_Click(object sender, EventArgs e)
{
toolStripProgressBar.Visible = true;
...
toolStripProgressBar.Visible = false;
}
I ran into a similar problem with tkinter in Python, and I had to call a function to update the idle tasks. Is there a way to do this with windows forms without using threads?
Edit: On a side note, this is a progress bar in a toolStrip that also contains a label that gets updated with status bar text. Is there any way to get the label on the left side and the progress bar on the other instead of right next to each other on the left?
Well, there is a way to do this without using threads (Application.DoEvents) but I strongly recommend against you using it. Re-entrancy is nasty, and you really don't want the UI thread tied up at all.
Use BackgroundWorker instead - it's easy, and it's pretty much designed for progress bars. It takes the hassle out of using a separate thread and reporting progress back to the UI thread. No need for Control.Invoke etc - it takes care of that for you.
There are lots of tutorials for BackgroundWorker - it shouldn't take you too long to get going with it.
Per the question you asked for the way to do this WITHOUT threads, that is to do it with Application.DoEvents();. (Just add that call right after setting the progress bar as visible.)
Now I do agree with Jon Skeet though that BackgroundWorker is a better way of doing this, but it does use a separate thread.
You need to execute your process in a thread separate from the UI thread, and then have it periodically report back to the UI thread with it's progress. If your convert operation is working inside the UI thread, it will simply go unresponsive until the operation is complete.
The progress bar can only become visible when it is allowed to paint which occurs during the processing of messages. Message processing cannot normally happen while you are in the middle of an event handler. If you want the progress bar to show up you will have to set the visiblitity to true, start a background thread to complete the work and return from the handler.
I'm guessing the problem is that the "..." in your code is a long-running process. UI updates are not instantaneous, but must run through the message queue in windows and then be painted to the screen. The queue is pumped and painting takes place in the same thread as your events.
As a result, any long-running tasks need to be moved to a different thread. More than that, your line line of code needs to called after that thread terminates. Otherwise you set the progress bar and then immediately turn it off again.
One way to do that is with a BackgroundWorker control.
Here go two links trying to explain you how things work:
(1) (2)
Now, I will try to explain it as shortly as I can. Most of what happens inside a windows forms application happens in a single thread, usually the same thread Main() runs in. If you open Program.cs, you will see that Main() has a line that looks like the following:
Application.Run(new Form1());
If you debug the application at any moment and examine the call stack, you will see it will trace back to that Run method. This means that a Windows Forms application is in fact a continuous run of the Run method. So, what is Run doing? Run is eating a message queue through which Windows sends messages to it. Run then dispatches those messages to the correct controls, which themselves do things like add text which corresponds to the key being pressed, redraw themselves, etc. Notice that all this happens during and endless loop running alongside a single thread, so weather you are typing or simply moving the window around, loads of those messages are being passed onto the application, which in turn is processing them and reacting accordingly, all in that single thread. Controls can also send messages to themselves through the queue and even you can place messages in the pump via Control.BeginInvoke. One of the things those controls do is to raise events according to what happens. So, if you click a button, the code you've written to handle that click will ultimately and indirectly be run by the Application.Run method.
Now, what is happening with your code is that even though you are changing the visible status of your progress bar to visible and then updating its Value, you are then changing its visibility to false, all in the same method. This means that only after you leave the method, will Application.Run() be able to continue iterating and consuming the message queue, effectively asking the progress bar to update its display. When that happens, you've already left the progress bar's visibility to false, the last thing you did before exiting the method. DoEvents() is a quick and dirty workaround to your problem as it reads the messages in the queue and processes them. I don't really feel comfortable using it as it can bring reentrancy problems.
Using threads is a good solution, but I would recommend using a ThreadPool thread instead of a custom thread in this kind of situation, as I tend to use custom threads only in cases where I have a limited number of long lived threads and I need to control their life cycles. The easiest and most practical way to use threads is to use the BackgroundWorker component, even though I would recommend going through the pains of understanding how to do Windows Forms multithreading with delegates if you want to really understand what is going on.
My solution is to call refresh on the status strip.
I believe this causes the UI thread to repaint the status strip.
toolStripStatusBar1.PerformStep();
statusStrip1.Refresh();
This is for .NET 4.0. Even though this question is old it was the first I found on googling this issue.