【问题标题】:Toggling Checkbox on Timer/Delay Without Thread.Sleep在没有 Thread.Sleep 的情况下切换定时器/延迟复选框
【发布时间】:2018-01-20 03:42:03
【问题描述】:

我有 2 个复选框。 Checkbox_toggle 选中后,将启动一个切换序列。此切换序列将使用计时器/延迟检查和取消选中 Checkbox_control

只要 Checkbox_toggle 被选中,我希望它继续循环。但是, Thread.Sleep 不适用于我的目的,因为我需要程序的其余部分继续运行。我查看了BackgroundWorker,但我找不到一个例子/我对它的理解不够好,无法将它应用到我的程序中。我正在使用 .NET 4.0,所以我不能使用 Task.Delay

我知道BackgroundWorkerProgressChanged 事件可用于更新用户界面,但我不确定如何将它用于我的应用程序。我也愿意接受不是BackgroundWorker 的另一种解决方案。

我尝试使用 Task.Delay 的这个 .NET 4.0 实现,但它没有按我的意愿工作。它贯穿了所有这些,但延迟实际上并没有延迟循环

    public static System.Threading.Tasks.Task Delay(double milliseconds)
    {
        var tcs = new TaskCompletionSource<bool>();
        System.Timers.Timer timer = new System.Timers.Timer();
        timer.Elapsed += (obj, args) =>
        {
            tcs.TrySetResult(true);
        };
        timer.Interval = milliseconds;
        timer.AutoReset = false;
        timer.Start();
        return tcs.Task;
    }

    private void Checkbox_toggle_CheckedChanged(object sender, EventArgs e)
    {
        while (Checkbox_toggle.Checked == true)
        {
            Checkbox_control.Checked = true;
            Delay(1000);
            Checkbox_control.Checked = false;
            Delay(1000);
        }
    }

在这里找到任务延迟事件:https://stackoverflow.com/a/15342256/8407531

我的实际问题:如何在不使用 Thread.Sleep 的情况下切换计时器上的复选框,或者如何将其偏移到另一个线程?如果可能的话,这个延迟需要从其他线程进行调整。

【问题讨论】:

  • 不要使用BackgroundWorker,使用System.Windows.Forms.Timer

标签: c# .net winforms


【解决方案1】:

您似乎误解了计时器的使用。通常你会为Timer设置一个间隔,如果你想要重复的动作,你会设置timer.AutoReset = true

public Form1()
{
    InitializeComponent();

    System.Timers.Timer timer = new System.Timers.Timer();

    timer.Interval = 1000;
    timer.AutoReset = true;

    timer.Elapsed += Timer_Elapsed;

    timer.Start();
}

现在,当您现在启动计时器时,它会等到间隔结束,然后它会触发 Elapsed 事件并在您注册事件时实现的事件处理程序中执行一些操作:

private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
    // here you can specify whether the toggeling should occur or not
    if (Checkbox_toggle.Checked)
    {
        // toggling needs to be invoked since it is called on a different thread
        this.checkBox_Control.BeginInvoke(
                new Action(() => this.checkBox_Control.Checked = !this.checkBox_Control.Checked));
    }
}

计时器将继续运行,而不会冻结您的 GUI。您可以简单地选中或取消选中Checkbox_toggle,然后切换将停止。但计时器将继续运行。如果您再次检查Checkbox_toggle,计时器将再次切换。

【讨论】:

  • 我认为这绝对符合我正在寻找的内容,但我正在努力弄清楚如何实际使用该代码主动切换。我正在尝试实现类似于:if (Checkbox_toggle.Checked) { Checkbox_control.Checked = !Checkbox_control.CheckedState} 的东西。这给出了一个语法错误,但我希望能明白这一点
  • @ScottMyers 差不多,只需反转Checked 属性并将其写回:Checkbox_control.Checked = !Checkbox_control.Checked; 我将其添加到我的帖子中
  • 好的,它看起来可以正常工作,但是有一个奇怪的行为。如果我将鼠标悬停在它上面,UI 只会更新复选框的状态。为了让它再次更新,我需要将鼠标从复选框上移开,然后再将其移回。为清楚起见,如果我快速将鼠标移开和移开复选框(不单击),那么我可以看到复选框选中和取消选中。但是,如果我不这样做,我将看不到 UI 更新。为什么会这样?如果这超出了这个问题的范围,我可以做一个新的
  • @ScottMyers 我的错。您需要调用InvokeBeginInvoke,因为计时器事件到达不同的线程。查看我的更新答案
  • 太完美了!非常感谢
猜你喜欢
  • 2018-04-25
  • 2013-10-19
  • 1970-01-01
  • 2012-11-28
  • 1970-01-01
  • 1970-01-01
  • 2011-06-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多