简体   繁体   中英

Windows Forms Application is not responding

I have created a Windows Forms Console Application in which I am reading a file which has been written by another console application. The other console application will write about the status of some process and the Windows Forms application will read the status and accordingly update the status text box. I wrote the following code for above scenario.

while (true)
{
    if ((new FileInfo(filename)).Length > 0)
    {
         Status = File.ReadAllText(filename, Encoding.ASCII);
         System.IO.File.WriteAllText(filename, string.Empty);

         Statustb.Text = Status;
         Statustb.Refresh();
                    
         if (Status.Equals("Data Got Loaded"))
         {
             Environment.Exit(0);
         }
     }
 }

When I am running the Windows Forms application it shows "Form Not Responding" but when I comment out these lines then it will run smoothly. But for me it is important to update the status.

You have to understand the architecture of a GUI application.

All interactions with the user happen on one thread.

This includes reacting to things like mouse and keyboard events etc.

If one of these events happens you can handle that event and do something in response to it.

But, until you return from the handler, the application will not be able to receive any further notifications (Windows Messages aka events).

I suspect you have the above code in either the constructor or in one or other event handler. Since you never exit (infinite loop, due to while(true) without a return or break , the operating system cannot send any further events to the application. They get put in a queue to be sent, but never get picked up.

Windows will detect this situation and give you the Not Responding dialog message.

I suggest, that, instead of having the code inside the while(true) loop, you create a Timer with a suitable Interval , and put the body of the while statement (ie the bit between the { and } , but not the while(true) itself ) in the Tick handler.

It is better to use the code inside a timer. Still, you need to make sure that no two different threads at the same time accessing a file. You should have used lock while reading and writing it.

I have a pattern that I use for getting long running tasks off of the UI thread. To see it, create a Winforms project and open the code-behind for Form1.cs. Delete the content and copy the following into that file. It should run and it has comments describing what it is doing.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace POC_DoEvents_alternate
{
    public partial class Form1 : Form
    {
        private Button button1;
        private Button button2;
        private TextBox textbox1;

        public Form1()
        {
            InitializeComponent();

            // programmatically create the controls so that the
            // entire source code is contained in this file.
            // normally you wouldn't do this.

            button1 = new Button();
            button1.Name = "button1";
            button1.Enabled = true;
            button1.Location = new Point(12, 12);
            button1.Size = new Size(144, 35);
            button1.Text = "button1";
            button1.Click += button1_Click;
            this.Controls.Add(button1);

            button2 = new Button();
            button2.Name = "button2";
            button2.Enabled = false;
            button2.Location = new Point(12, 53);
            button2.Size = new Size(144, 35);
            button2.Text = "button2";
            button2.Click += button2_Click;
            this.Controls.Add(button2);

            textbox1 = new TextBox();
            textbox1.Name = "textbox1";
            textbox1.Location = new Point(12, 94);
            textbox1.ReadOnly = true;
            textbox1.Size = new Size(258, 22);
            this.Controls.Add(textbox1);

            this.Load += new System.EventHandler(this.Form1_Load);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            textbox1.Text = "You can't press button 2 yet...";
            button1.Enabled = true;
            button2.Enabled = false;
            this.Cursor = Cursors.AppStarting;

            // start the long running task in a separate background thread
            ThreadPool.QueueUserWorkItem(Async_LongRunningTask, "Form1_Load");

            // calling the QueueUserWorkItem will not block. Execution will
            // contiune immediately with the lines below it.

            textbox1.BackColor = Color.LightPink;

            // this event handler finishes quickly so the form will paint and
            // be responsive to the user.
        }

        private void button1_Click(object sender, EventArgs e)
        {
            textbox1.Text = "Button 1 pressed";
        }

        private void button2_Click(object sender, EventArgs e)
        {
            textbox1.Text = "Button 2 pressed";
        }

        private void Async_LongRunningTask(object state)
        {
            // put all your long running code here, just don't put any
            // UI work on this thread

            Thread.Sleep(5000);     // simulates a long running task

            // put any UI control work back on the UI thread
            this.Invoke((MethodInvoker)delegate
            {
                button2.Enabled = true;
                textbox1.Text = "End of long running task: " + state.ToString();
                textbox1.BackColor = SystemColors.Control;
                this.Cursor = Cursors.Default;

                // as with anything on the UI thread, this delegate
                // should end quickly
            });

            // once the delegate is submitted to the UI thread
            // this thread can still do more work, but being a
            // background thread, it will stop when the application
            // stops.

            Thread.Sleep(2000);     // simulates a long running task
        }
    }
}

You can add
using System.Windows.Forms;
Application.DoEvents();
in the While

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM