C# 如何使用任务闪烁标签

C# 如何使用任务闪烁标签,c#,.net,winforms,C#,.net,Winforms,我想要一个扩展方法来闪烁Windows窗体上的标签 所以我写了下面的代码 private static ConcurrentBag<Task> Tasks = new ConcurrentBag<Task>(); private static CancellationTokenSource cts = null; public static void Blink(this Label label, string text) { cts = new Cancell

我想要一个扩展方法来闪烁Windows窗体上的标签

所以我写了下面的代码

private static ConcurrentBag<Task> Tasks = new ConcurrentBag<Task>();
private static CancellationTokenSource cts = null;

public static void Blink(this Label label, string text)
{
    cts = new CancellationTokenSource();
    Task task = new Task(async () =>
    {
        label.Invoke((Action)(() =>
        {
            label.Text = text;
            label.Visible = true;
        }));
        while (true)
        {
            label.Invoke((Action)(() => { label.Visible = !label.Visible; }));
            if (cts.IsCancellationRequested)
            { 
                break; 
            }
            await Task.Delay(600);
        }
        label.Invoke((Action)(() => { label.Visible = false; }));
    },cts.Token);

    Tasks.Add(task);
    task.Start();
}
label1.Blink("Hello World!");
label1.Blink("Hi");
如果我有两个按钮,一个闪烁,一个停止,一切都很好。。。 我的问题是,如果我有一个按钮与以下代码

private static ConcurrentBag<Task> Tasks = new ConcurrentBag<Task>();
private static CancellationTokenSource cts = null;

public static void Blink(this Label label, string text)
{
    cts = new CancellationTokenSource();
    Task task = new Task(async () =>
    {
        label.Invoke((Action)(() =>
        {
            label.Text = text;
            label.Visible = true;
        }));
        while (true)
        {
            label.Invoke((Action)(() => { label.Visible = !label.Visible; }));
            if (cts.IsCancellationRequested)
            { 
                break; 
            }
            await Task.Delay(600);
        }
        label.Invoke((Action)(() => { label.Visible = false; }));
    },cts.Token);

    Tasks.Add(task);
    task.Start();
}
label1.Blink("Hello World!");
label1.Blink("Hi");

在使用Blink方法启动第二个任务之前,我需要一种方法来取消第一个任务…

目前的解决方案存在一些问题。首先,取消令牌是静态的,因此它们将在所有闪烁的标签之间共享。另一方面,通过使用任务构造函数、Start和Control.Invoke,代码过于复杂

更简单的方法如下所示:

public static Tuple<Task, CancellationTokenSource> Blink(this Label label)
{
  var cts = new CancellationTokenSource();
  var task = BlinkAsync(label, cts.Token);
  return Tuple.Create(task, cts);
}

private static Task BlinkAsync(Label label, CancellationToken cancellationToken)
{
  label.Visible = true;
  while (true)
  {
    label.Visible = !label.Visible;
    cancellationToken.ThrowIfCancellationRequested();
    await Task.Delay(600);
  }
}

我不知道为什么,但它不起作用。在我的应用程序中,我有一个场景,同一个标签应该更改其文本并闪烁。这就是重点。按顺序闪烁的停止不会给取消任务的时间。我尝试了Task.WhenAllTasks.ToArray,但没有成功…为什么要将闪烁与设置标签文本混为一谈?闪烁不应设置文本。案子结束了,为什么不呢?这不是重点。。。关键是要以适当的方式取消第一个任务…从Blink方法返回取消令牌,您应该能够取消该任务。哦,还有,从方法中生成取消令牌。摆脱静态实例。如果我扩展Label控件,将CancellationTokenSource作为属性,在Blink方法中取消它,您认为如何?@user3641815:如果您要扩展Label,为什么要使用CTS或Blink方法?为什么不干脆拥有一个IsBlinking酒店呢?我对我想到的解决方案很着迷,没有其他选择,谢谢!