Multi-threaded multi-windowed application not working - c#

I want to create a program that does remote installs. I'd like to be able to have a window launch at the start of each installation and give a progress bar with the approximate progress of the job.
If I create the window off the main thread I can access all of it's elements but it's not responsive due to the task of actually running the install. If I launch the window in a new thread I can't seem to get the main thread to recognize any of the elements in the window so I can't update the progress bar.
How can I create a multi-threaded UI that is responsive?

To keep the UI responsive with a second thread (that's doing the work) and be able to update the UI from the second thread, you'll need to use Invoke on the controls. There's a number of code snippets available out there.
Here's a short example: How can I update my user interface from a thread that did not create it?
You can find dozens of examples here on SO as well - just do a search :)
Here's another similar question on SO today - cross threading problem - there's a code example in one of the answers.

There's a simple way to access UI controls from other threads safely - to call lambda with Control.BeginInvoke(lambda) method. For example, suppose you have WinForms application with one form and progress bar with button on it. When button is clicked - some imaginary work is going on in separate thread and progress bar should be updated. The simplest would be to write something like that:
private void button1_Click(object sender, EventArgs e)
{
ThreadStart s = () =>
{
for (int i = 0; i <= 10; i++)
{
Action a = () => progressBar1.Value = i * 10;
BeginInvoke(a);
Thread.Sleep(300); // imitate some workload
}
};
var t = new Thread(s);
t.Start();
}
The same result could be achieved with BackgroundWorker or other techniques, but this is the most simple as for me.

Related

How to sync progress bar with a function execution? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I am creating a 'cleaner' application using windows forms c# and want to have a progress-bar. At the moment I am just cleaning temp files, cache files and browser junk.
I have a progress bar:
private System.Windows.Forms.ProgressBar _myProgressBar;
And here is my cleanup method:
private void button1_Click_1(object sender, EventArgs e)
{
_myProgressBar.Value = 0;
ClearCache();
_myProgressBar.Value = 25;
ClearCookie();
_myProgressBar.Value = 50;
ClearHistory();
_myProgressBar.Value = 75;
TempCleaner();
_myProgressBar.Value = 100;
}
I want it to execute those 4 methods (each of which takes a few seconds to complete) while updating the progress bar as it goes; but all it does is wait until they have finished and then show the progress bar as completed. How can I make the progress bar show the progress as it completes each part?
This is a complicated subject, and the code sample and your reputation indicates that you may be a little inexperienced; which is a tricky combination. But I'm going to try to answer... (other readers please bear in mind I'm going to try to keep this answer simplistic).
The reason it's complicated is that in order to do it properly, you're going to need to use threading. Threading is a massive and tricky topic, which causes problems even for experienced developers. I cannot possibly hope to reasonably cover that topic all here, so I'm just going to stick to the key points.
When your WinForms application is running, unless you arrange it specially, your code will be running on what can be called the "user interface thread" ("UI thread"). Ideally, that thread should be left to do things like processing events on the window (like moving, resizing, mouse clicks, etc). If you want to do anything which is going to take time (like the contents of your "Click" method above), then you need to execute that functionality on a background thread (not directly within the method, as you've done above)
Something you need to know is that although the work is going to be done on a background thread, the changes to the progress bar will have to be done by the UI thread - this is mandatory, you are not allowed to do it from a background thread.
So here are the key points to my proposed solution:
Move the code from the Click method into a background worker, and add the notification of progress from that worker as it progresses
Update the progress bar from the correct thread
So here we go...
1) There are lots of ways of doing this. Here's one... move all your code from the Click event into a method called "BackgroundThread", and modify your click method so you have this...
private void button1_Click_1(object sender, EventArgs e)
{
if (_thread == null)
{
_thread = new Thread(new ThreadStart(BackgroundThread));
_thread.IsBackground = true;
_thread.Start();
}
}
private void BackgroundThread()
{
UpdateProgress(0);
ClearCache();
UpdateProgress(25);
ClearCookie();
UpdateProgress(50);
ClearHistory();
UpdateProgress(75);
TempCleaner();
UpdateProgress(100);
}
You'll need to declare that "_thread" variable as a private member variable on your Form (to prevent it being garbage collected).
Now I'm going to highlight but not solve a couple of problems that you will need to deal with. Since we have moved the code onto a background thread, there will be nothing stopping the user pressing the button lots of times, each of which would fire off a new thread (probably not what you want). How you deal with that problem depends on how the progress bar sits in your UI, and how often you want people to press the button. A simple (but incomplete) answer would be to wrap the contents of the Click method in "if(_thread==null)" (as shown above), meaning that the button would only work the first time you clicked it.
The other problem is notifying your background thread if you wanted it to stop what it was doing (e.g. user wants to close the application). As I've said, it's a big topic, and I'm not going to get into that here.
3) The above code needs us to write the UpdateProgress method...
private void UpdateProgress(int percent)
{
RunOnUiThread(() => _myProgressBar.Value = percent);
}
private void RunOnUiThread(Action action)
{
if (InvokeRequired)
{
Invoke(action);
}
else
{
action();
}
}
You will have guessed the "_myProgressBar.Value = percent"; but the rest of it probably looks bizarre. The RunOnUiThread method is reusable on any WinForm Form or Control, so you might like to keep that in a snippet. Basically, whatever action you give it, it will check whether it's on not the UI thread ("InvokeRequired"). We're passing it a lambda expression "() =>" to do what we need to happen on the UI thread.
If it's on the wrong thread, it will "Invoke" the action (basically queue it up so that the UI thread will do it when it gets the chance). If it was already on the right thread then it will just execute the action on the same thread.
That should do it.

Update UI while Task.Run or TaskFactory.StartNew is still working

So I have decided to rewrite my Mail client in WPF as I think it's about time I move on from Windows Forms (I still like it), but I am facing a bit of a problem.
I use a BackgroundWorker in my Windows Forms app to do stuff and in a foreach I worker.ReportProgress(currentProgress); and this allows me to update the UI as things are being done in the background which is great.
But just now after starting a new WPF project, I notice that there is no BackgroundWorker in the Toolbox (for WPF apps) so I go searching online, and found that some people have problems updating the UI while using BackgroundWorker with WPF. So this makes me think that using BackgroundWorker in a WPF app is a bit hacky - and I don't want that.
On that same page, another user refers them to this page, telling them to use Task.Run instead of BackgroundWorker in WPF. Upon looking at Task.Run docs, I immediately see how it can be useful, however I do have one concern. I do not see a way to "Report Progress" or to update the UI as things are being done. All I see is how to Run a Task and "await" it; leaving me with just one option - update the UI after the long-running Task has completed.
How can we update the UI of a WPF desktop app while Task.Run/TaskFactory.StartNew is still working?
You can stick with BackroundWorker if you so choose. There is nothing really hacky about it although it is very old-school. As others said, if you can't find it in your toolbox, you can always declare and initialise it straight from your code (don't forget the using System.ComponentModel; directive).
Stephen Cleary has an excellent series of blog posts on BackgroundWorker vs Task, which highlights the differences and limitations of each approach. It's definitely worth a read if you're on the fence or just curious.
http://blog.stephencleary.com/2013/05/taskrun-vs-backgroundworker-intro.html
If you do decide to go down the Task + async/await route, there are a couple of things specifically related to progress reporting that you should keep in mind.
Generally you should be aiming to have your await Task.Run encapsulate the smallest meaningful amount of work possible. The rest of your async method will then execute on the dispatcher SynchronizationContext (assuming that it was started on the dispatcher thread) and will be able to update the UI directly, like so:
List<object> items = GetItemsToProcess();
int doneSoFar = 0;
foreach (var item in items)
{
await Task.Run(() => SomeCpuIntensiveWorkAsync(item));
doneSoFar++;
int progressPercentage = (int)((double)doneSoFar / items.Count * 100);
// Update the UI.
this.ProgressBar.Value = progressPercentage;
}
This is the easiest way of implementing progress reporting in the async world.
The only time I can imagine reporting the progress from within the body of the delegate you pass to Task.Run is when you're processing a very large number of items, and the processing of each item takes a very short time (we're talking 10,000 items per second as a rough guide). In such a scenario creating a large number of extremely fine-grained Tasks and awaiting them will introduce significant overhead. If this is your case you can fall back to the progress reporting mechanism introduced in .NET 4: Progress<T>/IProgress<T>. It's quite similar to the way the BackgroundWorker reports progress (in that it relies on events) and it provides a bit more flexibility in terms of deciding when you get to post back to the dispatcher context.
public async Task DoWorkAsync()
{
// Let's assume we're on the UI thread now.
// Dummy up some items to process.
List<object> items = GetItemsToProcess();
// Wire up progress reporting.
// Creating a new instance of Progress
// will capture the SynchronizationContext
// any any calls to IProgress.Report
// will be posted to that context.
Progress<int> progress = new Progress<int>();
progress.ProgressChanged += (sender, progressPercentage) =>
{
// This callback will run on the thread which
// created the Progress<int> instance.
// You can update your UI here.
this.ProgressBar.Value = progressPercentage;
};
await Task.Run(() => this.LongRunningCpuBoundOperation(items, progress));
}
private void LongRunningCpuBoundOperation(List<object> items, IProgress<int> progress)
{
int doneSoFar = 0;
int lastReportedProgress = -1;
foreach (var item in items)
{
// Process item.
Thread.Sleep(1);
// Calculate and report progress.
doneSoFar++;
var progressPercentage = (int)((double)doneSoFar / items.Count * 100);
// Only post back to the dispatcher SynchronizationContext
// if the progress percentage actually changed.
if (progressPercentage != lastReportedProgress)
{
// Note that progress is IProgress<int>,
// not Progress<int>. This is important
// because Progress<int> implements
// IProgress<int>.Report explicitly.
progress.Report(progressPercentage);
lastReportedProgress = progressPercentage;
}
}
}

How to create an application global Progress Window without blocking running threads?

We have a project that have a couple years development invested into and it now need a progress window because some process are very long. We deal with 3D CAD, advanced engineering, Simulations Third Party DLL, Web services, WCF services.
Now i am trying to add a generic process window you can start in 1 place and end anywhere else. that's not complicated per say. simple static class that open a window on MyClass.Open(string Message) and a MyClass.Close() to hide it once the heavy duty code completed. This works perfectly except the heavy code block the Thread.
The project is a mix of bunch of projects but this part is 99% WPF and i am fairly new to WPF threading as they don't behave like winforms. In winforms thread i create that open other forms are not block by main app heavy work. In WPF the copy pasted code the form is frozen.
I tried Thread and Background Worker without success. then to make sure it wasn't my window the issue or my static class i tried opening the window manually with a Form.Show(); and a Form.Close(); in one of the heavy work function an the form still showed and close properly but yet still frozen. then i removed the Form.Close(); and it started to move right after the work completed. Now i find very strange that the main thread when working at full capacity freeze other threads. I have an actual Exact copy in winform for that progress window except that instead being a Form with label i have a WPF window with a label in a grid.
I tried doing it the right way which is creating a thread for the heavy function but compiler now give me 2,404 errors. I would have at least a week of work just o try if something works and i'd rather not as changing the whole project like so would take at least a year and half and we mostly have 2-3 weeks to complete this so i am looking or any solution that might help finishing that. I can be very dirty. as long as it works.
thank you very much.
Edit :
#Baldrick requested more detail about thread.
I went very simple for thread.
public static class CWaitingMessage
{
private static frmWaiting window = new frmWaiting();
private static Thread t = null;
private static string Message = "";
public static void Open(string sMessage)
{
Message = sMessage;
t = new Thread(new ThreadStart(RunForm));
t.SetApartmentState(ApartmentState.STA);
t.IsBackground = true;
t.Start();
}
private static void RunForm()
{
try
{
window = new frmWaiting();
window.UpdateText(Message);
window.Show();
System.Windows.Threading.Dispatcher.Run();
}
catch
{
window.Close();
}
}
public static void Close()
{
if (t != null)
{
t.Abort("Completed");
}
}
}
If i use System.Windows.Threading.Dispatcher.Run(); instead while (ShowForm) { } the form isn't frozen but my thread disappear by that i mean it never reach f.Close();... ever.
Edit #2 :
Managed to make the abort of the thread using the dispatcher.Run but now i have a bigger issue. the program never stop. the thread start, then i call the abort with a special catch on thread exception and on abort i call a method in the window to save the amount of time it's been opened and close the form. I checked and the file is created so the abort does work but if Dispatche.Run is calle in a thread that is aboded it seems to live on his own. now i have created a monster that never stop running. i close my app completely an visual studio still see it as running.
I am very close to forget about a solution in WPF and go for a winform form to show that message as i know it works perfectly in winforms without that freeze up annoyance.
Edit #3 : Updated my current class i use. I have checked my old exampled and background worker i was only doing a normal form load then running a background worker to loop. the form was in a the same thread as the main code which is completely normal as Background worker are MTA and therefore block UI thread. for UI i need Threads which are STA.
I cannot call dispatcher.Invoke to test it. i couldn't find the assembly for it. my compiler and intellisense don't like it by default :)
The Thread class is not used so much these days as there are now much simpler ways of creating asynchronous methods. For example, please take a look at the Task Class page on MSDN for examples on how to easily create asynchronous methods in WPF.
If you are using .NET 4.5, you can also use the new async and await keywords for even easier asynchronous methods. Please see the await (C# Reference) page on MSDN for a detailed description of this new functionality with code examples.
Having said that, using a BackgroundWorker may actually be your best bet for implementing ProgressBar update functionality with its easy access to update the UI on the UI thread. Please take a look at the BackgroundWorker Class page on MSDN for a full example.
If you need specific help with something, please edit your question in order to add the relevant code.
Found it. after 3 days of work.
For people wondering how to open and close a thread in WPF without freezing he main thread when the new form have animation and no process work.
Code :
public static class CWaitingMessage
{
private static event Action CloseWindow = delegate { };
public static void Open(string sMessage)
{
Thread t = new Thread(delegate()
{
frmWaiting window = new frmWaiting(sMessage);
CloseWindow += () => window.Dispatcher.BeginInvoke(new ThreadStart(() => window.Close()));
window.Closed += (sender2, e2) => Window.Dispatcher.InvokeShutdown();
window.Show();
System.Windows.Threading.Dispatcher.Run();
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
}
public static void Close()
{
CloseWindow();
}
}
Note that no error handling and multiple window opening is supported. this is simple the skeleton working and ready to use. I know at least 2 handful of people that will be very interested in this piece of code.
If you required process also on that window background worker works perfectly in the window. This is very useful for mouse over over a grid being filled asynchronously and while you mouse over you can still open secondary window with another DataGrid and heavy work without issue.

How to retrieve information in a second thread with a Windows Forms C# Application

I have an usual C# Windows Forms Application with one Form and several TextBoxes / Labels which runs (how I understand) in its own thread. (Win 7 64 / VS 2008 / Net 2).
Now I want to start a second thread while my base application stays in the first thread.
The second thread shall retrieve some system information and input it into the Labels while my user is still able to fill in the TextBoxes while the information is going to be retrieved by the second thread. So the advantage would be by my understanding, that the user has not to wait until retrieving information is completed and the main application would not hang in that time.
Let's say I want this code to be executed in a second thread which starts in the Form_Shown event:
Label1.Text = GetInternetIP();
try
{
Label2.Text = System.Net.Dns.GetHostEntry(Label1.Text).HostName.ToString();
}
catch{MessageBox.Show("Fatal Error."); Process.Start("shutdown.exe", "-r -t 2"); this.Activate(); SendKeys.Send("%{F4}");}
I would be grateful for a detailed description on how to setup a "new thread". I am a newbie but I would like to learn something new and optimize (speed up) my very first applications.
The Label1 and Label2 are in the main thread on the main form (Form1). So I have to get the retrieved information there.
in dealing with Windows forms the UI can only run on one thread, then it will create background threads the background threads retrieve the data and then pass it to the single UI Thread. This is also how it works in WPF.
take a look here on how to do this
http://msdn.microsoft.com/en-us/magazine/cc300429.aspx
You should never access your UI components from code running on another thread. In fact, you shouldn't access anything from multiple threads unless those things are explicitly thread-safe (or you access them in a thread-safe manner).
In your example you are saying you want to fetch information which takes some time. In your case the programming model you want is to have your main thread call an asynchronous function to retrieve that information, and it should signal your main thread when the information is ready.
There are a lot of different ways to implement multithreaded programming in C#, but here is one example:
public Task<IPAddress> GetInternetIP()
{
return Task.Factory.StartNew(() =>
{
IPAddress ip;
// do some work to get the IPAddress
return ip;
});
}
private void Form_Load(object sender, EventArgs e)
{
GetInternetIP().ContinueWith(ip =>
{
Label1.Text = ip.ToString();
}, TaskScheduler.FromCurrentSynchronizationContext());
}
In this case what you're doing is executing a System.Threading.Tasks.Task which will handle the multithreading for you. And you're telling it to continue execution with a method on the current thread. That method is passed the return value of the task (in this case an IPAddress object).
to access user controls that are on the main thread from your background thread you only need to use BeginInvoke against the controls you want to populate. This is an article that fully explains how to do so along with the ins and outs of doing so.
http://weblogs.asp.net/justin_rogers/pages/126345.aspx
The three answers which I received brought me nowhere or have not worked, so I found it out myself much later: I used the Backgroundworker-Control to achieve what I wanted. In the "Completed"-Event of the Backgroundworker I can access the UI and transfer the information to the form attached to my application. What helps me a second thread if my UI is locked for that second thread, so Backgroundworker is the best for me to go and self-explaining.

Notifying when a FindFiles Process has finished

I have a multi threaded app where I have created a Producer/Consumer Pattern for the processing of XML files etc
What I want to know is what would be a good approach for updates to the UI and when the process finshed.
Should I go down a threaded approach and create Barrier and wait for all tasks to complete or should I just create an event/delegate and get the UI to catch this for both UI updates/compeltion
You may checkout Signalr which allows you to achieve PUSH notifications to clients.
Sorry, this answer was assuming Windows Forms, because there was no asp.net tag at first. Hopefully someone will provide a good answer for asp.net as well.
You can use Form.Invoke() to update stuff from the non-GUI thread, here's a simple example:
private void Form1_Load(object sender, EventArgs e)
{
Thread thread = new Thread(DoStuff);
thread.Start();
}
void DoStuff()
{
Thread.Sleep(1000);
this.Invoke(new Action(() => MessageBox.Show("Hey, this was invoked")));
}
With Invoke, you can do just about anything with the Form, it runs the invoked action in the form's thread. So you can change your status text or whatever that way. Of course, you shouldn't have your "business logic" inside the Form class, and you shouldn't use Thread.Sleep, I'm just showing the very basic fact that you can call back to the UI thread this way.
As to whether you should wait for all tasks to complete before doing anything, or show status updates as they execute, that's really up to you. I like to show updates on the UI when possible so the user knows what's going on. It's also good to have a progress bar going if there's something happening that the user might be waiting for. The progress bar can just be a marquee if you don't have a good way to indicate real progress.

Categories

Resources