Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Most likely you are improperly running a long operation in the main UI thread which prevents the label from updating. You could "fix" this by calling DoEvents():</p> <pre><code>public void UpdateLabel(String newLabel) { lblCurProgress.Text = newLabel; Application.DoEvents(); } </code></pre> <p><strong>But</strong> this is just a band-aid on top of a bad design. <strong>You should properly move that code to a background thread and use a delegate/Invoke() to update the label.</strong></p> <p>Edit: (answering followup question)</p> <p>By default, your application runs in a single thread. This includes the code that you add to control events, as well as the code that you can't see that is running behind the scenes to make your application respond in the way you'd expect. Things like user interaction (mouse clicks, keyboard presses, etc.) and painting messages (when controls are changed, your window is obscured) are placed into a queue. Those pending messages in the queue only get processed once your code has stopped running. If you have a lengthy chunk of code running, like a long loop, then those messages just sit in the queue waiting to be processed. Thus the update to the label doesn't occur until after your loop is done. What DoEvents() does is tells the application to process those pending messages in the queue, right now, and then return to the code that was currently executing. This allows the label to update in real-time like you expect it to.</p> <p>When you encounter situations that are "fixed" by DoEvents(), it simply means that you are attempting to run too much code in the main UI thread. The main UI thread is supposed to be focused on responding to user interaction and keeping the display updated. Code in control event handlers should be short and sweet, so that the main UI thread can get back to doing its main job.</p> <p>The proper fix is to move that lengthy code to a different thread, thus allowing the main UI thread to respond and keep itself updated. For many scenarios, the easiest approach is to place a <a href="http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx" rel="nofollow">BackgroundWorker()</a> control on your form and wire up the DoWork(), ProgressChanged() and RunWorkerCompleted() events. *You have to set the WorkerReportsProgress() property to true, however, to handle the ProgressChanged() event. The latter two events are already marshaled to the main UI thread for you so you don't need to worry about cross-thread exceptions. From the DoWork() handler, you call ReportProgress() and pass out a progress percentage value and an optional other object (it could be anything). Those values can be retrieved in the ProgressChanged() event and used to update the GUI. The RunWorkerCompleted() event fires when all the work in the DoWork() handler has been finished.</p> <p>In your case, you've got a separate class that is doing the work. You can mirror what the BackgroundWorker does by manually creating your own thread in that class to do the work. When you want to update progress, make your class raise a <code>Custom Event</code> that the main form subscribes to. When that event is received, however, it will be running in the context of the separate thread. It is necessary, then, to "marshal" the call across the thread boundaries so that the code is running in the main UI thread before you update the controls. This is accomplished by using delegates ("pointers" to methods) and the Invoke() method. *There are other methods to accomplish this task as well, such as a SynchronizationContext.</p> <p>See <a href="http://msdn.microsoft.com/en-us/library/ms171728%28v=vs.110%29.aspx" rel="nofollow">here</a> for some examples of these approaches.</p> <p>Finally, here is a super simple example of a class that raises custom events from a separate thread:</p> <pre><code>public partial class Form1 : Form { private Clock Clk; public Form1() { InitializeComponent(); Clk = new Clock(); Clk.CurrentTime += new Clock.TimeHack(Clk_CurrentTime); } private void Clk_CurrentTime(string hack) { if (label1.InvokeRequired) { Clock.TimeHack t = new Clock.TimeHack(Clk_CurrentTime); label1.Invoke(t, new object[] { hack }); } else { label1.Text = hack; } } } public class Clock { public delegate void TimeHack(string hack); public event TimeHack CurrentTime; private Thread t; private bool stopThread = false; public Clock() { t = new Thread(new ThreadStart(ThreadLoop)); t.IsBackground = true; // allow it to be shutdown automatically when the application exits t.Start(); } private void ThreadLoop() { while (!stopThread) { if (CurrentTime != null) { CurrentTime(DateTime.Now.ToString()); } System.Threading.Thread.Sleep(1000); } } public void Stop() { stopThread = true; } } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload