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.
Related
I have very generic question. I tried google it but couldn't find anything good.
So the question is: I have winform application where based on option selected from menu bar, child form/view is loaded and these child forms are used to display reports.
in order to generate report, these child form contains report selection criteria like date, name etc and these value comes from DB. based on values available in DB, we add controls in the view.
Problem comes when screen takes lots of time to load, it freeze UI/application during loading that I don't want.
I also tried run tasks async but since it is using view during the processing, this option failed.
ThreadPool.QueueUserWorkItem(delegate { method.Invoke(presenter, results); });
presenter is my viewpresenter and results is parameters to invoke it. application concluding presenter name at run time and calling its default method using methodinfo.invoke().
Is there any other way to achive the same.
Point: I cannot redesign the whole application to separate out complete DB logic from UI logic as it is legacy application and this might break the application.
If "freezing" is the problem, you could use doevents, see here: Use of Application.DoEvents()
Or, you could go the really old fashioned, vb6 way: run the code that freezes your UI synchronously, but from a modal window shown above your ui. You can event present the user with the progress indicator.
I have a lengthy process that I can't run asynchronously, so just like Explorer when you're copying files, I have a progress dialog. I show the dialog modally, then perform the operations (we'll call it copying files to keep it abstract), update the progress dialog, and pump messages with Application.DoEvents() to keep the application main frame painting and responsive.
Since the dialog is modal, the user isn't able to do anything other than watch or cancel. In other words, they can't select a menu item or click any buttons.
I've always believed Application.DoEvents to be extremely evil, because you could re-enter code you didn't intend to be re-entrant. But in this case, since the progress dialog is modal, I can't see a reason why this is a bad or dangerous solution.
Am I overlooking something, or is pumping messages with Application.DoEvents a legitimate thing to do with a modal dialog up?
I don't see a particular problem with this limited use of DoEvents. We successfully use it in very limited situations like this when background processing isn't an option.
Normally, your UI thread in the application will pump messages. Now even though modal dialogs run their own message pump this is merely to keep the call behavior as expected (e.g. the call only returns when the modal dialog is closed), it is not a necessity for dealing with the modal dialog per se. (See also this blog post from "the old new thing" blog).
Therefore it isn't really a problem to call Application.DoEvents() either, even though it usually shows a design problem (e.g. non-cooperative processing in the UI thread) and it may cause re-entrancy if some window messages and event handlers are triggering each other - but that's independent of dialog modality.
I’ve got a process which will take a little under 5 seconds to complete. The user will most likely notice the program flicker for a few seconds after pushing the “go” button.
My question is:
Is this something that would normally be dumped onto a background worker, or is there another .NET method for handling small tasks, or is this something that shouldn’t be a concern?
FYI:
The process opens a user specified excel file, processes an unknown number of lines (max 1.5 million due to excel I believe), and queries a database (very quick query). So at the worst case scenario the user uploads a 1.5 million row excel file and is running on a very slow internet connection.
If you don't want the user to be able to do anything while the file is being uploaded, then you don't need to put it on a different thread.
If you want the user to be able to go on to other tasks while the file is uploading, put it on a different thread.
As a general rule of thumb, if I have a situation where I absolutely don't want the user to do anything while a long-running process is going, I disable the controls on the form until the task is complete, and usually use a status indicator to show that progress is happening.
My personal guideline for whether or not to allow user interaction is if the results of a process could be altered by a user action in mid-stream.
For example, one program that we have parses a bunch of queries on a highly normalized database (normalized to the point where reporting is sloooow) into "reportable" tables, and I don't want the user altering data in one of the source tables while the query is running, because it will give goofy results.
If there is no harm in allowing user interaction while the process is occuring, then put it in another thread.
Edit
Actually, on reading #UrbanEsc and #archer's comments, I agree with them. Still put it on a different thread and freeze the controls (and include a progress indicator where possible).
I would push this to a background worker. Doing so will keep the UI responsive. If the process ever does lag for more than a few seconds, users start getting nervous ...especially when the lagging process causes the UI to be 'frozen'.
From a user experience point of view it might be best to hand the job over to a different thread or an asynchronous worker and tell the user that his request is being processed in the background. Once the worker finishes, a success/failure message can be handled and shown to the user as required.
The cheapest way to handle the problem is to turn the cursor into an hourglass during the processing. That tells user please wait, I'm busy.
According to the budget (time and/or effort) you're willing to throw in it, using a backgroundworker and some reporting GUI is certainly a plus. But it's up to you according to your app.
For example, I'm currently modifying an in-house app that has 3 users. In that case, the hourglass is OK: All 3 of them will quickly learn they just have to wait. Don't get me wrong: this app is damn important. Without it, the small company that uses it would just die. But if I ask them for 2 hours of extra budget for a nice and tested little GUI, background thread, blah vs an hourglass, what do you think they'll say?
On the other hand, if it's an important operation in your flagship product, of course be nice to your users! Don't hesitate: background thread. Especially if the operation may actually take much longer than those 5 seconds.
Conclusion: Be pragmatic!
I would put it into a background worker or fire of a task if you are in .NET 4.0, for example:
void OnButtonClick(...)
{
new TaskFactory().StartNew(() => { /* your excel and query code */ });
}
I'll vote for the background worker process, since a frozen UI is like a frozen application, and most of users will think your application isn't doing anything at all.
UI thread for a progress bar or some animation, info text noticing what's going on + background worker thread = win
I think every process not related with the UI itself should be started as a separate thred or, in this case, as a bg worker. This will help to maintain the app healthy and easy to improve/fix in the future.
Also, as a user or tester, I really hate flicking and freezing windows...
Regards.
A general rule of thumb is any operation that takes a second or longer to complete requires some form of feedback to the user. This can be a progress bar, message, etc. Anything longer then that then the user becomes frustrated (not sure if they did something wrong, hate waiting, etc).
For operations like this that can take longer based on the environment (number of apps, available memory, data size, hard drive speed, etc) they should ALWAYS be put on a background thread and pipe messages back to the UI. I love the BackGroundWorker for this.
K I am looking at a primarily single thread windows forms application in 3.0. Recently my boss had a progress dialogue added on a separate thread so the user would see some activity when the main thread went away and did some heavy duty work and locked out the GUI.
The above works fine unless the user switches applications or minimizes as the progress form sits top most and will not disappear with the main application. This is not so bad if there are lots of little operations as the event structure of the main form catches up with its events when it gets time so minimized and active flags can be checked and thus the dialog thread can hide or show itself accordingly.
But if a long running sql operation kicks off then no events fire. I have tried intercepting the WndProc command but this also appears queued when a long running sql operation is executing. I have also tried picking up the processes, finding the current app and checking various memory values isiconic and the like inside the progress thread but until the sql operation finishes none of these get updated. Removing the topmost causes the dialog to disappear when another app activates but if the main app is then brought back it does not appear again.
So I need a way to find out if the other thread is minimized or no longer active that does not involve querying the actual thread as that locks until the sql operation finishes.
Now I know that this is not the best way to write this and it would be better to have all the heavy processing on separate threads leaving the GUI free but as this is a huge ancient legacy app the time to re-write in that fashion will not be provided so I have to work with what I have got.
Any help is appreciated
It sounds as if the long running operation is bound to the progress dialog? That's usually a bad idea and I wonder whether the progress can be showed at all.
However you should consider using a BackgroundWorker for your long running operations. So your GUI (the main form as well as the progress dialog stays alive).
This way you should be able to send the minimize event of the main form to the progress dialog which can react to it instantly.
Btw. the BackgroundWorker supports progress reports on its own.
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