我有问题。我需要用标签创建一个滚动效果。其实质是将值放在标签上,延迟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)......等等。
我将不胜感激:)
答案 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
事件替换外部循环,使得计时器的每个“滴答”执行一次迭代。请按照以下步骤操作:
Timer
控件。我在这里假设它被称为timer1
。Interval
设置为1000.这将使其每秒“勾选”一次。请确保Enabled
属性设置为False
。在表单中添加几个私有字段,以跟踪生成的数字数组以及要填充的下一个标签的索引:
private int[] generatedArray;
private int nextControlIndex = 0;
双击表单中的计时器以添加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();
}
}
最后,更改generator()
方法的代码以设置私有字段并启动计时器:
public void generator() // присваивание текстбоксам значений
{
generatedArray = getUniqueRandomArray(1, 81, 20).ToArray();
nextControlIndex = 0;
green = 0;
timer1.Start();
}
就是这样。现在,只要您调用generator()
函数,就会逐渐填充标签。