I'm wondering what the best approach might be for what I'm trying to do. My application has a button that starts a background download operation, and then performs some actions dependent on the downloaded files.
It's like a "The game will begin shortly once necessary data is downloaded" situation, where the user may still use the main form.
private void btnStart_Click(object sender, EventArgs e)
{
//execute some code
Downloader.RunWorkerAsync(files); //this worker reports progress to the main form
while (Downloader.IsBusy)
Application.DoEvents();
//execute some more code
}
I'm aware that doing it that way is not good at all.
I cannot execute the download code synchronously, because the main form needs to remain responsive during the download operation.
I also cannot put the final code into the download completed event, as it is used by many other areas of the program and must remain a "generic" download system.
So, is there a way to do what I want? I do not have any experience with other async methods.
If you use BackgrounWorker you must configure it properly. BW has RunWorkerCompleted event to which you must subscribe to handle completion of you async work.
I think you should use asynchronous programming features of the .net 4.5 framework (await and async).
refer to async programming
Related
In c#,
I have a device that accepts HTTP requests as remote commands.
I've created a button that send those requests, it's not the perfect but it works.
However, when the device is disconnected and there is
destination unreachable
response the application freezes until i restarts it.
I need a way around it, maybe some timeout that will close the stream after 1 second.
private void httpBTN_Click(object sender, EventArgs e)
{
String URI = "http://192.168.1.118/cgi-bin/aw_cam?cmd=DCB:0&res=0";
WebClient webClient = new WebClient();
Stream stream = webClient.OpenRead(URI);
stream.Close();
}
Long running operations in GUI's are propblem: As long as the operation has not finished (result or timeout), the event does not finish. And as long as a Event does not finish, no other code can run. Not even the code that updates the GUI with changes or "yes, I got the message about a user input" to Windows. You will need some form of Multitasking.
Luckily Networking is one of the most common cases of long running Operations, so it has build-in ways of multitasking (the async functions). However that might no be the best start. As Multitasking beginner I would advise towards using the BackgroundWorker in Windows Forms. At least until you got a handle on Invoke and Race Conditions. async/await is the better pattern longterm, but has a much steeper learning curve.
I have developed a GUI to capture packet via ethernet cable.
For this purpose i have 3 separate functions I am running each function in separate thread.
1) public void Capture_Click(object sender, EventArgs e) //packet capturing
2) public static void PacketHandler(Packet packet) // storing received packets and showing in dataGrid
3) public void dataGridView1_CellContentClick_1(object sender, DataGridViewCellEventArgs e) // I have Kept a button on each row to get packet details in more detail.
Problem: When packets are coming that there is no problem but as soon as packet stop coming GUI freezes now I am not able to click Detail button in DataGrid.
suggest possible solution?
It seems you are receiving (psychic debugging) packages in your ui thread. A solution could be to do this in a background worker. This will allow your ui to update and receive/handle your incoming packages at the same time.
MSDN Backgroundworker
From MSDN: The BackgroundWorker class allows you to run an operation on a
separate, dedicated thread. Time-consuming operations like downloads
and database transactions can cause your user interface (UI) to seem
as though it has stopped responding while they are running. When you
want a responsive UI and you are faced with long delays associated
with such operations, the BackgroundWorker class provides a convenient
solution.
In a splash screen for an iOS app written in MonoTouch C# I am calling a number of web services which then calls another web service until all the data I need has been collected for the app to run. I am doing this asynchronously so that I can display an activity indicator to the user.
However I feel like the code is very messy and all these calls and callbacks are in the ViewController. I would like a way of separating this so that the ViewController only cares about the results coming back but I would need a way for the ViewController to stop until the call has completed.
At the moment, my code looks a little something like this:
protected void FirstServiceCompleted(object sender, FirstServiceCompletedEventArgs e)
{
// Do something
_servicesHelper.GetSecondService(GetSecondServiceCompleted);
}
protected void SecondServiceCompleted(object sender, SeconServiceCompletedEventArgs e)
{
// Do something else
_servicesHelper.GetThirdService(GetThirdServiceCompleted);
}
... etc
It would be nice to have a way which through another object my ViewController retrieves the data from the event args while behind the scenes I use this code. At the end of all these calls I change to a new view to show the main home screen with this data populated. However my ViewController seems very bloated and there's a lot of repetitive calls like this.
Any help or advice would be very much appreciated.
I think it might be useful for you to look at the TPL - Task Parallel Library - this tackles exactly the sort of async processing you are talking about.
Using Task along with ContinueWith and WaitAll, I'm sure you'll find a way to clean up your code flow.
If you search you'll find hundreds of getting started links for this - eg http://www.codeguru.com/columns/experts/article.php/c17197/Understanding-Tasks-in-NET-Framework-40-Task-Parallel-Library.htm
Built on top of the TPL, in the near future you will also be able to use the new await/async features of c# - but these aren't available today for MonoTouch.
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.
I'm trying to figure out a way to make user controls run in their own UI threads. Is this possible? I'm trying to prevent a module-based application from crashing due to a single module.
Any thoughts?
That's not possible. However, with some non-trivial code, you can have different windows running in separate threads. Each window will have its own message loop.
Update:
Another way you could think of is to write your controls in a special way. You can handle all events in your controls by creating a new thread that will run all the logic.
Unfortunately all UI controls run on the same UI thread. Therefore any code running on this thread that could potentially lead to a hang situation would need to be coded with some sort of timeout logic.
DateTime startTime = DateTime.Now;
while(DateTime.Now.Subtract(startTime).TotalSeconds < 30)
{
//do something
}
Otherwise, as Orlangur stated earlier, all event handler code would need to be run in separate threads. You would still however need to monitor these threads to determine if they've been running too long and shut them down. As such you might as well implement the type of logic above as it would be a lot less work and more maintainable.
I suppose it's not a matter of the program crashing. Exceptions can be caught of course, but the issue is in hanging controls. For the sake of this situation, here's an example:
public void Button1_Click(object sender, EventArgs args)
{
while(true) {}
}
If this code were to run in a control, an exception wouldn't throw, but it would hang. I'm trying to determine a way to catch this and remove the control module from the application.
Running controls in different threads should be possible. A little hacking and windows overrides and it should be doable.
I am thinking you can create a GUI control in another thread, then move it to a common window (main gui thread) with the win api SetParent. SetParent can be used to "hijack" other windows, so you should be able to grab the controls this way. But of course there might be focus issues and other issues, but might be doable.
I used that once to put my own button onto MS Messenger.