如何让表单延迟显示

how to make form delay a display

编辑:Application.DoEvents();这做到了。在这里找到:Force GUI update from UI Thread

c#,winforms。我想以 1 为步长增加一个数字,并将这些增量显示在列表视图中,以便用户看到数字递增(例如从 10 到 15)。

我有另一个按钮,在单击时仅增加 1,并使用相同的 display()。它工作正常并按预期更新显示。

我尝试了这些代码(为了在此处保存 space 而缩短):

(1)

for (int i = 0; i < 5; i++) 
{
    var t = Task.Run (async () =>
    {
        myInt++;
        await Task.Delay(300);
        display(); //forces screen refresh
    });
}

(2)

for (int i = 0; i < 5; i++) 
{
    var t = Task.Run (() =>
    {
        myInt++;
        Task.Delay(300).Wait;
        display();
    });
    //t.Wait(); //causes "An unhandled exception of type 'System.AggregateException' occurred in mscorlib.dll"
}

(3)

for (int i = 0; i < 5; i++) 
{
    myInt++;
    display();
    System.Threading.Thread.Sleep(300);
}

(4)

Stopwatch stopwatch = new Stopwatch();
for (int i = 0; i < 5; i++) 
{
    stopwatch.Restart();
    while (true)
    {
        if (stopwatch.ElapsedMilliseconds >= 300)
        {
            break;
        }
    }
stopwatch.Stop();
myInt++;
display();
}

都用这个:

private void display()
{   
    myListView.Items.Clear();
    myListView.Items.Add(new ListViewItem(new[] { myInt }));
}

(1) 和 (2) 将数字递增 5,但显示根本没有更新。它显示何时由其他功能更新显示。

(3) 和 (4) 将数字递增 5,但显示仅在大约 1500 毫秒后更新,显示跳过单个步骤并仅显示最终结果(例如 15)。

有什么建议可以使这项工作成功吗?我能以某种方式强制刷新 display() 函数吗?

为什么 t.Wait();导致异常? (我在网上的某个地方找到了任务代码)

编辑:

(5)

private void team_comm_btn_all_Click(object sender, EventArgs e)
{
    for (int i = 0; i < 5; i++) 
    {
            await Run(i); //error 74 see below
    }
}

private async Task Run(int i)
{
    myInt++;
    display();
    await Task.Delay(300);
}

等待运行(i);给出以下内容: 错误 74 'await' 运算符只能在异步方法中使用。考虑使用 'async' 修饰符标记此方法并将其 return 类型更改为 'Task'.

只是做 "Run(i)" 而不是给出 "await" 缺失的警告...在这种情况下,它编译并递增 5,没有任何延迟。

(6)

private void team_comm_btn_all_Click(object sender, EventArgs e)
{
   for (int i = 0; i < 5; i++) 
   {
       var task = Task.Run(async () =>
        {
            await Run(i);
        });
   }
}

private async Task Run(int i)
{
    myInt++;
    display();
    await Task.Delay(300);
}

增加 5 但根本不更新显示。

通常您会为此使用 System.Windows.Forms.Timer。但是 async/await 一旦您理解它(并仔细阅读编译器警告和错误消息),这些事情就会变得微不足道。简而言之,(5) 是解决编译器错误的小修改方法。
但是让我们从头开始。假设您首先像这样编写一个普通的同步版本(基本上是您的 (3))

private void team_comm_btn_all_Click(object sender, EventArgs e)
{
    for (int i = 0; i < 5; i++) 
    {
        if (i != 0) System.Threading.Thread.Sleep(300);
        myInt++;
        display();
    }
}

只是看到 UI 没有更新。所以你决定把它变成异步的,在 async/await 的帮助下很简单用 Task.Delay 替换 Thread.Sleep 像这样

private void team_comm_btn_all_Click(object sender, EventArgs e)
{
    for (int i = 0; i < 5; i++) 
    {
        if (i != 0) await Task.Delay(300);
        myInt++;
        display();
    }
}

但是现在编译失败,出现如下错误

Error 74 The 'await' operator can only be used within an async method. Consider marking this method with the 'async' modifier and changing its return type to 'Task'.

消息已经足够清楚了。您必须async 关键字标记您的方法。将 return 类型更改为 Task 的其他建议怎么样,通常您应该考虑它,但由于您在事件处理程序中,即无法更改签名的方法,您可以忽略那部分 - 这就是为什么 async void 被允许的确切情况。

总而言之,您的最终代码将如下所示

private async void team_comm_btn_all_Click(object sender, EventArgs e)
{
    for (int i = 0; i < 5; i++) 
    {
        if (i != 0) await Task.Delay(300);
        myInt++;
        display();
    }
}