Thread Starts lags UI WPF - c#

Well, I've been struggling with this for a while and I've been unable to find a solution.
I'm developing one of those cashier apps you see in the supermarket where everything works fast as hell. The cashiers know the program so good they just type at the speed of light so the UI must be incredibly responsive.
Anyway, as I've only coded in WPF I'm using it, if someone says WinForms is faster I'll surely learn it.
This is my code, it's very simple as I'm testing performance
public partial class MainWindow : Window
{
Thread t;
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
t = new Thread(HandleThread);
t.Start();
}
private void HandleThread()
{
Thread.Sleep(3000);
}
}
Whenever the button is clicked, a new thread is launched as I plan on connecting to a server in the new thread.
My problem is the method button_Click is VERY SLOW. It takes about 1 second to return so the button looks like it's stuck and the application look sluggish. I've tried threads, BackgroundWorker, changed the framework to 4.0 and tried Tasks. NOTHING. Whatever I do to start some kind of background work the method takes forever.
I need to check the username and password on a remote server, how can I accomplish it without hurting the UI?

You should turn off the IntelliTrace (How-To).
On the Tools menu, click Options.
In the Options dialog box, expand the IntelliTrace node and then click General.
Clear the Enable IntelliTrace check box.
Click OK.

Do you need to spawn a new thread every time you click your button? Is this thread long-lived? Do you really want to allocate 1 meg of stack space (on 64 bit OSes) for this every time you click this button? Really sure you don't want to use the TPL's Task and CancellationTokenSource instead?
In your case, you should really not create a thread every time you click, what you want is start a long-running async task and check the result.
public void OnClick(object src,EventArgs args)
{
var login = tbLogin.Text;// assuming non MVVM coding here
var pwd= tbPass.Text;
Task.Factory.StartNew(()=>{
return _myWebService.CheckAuth(login,pwd); // your login stuff here
}).ContinueWith(wsTask=>{
if(!wsTask.IsCompleted){ // handle errors / cancel }
DisplayLoginState(ws.Result);
}, TaskScheduler.FromCurrentSynchronizationContext()); // this runs on the UI Thread
}

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.

C# Start and Stop Thread inside SAME button click event

I am using C#,.Net4.0 and Visual Studio 2010 and I am trying to get this behaviour from my windows form application when the user click on a button:
A GUI LED starts to blink
A long rung operation starts
When the operation at point 2 ends the LED stops blinking
private void Btn_WebService_Click(object sender, EventArgs e)
{
Thread_Blink = new Thread(() => { LED_Blink(LED.WS); });
Thread_Blink.Start();
// Do something that takes time.. Let's imulate with a sleep
Thread.Sleep(2000);
Thread_Blink.Abort();
}
I also tried using 3 different events and/or timers..
private void Btn_WebService_MouseDown(object sender, MouseEventArgs e)
{
Timer_Blink.Enabled = true;
}
private void Btn_WebService_Click(object sender, EventArgs e)
{
// Do something that takes time.. Let's imulate with a sleep
Thread.Sleep(2000);
}
private void Btn_WebService_MouseUp(object sender, MouseEventArgs e)
{
Timer_Blink.Enabled = false;
}
The result is always the same: The LED starts to blink only AT THE END of the long running operation (Thread.Sleep(2000);) and suddenly STOPS so that you can't see anything. Why does this happen and how can I get the desired behaviour?
I add further infos. I tried to use BackgroundWorked and implemented the wanted behavour in this way:
private void Btn_WebService_Click(object sender, EventArgs e)
{
BlinkWorker.RunWorkerAsync(LED.WS);
LedOn(LED.WS);
TestWebService(); // This method takes about 2 seconds to answer..
LedOff(LED.WS);
BlinkWorker.CancelAsync();
}
While the TestWebService() is running I get the LED off(LedOn(LED.WS);). When the TestWebService()has finished the LED comes on.
The BlinkWorker still does not work if started and cancelled inside the Click event.
FYI: If I make a button that starts the blinking and another button that stops it, it works perfectly.
The problem is, you're tying up the UI thread inside that Thread.Sleep. The UI thread is special - it's the only one that can make changes to the UI - so whilst it's busy sleeping, it's not able to service any attempts from your BackgroundWorker or LED_Blink timer callback to change the UI state.
So, you need to not tie up the UI thread. You need to put the Thread.Sleep code (or it's actual real equivalent) into the BackgroundWorkers DoWork handler, or use other means to avoid blocking the UI thread.
Common approaches today would be to make use of async/await if the real work you're trying to do already offers an asynchronous alternative (e.g. await Task.Delay(2000); would be the equivalent of your current Thread.Sleep(2000);). Unfortunately, using async and await would require you to move to a later version of .NET/Visual Studio - but you ought to be considering that anyway. 2010 is quite dated (and also, IMO, probably the worst one to stop on - it was notoriously slow), and .NET 4.0 (as opposed to .NET 4.5.2 or later) is no longer supported.
I would propose that you take a look at the BackgroundWorker class and the ReportProgress method.

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.

Threading in Form_Load - Application now hangs suddenly

Sorry for the lengthy post, I just want to illustrate my situation as best as possible. Read the items in bold and check the code if you want the quick gist of the issue.
I use ClickOnce to deploy a C# application, and have opted to have my application check for updates manually using the ApplicationDeployment Class rather than letting it do the update checking for me.
The program is a specialized network scanner that searches for network devices made by the company I work for. Once the main window is loaded, a prompt is displayed asking if the user would like to scan the network. If they say Yes, a scan begins which can take a minute or two to complete depending on their network settings; otherwise it just waits for the user to do some action.
One of the last things I do in Form_Load is create a new thread that checks for updates. This had all been working fine for several months through about 12 releases and has suddenly stopped working. I didn't change the update code at all, nor change the sequence of what happens when the app starts.
In staring at the code, I think I see why it is not working correctly and wanted to confirm if what I think is correct. If it is, it begs the question as to why it DID work before - but I'm not too concerned with that either.
Consider the following code:
frmMain.cs
private void Form1_Load(object sender, EventArgs e)
{
// set up ui, load settings etc
Thread t = new Thread(new ParameterizedThreadStart(StartUpdateThread));
t.Start(this);
}
private void StartUpdateThread(object param)
{
IWin32Window owner = param as IWin32Window;
frmAppUpdater.CheckForUpdate(owner);
}
frmAppUpdater.cs
public static void CheckForUpdate(IWin32Window owner)
{
if (ApplicationDeployment.IsNetworkDeployed) {
Console.WriteLine("Going to check for application updates.");
parentWindow = owner;
ApplicationDeployment ad = ApplicationDeployment.CurrentDeployment;
ad.CheckForUpdateCompleted += new CheckForUpdateCompletedEventHandler(ad_CheckForUpdateCompleted);
ad.CheckForUpdateProgressChanged += new DeploymentProgressChangedEventHandler(ad_CheckForUpdateProgressChanged);
ad.CheckForUpdateAsync();
// CAN/WILL THE THREAD CREATED IN FORM1_LOAD BE TERMINATED HERE???
}
}
When the CheckForUpdateAsync() callback completes, if no update is available the method call simply returns; if an update IS available, I use a loop to block until 2 things occur: The user has dismissed the "Would you like to scan prompt" AND no scan is currently running.
The loop looks like this, which takes place in ad_CheckForUpdateCompleted:
while (AppGlobals.ScanInProgress || AppGlobals.ScanPromptVisible) {
System.Threading.Thread.Sleep(5000);
}
I sleep for 5 seconds because I figured this was happening in a separate thread and it has seemed to work well for a while.
My main question about the above code is:
When ad.CheckForUpdateAsync(); is called from CheckForUpdate does the thread I created in Form1_Load terminate (or might it terminate)? I suspect it may because the subsequent Async call causes the method to return, and then start another thread?
The only reason I am confused is because this method WAS working for so long without hanging the application and now all of the sudden it hangs and my best effort at debugging revealed that it was that Sleep call blocking the app.
I'd be happy to post the full code for frmAppUpdater.cs if it would be helpful.
When ad.CheckForUpdateAsync(); is called from CheckForUpdate does
the thread I created in Form1_Load terminate (or might it terminate)?
If the CheckForUpdateAsync() call is asynchronous then yes, the thread will terminate, no it won't otherwise.
If you suspect the Sleep to have caused the application hang then these two variables AppGlobals.ScanInProgress and AppGlobals.ScanPromptVisible are probably always set to true! You should start looking at the code that is setting them to true and see what is going on there.
In order to avoid an application hang, you could introduce a variable to avoid sleeping indefinitely:
int nTrials = 0;
while ((AppGlobals.ScanInProgress || AppGlobals.ScanPromptVisible) && (nTrials < 5)) {
System.Threading.Thread.Sleep(5000);
nTrials++;
}
// Check the results and act accordingly
I personally do not like using Sleep for thread synchronization. .NET offers a bunch of classes that are perfect for thread synchronization, WaitHandle being one of them.
See this post at Asynchronous Delegates Vs Thread/ThreadPool?
your form load method seems to be doing synchronous work. you mention that you are using clickonce deployment. Has the binary location changed after the previous release or has permissions on this resource changed. Looks like the work (checkupdates) in the Thread is never finishing and is never handed back to the form.
as an immediate fix, I would change the Thread approach to Delegate - if you use delegate, then this becomes less of a customer issue (the form will respond to end user) but the underlying problem remains.
as the next step, i would go through http://msdn.microsoft.com/en-us/library/ms229001.aspx and do the troubleshoot

How to pause the code until I want? [something like Thread.Sleep(int);]

I think the best way to make my point is to give you these examples:
Console.ReadLine();
Process.WaitForExit();
These functions will pause the application (without freezing the UI).
I need something like this.
In fact, I am writing something like ReadLine() but in windows forms applications.
When you call this method, it should be waited until the user press Enter.
You can create a thread which does a wait on an AutoResetEvent, the UI thread should continue and accept input which signals the event.
Console apps don't have a UI so there's nothing for WaitForExit() to freeze. In a console app the chrome (title bar and window buttons) are handled by the system. In a WinForms app those things aren't painted until you pass the NC_PAINT events to the default handler. If your main message loop is sleeping then your chrome doesn't get painted.
A WinForms app doesn't close automatically so there should be no reason to call something like WaitForExit(). Instead you explicitly tell the app when to close - say when the user presses escape or something.
You can use backGroundWorker which simply checks for cancellation and waits some time using Thread.Sleep(100) for example.
The other way is to create own thread and control all checks and callbacks yourself.
Try this
Task logManager = Task.Factory.StartNew(() => { /* Your code */ }, TaskCreationOptions.LongRunning);
or even
Task screenshotManager;
private void StartScreenshotManager()
{
screenshotManager = Task.Factory.StartNew(() => { ScreenshotManagerJob(); }, TaskCreationOptions.LongRunning);
screenshotManager.ContinueWith((t) => { ScreenshotManagerUpdateUI(); }, TaskScheduler.FromCurrentSynchronizationContext());
}
private void ScreenshotManagerUpdateUI()
{
// ... UI update work here ...
}
private void ScreenshotManagerJob()
{
// your code
}
Most likely, you don't need to halt the execution at all in Windows Forms application.
Windows Forms applications usually require a much more consistent architecture. If you need some code to proceed after the user input, you should not be halting a function execution. In contrast, open a dialog (or provide any other mean for the user to do the required input) and just wait for him to "interact with it". Interaction should raise C# events that will be processed by an logical class instance that knows how to do it and is subscribed to them.

Categories

Resources