使用延迟C#的标签滚动效果

时间:2017-12-05 00:19:34

标签: c# winforms scroll label

我有问题。我需要用标签创建一个滚动效果。其实质是将值放在标签上,延迟1秒。 我有一个为数组的每个标签号生成的函数。但它立即发生,我试图延迟。我使用了Timer,但它没有给我任何结果,或者我只是不知道如何正确使用它。还尝试使用Thread.Sleep(),但它没有给我预期的结果。

public void generator() // присваивание текстбоксам значений 
    {
        int[] array = getUniqueRandomArray(1, 81, 20).ToArray();
        green = 0;

        for (int i = 0; i < array.Length; i++)
        {
            panel1.Controls[i].Text = array[i].ToString();
            Thread.Sleep(350);
            panel1.Controls[i].Refresh();

            foreach (DataGridViewRow currentRow in dataGridView1.Rows)
            {
                foreach (DataGridViewCell currentCell in currentRow.Cells)
                {
                    if (Convert.ToInt32(currentCell.Value) == array[i] && currentCell.Style.BackColor == Color.Yellow)
                    {
                        currentCell.Style.BackColor = Color.Green;
                        green++;
                        panel1.Controls[i].BackColor = Color.Green;
                    }

                }
            }
        }
    }

getUniqueRandomArray(1, 81, 20) - 此函数生成一个从1到80的数组,并返回20个数字。

当我使用Thread.Sleep(350)时,我按下按钮并且表单处于冻结状态,然后每个标签从一个延迟350毫秒的数组中获取一个值。如果我再次按下此按钮,当前值将替换先前的值而不清除以前的值,尽管我用以下方法清除它们:

for (int i = 0; i < panel1.Controls.Count; i++)
        {
            panel1.Controls[i].BackColor = Color.White;
            panel1.Controls[i].Text = null;
        } 

这是我的实际结果。但我期望在没有冻结的情况下描述说明,并且在另一个线程中允许我在运行这样的圆圈时使用表单。

最后我会尝试更清楚地解释:
我有20个标签和20个数字。我需要为每个标签分配一些延迟的标签 - label1 =&#34; 1&#34; - &GT; (等待1s) - &gt; label2 =&#34; 2&#34; - &GT; (等待1s)......等等。

我将不胜感激:)

2 个答案:

答案 0 :(得分:1)

让你的generator()成为异步的:

generator();


private async void generator()
{
   //(...)

   for (int i = 0; i < array.Length; i++)
   {
      panel1.Controls[i].Text = array[i].ToString();
      panel1.Controls[i].Refresh();
      await Task.Run(async () => await Task.Delay(1000));

      //(...)

   }
}

关于评论:

await Task.Run(async () => await Task.Delay(1000)) 

是一个非阻塞的等待者。根据上下文,第二个任务可能不是上下文的。如果是这种情况,可以使用ConfigureAwait()来解决这个问题。

await Task.Run(async () => await Task.Delay(1200).ConfigureAwait(true)).ConfigureAwait(true);


await Task.Run(async () => await Task.Delay(1000));中的第二个异步作为Unwrap()方法。
通常,Task.Factory.StartNew()启动一个在不同线程中运行的新任务,并立即返回。 但是在.Unwrap()上使用Task<Task><TResult>可以返回Task<TResult>,这是完成内部任务的代理:

bool _task1 = await Task.Factory.StartNew(async delegate
{
   await Task.Delay(1000);
   return true;
}, TaskScheduler.Default).Unwrap<bool>();

因此,遵循相同的逻辑,可以用新的awaiter替换Unwrap()方法。

bool _task2 = await await Task.Factory.StartNew(async delegate
{
   await Task.Delay(1000);
   return true;
}, TaskScheduler.Default);

现在Task.Factory.StartNew()会返回Task<Task<bool>> 如果您等待Task<Task<bool>>,它将返回Task<bool>,并再次等待该任务,则返回一个布尔值。

但是,如果您不需要类型结果:

await await Task.Factory.StartNew(async delegate
{
   await Task.Delay(1000);
}, TaskScheduler.Default);

在功能上等同于:

await Task.Run(async () => await Task.Delay(1000)) 

答案 1 :(得分:0)

您可以使用表单上的Timer控件执行此操作。诀窍是让计时器Tick事件替换外部循环,使得计时器的每个“滴答”执行一次迭代。请按照以下步骤操作:

  1. 在表单中添加Timer控件。我在这里假设它被称为timer1
  2. 在计时器属性中,将Interval设置为1000.这将使其每秒“勾选”一次。请确保Enabled属性设置为False
  3. 在表单中添加几个私有字段,以跟踪生成的数字数组以及要填充的下一个标签的索引:

    private int[] generatedArray;
    private int nextControlIndex = 0;
    
  4. 双击表单中的计时器以添加Tick事件处理程序。在处理程序中,添加以下代码:

    private void timer1_Tick(object sender, EventArgs e)
    {
        int i = nextControlIndex++;
        if (i < panel1.Controls.Count && i < generatedArray.Length)
        {
            panel1.Controls[i].Text = generatedArray[i].ToString();
    
            foreach (DataGridViewRow currentRow in dataGridView1.Rows)
            {
                foreach (DataGridViewCell currentCell in currentRow.Cells)
                {
                    if (Convert.ToInt32(currentCell.Value) == generatedArray[i] && 
                        currentCell.Style.BackColor == Color.Yellow)
                    {
                        currentCell.Style.BackColor = Color.Green;
                        green++;
                        panel1.Controls[i].BackColor = Color.Green;
                    }
                }
            }
        }
        else
        {
            timer1.Stop();
        }
    }
    
  5. 最后,更改generator()方法的代码以设置私有字段并启动计时器:

    public void generator() // присваивание текстбоксам значений 
    {
        generatedArray = getUniqueRandomArray(1, 81, 20).ToArray();
        nextControlIndex = 0;
        green = 0;
        timer1.Start();
    }
    
  6. 就是这样。现在,只要您调用generator()函数,就会逐渐填充标签。