WinForm and Looping

I have a WinForm setup and a process that cyclically until a button is clicked on the form.

When I try to run my code, the form does not even display. I suspect this is because the code is stuck in a loop and not displaying WinForm far enough. How can I get a form to display and a loop to run after this point?

+4
source share
7 answers

If you are looping because you need to do something with the GUI periodically, waiting for input, I suggest using the Timer control and Tick event .

If you want to do things without a GUI while waiting, a more traditional timer is better suited to the task,

+4
source

You should probably run a loop in the background thread. The BackgroundWorker class makes this pretty easy.

+2
source

Loading your form freezes because the window form user interface runs on a single thread. And the logic that you put on the Load event of this form works on this thread.

You can easily start the loop in a separate thread using BackgroundWorker in your window form. In your worker’s DoWork event, you place code that has a loop that should run without blocking your user interface. In the Form.Load event, you can start the background working component by calling the RunWorkerAsync method. In the event handler of your button, you put the code to stop the background worker by calling the CancelAsync method .

The article How to implement a form that uses the background shows how to execute it.


About your comment that you cannot update the text of the text field from the desktop component. This is because it is not allowed to change the state of a window control from another thread (your background working code runs in a separate thread). The MSDN documentation states:

Access to Windows Forms controls is not essentially thread safe. If you have two or more threads that control the state of the control, you can force the control to go into an inconsistent state. Other flow-related errors are possible, such as race conditions and deadlocks. It is important to make sure that your controls are accessed in a thread-safe manner.

An example of how you can update the state of Windows form elements from a background thread will look similar to the following (assuming that the new value is already stored in a String variable called text):

 // InvokeRequired required compares the thread ID of the // calling thread to the thread ID of the creating thread. // If these threads are different, it returns true. if (this.textBox1.InvokeRequired) { SetTextCallback d = new SetTextCallback(SetText); this.Invoke(d, new object[] { text }); } else { this.textBox1.Text = text; } 

I borrowed this code, cut off from How to make secure calls in Windows Forms Controls . It can provide you with more information on how to handle multi-threaded window forms.

+1
source

Do not do that.

Windows Forms (like most modern user interface development tools) is an event-driven framework. You should never use a loop that “waits” for something to happen; instead, you want to use an event that fires something.

Essentially, this happens: WinForms has a loop in which a message pump runs, which listens for events from Windows and fires C # events in response to them. Your code runs in the same thread as this message pump (it should, since in WinForms only one thread can touch any given control). Therefore, if you insert this thread into a loop, there is no WinForms code that needs to pump messages, and your user interface seems to hang because it does not respond to any messages from Windows. (If you continue to click on it, you fill out the message queue and get a dialog box that says "This application has stopped responding, do you want to stop it?" Or something like that.)

The correct solution is to do one of the following:

Another solution that will work, but not a good idea:

+1
source

You can use the form load event to trigger the start of a loop.

Thus, this will handle the Me.Load event. However, is it necessary for your loop to run inside the user interface?

0
source

This is because your loop keeps the window function from processing messages, such as those that say they repaint. Place a call to Application.DoEvents () inside your loop so that the user interface continues to function.

However, you need to ask yourself why you are so obsessed. If you, say, copy a bunch of files, this might make sense. However, for most tasks, the answer to the timer should do the trick and will not block the user interface.

0
source

You must start the loop in the background thread using the BackgroundWorker component.

Remember that a background thread cannot interact directly with user interface controls.
To report progress in the user interface, you must call the BackgroundWorker ReportProgress method in the background thread and handle the ProgressChanged event to update the user interface.

You can call the CancelAsync method when the button is clicked and loop until the CancellationPending property is true .

0
source

Source: https://habr.com/ru/post/1311003/


All Articles