【问题标题】:how to make form delay a display如何使表单延迟显示
【发布时间】:2015-10-04 16:01:52
【问题描述】:

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

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

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

我尝试了这些代码(此处缩短以节省空间):

(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' 修饰符标记此方法并将其返回类型更改为 '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 为增量,但完全不更新显示。

【问题讨论】:

  • 该线程并未涵盖我尝试过的所有内容,并且我找不到任何可以解决我的问题的内容(请参阅上面的编辑)。虽然它确实提高了我对任务的理解 =)
  • 是的,因为我不确定这是否是同一个问题,所以没有投票关闭作为重复项。在异步发布之前很久就没有做过 WinForms。 “什么都没有”发生的事实然后你突然看到最终值感觉就像 Windows 消息队列没有被处理。如果你会得到这种行为,例如有一个循环在普通事件处理程序中更新 UI。不过,不知道具体情况如何适用于您的情况。
  • Application.DoEvents();这做到了。在这里找到:stackoverflow.com/questions/1360944/…
  • 这有时“有效”,但不是一个优雅的解决方案。您的代码会定期触发要触发的事件队列。如果您的代码不经常执行此操作,则 UI 将变得迟缓。由于这确实解决了问题,这可能意味着您正在阻塞 UI 线程而不是在单独的线程上进行处理。

标签: c# winforms stopwatch timedelay


【解决方案1】:

通常你会为此使用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();
    }
}

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

错误 74 'await' 运算符只能在异步方法中使用。考虑使用“异步”修饰符标记此方法并将其返回类型更改为“任务”。

信息很清楚。您必须使用 async 关键字标记您的方法。将返回类型更改为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();
    }
}

【讨论】:

  • 谢谢,有时会测试一下。 Application.DoEvents() 在这种情况下工作得很好,但似乎我在代码的其他点遇到了类似的问题,而更优雅的解决方案会更好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-14
  • 2019-08-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多