我创建了一个Window Form Console应用程序,其中我正在读取一个由另一个控制台应用程序编写的文件。 另一个控制台应用程序将写入某个进程的状态,窗口表单应用程序将读取状态并相应地更新状态文本框。 我为上面的场景编写了以下代码。
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);
}
}
}
当我运行窗口表单应用程序时,它显示表单无响应,但是当我将注释掉这些代码时,它将顺利运行,但对我来说,重要的是更新状态。
答案 0 :(得分:3)
您必须了解GUI应用程序的体系结构。
与用户的所有交互都发生在一个线程上。
这包括对鼠标和键盘事件等做出反应。
如果其中一个事件发生,您可以处理该事件并做出回应。
但是,在您从处理程序返回之前,应用程序将无法再接收任何通知(Windows Messages aka事件)。
我怀疑你在构造函数或一个或其他事件处理程序中有上面的代码。由于您永远不会退出(由于while(true)
没有return
或break
而导致无限循环,操作系统无法向应用程序发送任何其他事件。它们会被放入队列中以便发送,但永远不会被接受。
Windows将检测到这种情况,并为您提供Not Responding
对话框消息。
我建议,不要在while(true)
循环中包含代码,而是使用合适的Timer
创建Interval
,然后设置正文 tick语句中的while语句(即{
和}
之间的位,而不是while(true)
本身)。
答案 1 :(得分:1)
最好使用计时器内的代码。 但是,您需要确保在访问文件的同时没有两个不同的线程。你应该在阅读和写作时使用过锁。
答案 2 :(得分:0)
我有一个模式,用于从UI线程中获取长时间运行的任务。要查看它,请创建一个Winforms项目并打开Form1.cs的代码隐藏。删除内容并将以下内容复制到该文件中。它应该运行,它有描述它正在做什么的评论。
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
}
}
}