【问题标题】:Adding delay while taking in account execution time在考虑执行时间的同时增加延迟
【发布时间】:2017-06-17 12:32:18
【问题描述】:

因此,我正在尝试创建一种方法,该方法可以为窗体上的控件移动设置动画。我预先生成了控件将要到达的所有点,如下所示:

private static List<decimal> TSIncrement(int durationInMilliseconds, decimal startPoint, decimal endPoint)
    {
        List<decimal> tempPoints = new List<decimal>();
        decimal distance = endPoint - startPoint;
        decimal increment = distance / durationInMilliseconds;
        decimal tempPoint = (decimal)startPoint;

        for (decimal i = durationInMilliseconds; i > 0; i--)
        {
            tempPoint += increment;
            tempPoints.Add(tempPoint);
        }
        return tempPoints;
    }

这会输出一个列表,其中包含与动画持续时间中毫秒数一样多的点。我想你可以猜到我之后在做什么:

public static void ControlAnimation(Control control, Point locationEndpoint, int delay)
    {
        if (delay > 0)
        {
            List<decimal> tempXpoints = TSIncrement(delay, control.Location.X, locationEndpoint.X);
            List<decimal> tempYpoints = TSIncrement(delay, control.Location.Y, locationEndpoint.Y);

            for (int i = 0; i < delay; i++)
            {
                control.Location = new Point((int)Math.Round(tempXpoints[i]), (int)Math.Round(tempYpoints[i]));
                Thread.Sleep(1); //I won't leave this obviously, it's just easier for now
            }
        }
    }

在实际的方法中,我浏览了这个点列表并使用它们来创建控件的新位置(我实际上使用了两个列表作为横坐标和纵坐标)。

我的问题在于在每次换档之间产生一毫秒的延迟。由于循环中的代码需要一些时间来执行,所以我通常会多花大约 5 秒的时间。

我尝试使用秒表来测量设置 control.location 所需的时间,并将其减去 1 毫秒的延迟。秒表也增加了一些延迟,因为我每次都要开始、停止和重置它。

那么我应该怎么做,如何改进我的代码?非常感谢任何反馈:)

【问题讨论】:

  • 不要依赖定时器回调/Thread.Sleep 的时间是否准确。它不是。启动一个(单个)秒表,然后使用asyncawait Task.Delay()(或计时器,如果你是受虐狂,但绝对不是 Thread.Sleep) 导致短暂的延迟。当延迟结束时,找出已经过去了多少 实际 时间(通过检查 Stopwatch 实例),然后根据这个实际经过的时间值而不是由 wonky 导出的隐式累积时间值进行计算计时器。
  • 谢谢@spender,我一定要试试这个。

标签: c# winforms c#-4.0 timing


【解决方案1】:

在 WinForms 中你不会得到低于 50 毫秒左右的可靠延迟,所以这就是我在下面使用的延迟:

private Random R = new Random();

private async void button1_Click(object sender, EventArgs e)
{
    button1.Enabled = false;
    label1.AutoSize = false;
    label1.Size = button2.Size;
    Point p = new Point(R.Next(this.Width - button2.Width), R.Next(this.Height - button2.Height));
    label1.Location = p;
    label1.SendToBack();

    await MoveControl(button2, p, R.Next(2000, 7001));

    button1.Enabled = true;
}


private Task MoveControl(Control control, Point LocationEndPoint, int delayInMilliseconds)
{       
    return Task.Run(new Action(() =>
    {
        decimal p;
        int startX = control.Location.X;
        int startY = control.Location.Y;
        int deltaX = LocationEndPoint.X - startX;
        int deltaY = LocationEndPoint.Y - startY;
        System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
        sw.Start();

        while(sw.ElapsedMilliseconds < delayInMilliseconds)
        {
            System.Threading.Thread.Sleep(50);
            p = Math.Min((decimal)1.0, (decimal)sw.ElapsedMilliseconds / (decimal)delayInMilliseconds);
            control.Invoke((MethodInvoker)delegate {
                control.Location = new Point(startX + (int)(p * deltaX), startY + (int)(p * deltaY));
            });
        }
    }));
}

【讨论】:

  • await Task.Delay(50)?
  • 检查循环体的第一行。一个未等待的 Task.Delay 确实......好吧......不是很多。
  • 哈,现在明白了。我应该打个盹。
猜你喜欢
  • 2013-08-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多