1

当表单应用程序启动时,我需要运行一个无限循环。一个表格是这样开始的:

public Form1()
{
        InitializeComponent();
}

现在我想运行另一个函数,该函数内部将有一个无限循环,睡眠时间为一秒:

public void doProcess(){

    while(true){
         Thread.Sleep(1000);
         // other task
    }
}

我怎样才能做到这一点?当我调用doProcess()构造函数时,它不显示表单。我尝试运行 while 循环 10 次迭代。只有在所有迭代完成后才会显示该表单。我不明白为什么会这样。

4

6 回答 6

4

简而言之,你正在用这个无限循环阻塞 UI 线程。

异步运行:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        BeginWork();
    }

    private async void BeginWork()
    {
        while (true)
        {
            // Since we asynchronously wait, the UI thread is not blocked by the file download.
            var result = await DoWork(formTextField.Text);

            // Since we resume on the UI context, we can directly access UI elements.
            formTextField.Text = result;
        }
    }

    private async Task<string> DoWork(object text)
    {
        // Do actual work
        await Task.Delay(1000);
        // Return Actual Result
        return DateTime.Now.Ticks.ToString();
    }
}

对于更新循环,while(true) 可能有点过分。我是否可以建议您潜在地使用计时器,和/或利用取消令牌急切地取消那些花费了太长时间而不更新 UI 的请求,并且在高性能场景中可能会产生陈旧的结果。

例如

public partial class Form1 : Form
{
    private readonly Timer _sampleTimer;

    public Form1()
    {
        InitializeComponent();

        _sampleTimer = new Timer
            {
                Interval = 500 // 0.5 Seconds
            };
        _sampleTimer.Tick += DoWorkAndUpdateUIAsync;
    }

    private async void DoWorkAndUpdateUIAsync(object sender, EventArgs e)
    {
        // Since we asynchronously wait, the UI thread is not blocked by "the work".
        var result = await DoWorkAsync();

        // Since we resume on the UI context, we can directly access UI elements.
        resultTextField.Text = result;
    }

    private async Task<string> DoWorkAsync()
    {
        await Task.Delay(1000); // Do actual work sampling usb async (not blocking ui)
        return DateTime.Now.Ticks.ToString(); // Sample Result
    }

    private void startButton_Click(object sender, EventArgs e)
    {
        _sampleTimer.Start();
    }

    private void stopButton_Click(object sender, EventArgs e)
    {
        _sampleTimer.Stop();
    }
}
于 2013-06-17T08:04:06.000 回答
4

您可以像这样开始一个新线程:

new Thread(() => 
{
    while (true)
    {
        Thread.Sleep(1000);

        //other tasks
    }
}).Start();

虽然我建议你在做之前阅读线程。如果你想从不同的线程更新表单,你应该使用:Form.Invoke().

例如:w是表格

 w.Invoke((MethodInvoker) delegate
 {
     w.Width += 100;
 });
于 2013-06-17T08:14:10.883 回答
2

发生这种情况是因为 ctor 永远不会退出,因此无法显示表单 - 这不是很明显吗?

如果你想运行一个永远/睡眠循环线,你必须把它关掉。

不要在 GUI 事件处理程序(或 ctors)中等待。

你不能使用forms.timer吗?

于 2013-06-17T08:03:03.987 回答
1

您正在阻止 UI 线程。因此,只要doProcess运行,UI 就无法处理。

如果您使用 .Net 4.5,则可以使用异步等待:

public async void doProcess(){
    while(true){
         await Task.Delay(1000);
         // other task
    }
}

更清洁的解决方案是使用每 1 秒触发一次事件的计时器。您可以在 10 次循环后关闭计时器。

于 2013-06-17T08:04:21.173 回答
0

您没有退出构造函数,因此表单不会显示。如果您想在表单显示后执行此操作,请将您的代码放在 Form_Load 事件中。但是您更愿意使用后台线程来执行此操作,因此您可以使用 backgroundworker

于 2013-06-17T08:04:49.567 回答
0

您可以将它放在 Initialize 组件之后,或者找到表单的加载事件并将代码粘贴到那里

于 2013-06-17T08:12:05.867 回答