我的文本框在 Task.Run 内时没有改变

My Textbox does not change when inside Task.Run

我使用 C# Winforms

我正在使用 Task.Run() 以使我的 WinForm 不冻结。

在此代码中,我需要更新文本框文本。

我尝试直接和通过调用更新文本框文本,但没有成功。

我尽量减少我的代码以专注于问题

知道如何更新 Task.Run() 中的文本框吗?

public async void MyFunction()
{
    await Task.Run(() =>
    {
        lvwFiles.BeginInvoke(new Action(() =>
        {
            foreach (ListViewItem item in this.lvwFiles.Items)
            {
                txtLog.Text = item.Text + "\r\n" +txtLog.Text;
                if (txtLog.InvokeRequired)
                {
                    txtLog.Invoke(new MethodInvoker(delegate { txtLog.Text = item.Text + "\r\n" + txtLog.Text; }));
                }
                Thread.Sleep(4000);

                item.BackColor = Color.FromArgb(128, 255, 128);
            }
        }));
    });
}

您在不同的线程中使用 Task.Run 到 运行,但随后您使用 BeginInvoke,它告诉它 运行 该代码UI 线程。所以结果就是你的代码在UI线程上运行。由于您正在使用 Thread.Sleep(),因此您锁定了 UI 线程。

相反,运行 这一切都在您的 UI 线程上,并使用 Task.Delay() 而不是 Thread.Sleep() 以避免锁定 UI 线程。

public async void MyFunction()
{
    foreach (ListViewItem item in this.lvwFiles.Items)
    {
        txtLog.Text = item.Text + "\r\n" + txtLog.Text;
        await Task.Delay(4000);

        item.BackColor = Color.FromArgb(128, 255, 128);
    }
}

正如 Gabriel 所指出的那样,您正在 运行 创建一个新线程,然后在 BeginInvoke 之后立即返回 UI 线程。您可以使用 Gabriel 的回答,运行 UI 线程中的所有内容,或者您​​可以将代码更改为以下内容,这样您就可以将信息作为 [=11] 发送到 UI 线程=] 假设做。

public async void MyFunction()
{
    //run your code on new thread
    await Task.Run(() =>
    {
        foreach (ListViewItem item in this.lvwFiles.Items)
        {
            //whatever has to trigger that UI update is required
            if (txtLog.InvokeRequired)
            {
                //update UI thread
                Dispatcher.BeginInvoke(new Action(() => txtLog.Text = item.Text + "\r\n" + txtLog.Text));
            }
            // Thread.Sleep(4000); -> I'm not sure if sleep or delay would be required, for me, it looks like a waste of time. And 4 seconds is quite a lot.
            //this also looks like UI update, if so, add to dispatcher, or create another one when needed.
            item.BackColor = Color.FromArgb(128, 255, 128);
        }
    });
}