0

I have 2 checkboxes. Checkbox_toggle, when checked, will initiate a toggle sequence. This toggle sequence will check and uncheck Checkbox_control with a timer/delay.

I want that to keep looping as long as Checkbox_toggle is checked. However, Thread.Sleep won't work for my purposes as I need the rest of the program to continue running. I looked into BackgroundWorker and I can't quite find an example/I don't understand it well enough to apply it to my program. I'm using .NET 4.0 so I can't use Task.Delay.

I know with BackgroundWorker there's the ProgressChanged event that can be used to update the UI, but I'm not really sure how I would be able to use that for my application. I'm also open to another solution that isn't BackgroundWorker.

I tried using this .NET 4.0 implementation of Task.Delay, but it's not working how I'd like. It runs through all of that but the delay doesn't actually delay the loop

    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);
        }
    }

Task delay event found here: https://stackoverflow.com/a/15342256/8407531

My actual question: How can I toggle a checkbox on a timer without using Thread.Sleep, or how can I offset it to another thread? If possible, this delay needs to be adjustable from the other thread.

1 Answers1

0

It seems that you misunderstood the use of the timer. Normally you would set up the Timer with an interval, and if you want repeated actions then you would set 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();
}

Now when you start the timer now it will wait until the interval is over then it will fire the Elapsed event and perform some action in the eventhandler that you implemented when you registered the event:

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));
    }
}

The timer will continue to run, without freezing your GUI. And you can simply check or uncheck the Checkbox_toggle and the togegling will stop. But the timer will continue to run. If you check the Checkbox_toggle again the timer will toggle again.

Mong Zhu
  • 23,309
  • 10
  • 44
  • 76
  • I think this is definitely along the lines of what I'm looking for, but I'm struggling to figure out how I would actually make it actively toggle with that code. I'm trying to implement something that would be along the lines of: `if (Checkbox_toggle.Checked) { Checkbox_control.Checked = !Checkbox_control.CheckedState}`. That gives a syntax error, but I hope that gets the point across – Scott Myers Aug 11 '17 at 15:49
  • @ScottMyers almost, simply reverse the `Checked` property and write it back: `Checkbox_control.Checked = !Checkbox_control.Checked;` I added it into my post – Mong Zhu Aug 11 '17 at 15:53
  • Okay it looks like that's working but there's a strange behavior. The UI only updates the status of the checkbox if I hover over it. For it to then update again I need to move my mouse off the checkbox and then move it back on. For clarity, if I rapidly move my mouse on and off the checkbox (without clicking), then I can see the box check and uncheck. However, if I do not do this then I cannot see the UI updating. Any ideas for why that might be? If this is out of the scope of this question I can make a new one – Scott Myers Aug 11 '17 at 16:00
  • @ScottMyers my fault. You need to call `Invoke` or `BeginInvoke` because the timer event arrives on a different thread. See my updated answer – Mong Zhu Aug 11 '17 at 16:01
  • That's perfect! Thank you so much – Scott Myers Aug 11 '17 at 16:03
  • @ScottMyers no problem. Timers are perfect for such stuff. – Mong Zhu Aug 11 '17 at 16:04
  • @ScottMyers as a comment on your code: The while loop is executed on the main thread and is called busy waiting. This is why it blocks your GUI. The Method `Delay` doen't wait actually. It simply returns a `Task`, and sets up a new timer each time, with which you populate the memory. – Mong Zhu Aug 11 '17 at 16:07