Accessing winform control with System.Threading.Task gets stuck

时间:2015-07-31 20:57:14

标签: c# .net multithreading winforms task-parallel-library

The new Task class works great in WPF. However in Winforms, it is always stuck every time it tries to access a Winform control. The "InvokeRequired" routine below that has been working with BackgroundWorker and Thread classes that prevents cross-thread operation error. However, for some reason when it comes to Task, it gets stuck on the Invoke method. Help ?

Here is a sample code. I use NET 4.5.1 framework.

using System;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WinformTaskDemo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            string now = DateTime.Now.ToString();
            Task t = new Task(() => { setText(now); });
            t.Start();
            t.Wait();
        }

        private void setText(string text)
        {
            if (textBox1.InvokeRequired)
            {
                textBox1.Invoke(new Action(() => textBox1.Text = text)); //stuck forever here
            }
            else
            {
                textBox1.Text = text;
            }
        }
    }
}

4 个答案:

答案 0 :(得分:5)

你自己陷入僵局。您运行任务但使用Task.Wait()同步阻止它。此操作会阻止UI线程。现在,从后台线程,您同步将消息发布到刚刚阻止的同一UI消息循环。因此,陷入僵局。

对此的解决方案不是阻止Task,而是异步等待它。虽然问题确实存在,但如果您只是与UI元素进行交互,那么为什么首先要在后台线程中进行?

private async void button1_Click(object sender, EventArgs e)
{
     string now = DateTime.Now.ToString();
     await Task.Run(() => { setText(now); });
}

答案 1 :(得分:0)

它只是一个假设,为什么它会永远停留在那里但是 你的任务在button1.clicked方法中等待,这是一个与GUI相关的方法。

您的操作想要访问UI线程然后被阻止,因为您的任务正在等待。

我试着这样看看它是否会跳回调试器,但它没有

private void setText(string text)
{
    if (textBox1.InvokeRequired)
    {
        Action callSetText = () => setText(text);
        textBox1.Invoke(callSetText);

    }
    else
    {
        textBox1.Text = text;
    }
}

我前段时间为自己尝试过这种方法,你无法阻止UI线程,然后在WinForms中跳回到它中

因此您必须删除t.Wait() 你为什么在那里使用它?

答案 2 :(得分:0)

使用语句锁定来防止同时更改两个线程中的对象值。

    lock(textBox1){
      //Change here the textbox value
      textBox1.Text = "ok";
    }

当已经有其他线程正在使用同一个对象

时,这将锁定并等待

答案 3 :(得分:0)

问题是您是否使用t.Wait()

锁定UI线程

如果删除该操作,则操作将完成。您正在导致竞争条件,因为Wait正在等待设置文本并且因为Wait正在发生而无法设置文本。

评论出来,你会看到。如果你需要在完成后发生一些事情,你可以用

来完成
        t.ContinueWith(_ => { finished()); });