Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to wrap specific classes or methods and assign them to a thread?

I have a XAML form that I would like two independent features threaded out of the main XAML execution thread: 1.) a timer control that ticks up, and 2.) implement a pause button so I can freeze a set of procedural set of activities and clicking on the pause button again will resume.

When I start the form, the entire app freezes. Because of this I can't interact with btnPause control. I got the timer class to work, but it (lblTimer) updates in chunks, or whenver it looks like the CPU isn't busy on the main thread.

I tried to create a class "Task" that wraps a class or method in its own thread so I can control.

    Automation.Task AutomationThread = new Automation.Task();
    Automation.Task TimerThread = new Automation.Task();

Later on, I attempted to create a stopwatch class and assign the TimerThread to it so I can manage it independently.

    Automation.WatchTimer stopwatch = new Automation.WatchTimer(lblTimer, TimerThread);


class Task
{
    private ManualResetEvent _shutdownFlag = new ManualResetEvent(false);
    private ManualResetEvent _pauseFlag = new ManualResetEvent(true);

    Thread _thread;

    public Task() { }

    public void Start()
    {
        _thread = new Thread(DoWork);
        _thread.Start();
    }

    public void Resume()
    {
        _pauseFlag.Set();
    }

    public void Stop()
    {
        _shutdownFlag.Set();
        _pauseFlag.Set();
        _thread.Join();
    }

    public void DoWork()
    {
        do
        {
            _pauseFlag.WaitOne(Timeout.Infinite);
        }
        while (!_shutdownFlag.WaitOne(0));
    }

    // I AM NOT SURE IF THIS IS THE RIGHT APPROACH
    public void DoWork(Func<void> method????)
    {
        do
        {
            // NOT SURE WHAT TO PUT HERE
            // This is where I want it to do a method 
            // that wraps a long chain of procedural items
            // where I can pause (block) and unpause through the UI
        }
        while (!_shutdownFlag.WaitOne(0));
    }

class WatchTimer
{
    public WatchTimer(System.Windows.Controls.Label lbl, Automation.Task worker)
    {
        lblField = lbl;
        worker.Start();
    }

    private System.Windows.Controls.Label lblField;

    Timer time = new Timer();
    Stopwatch sw = new Stopwatch();

    public void Start()
    {
        time.Start();
        sw.Start();
        time.Tick += new EventHandler(time_Tick);
    }

    public void Stop()
    {
        time.Stop();
        sw.Stop();
    }

    public void Reset()
    {
        sw.Reset();
        lblField.Content = this.elapsedTime();
    }

    public string elapsedTime()
    {
        TimeSpan ts = sw.Elapsed;
        // return formatted TimeSpan value
        return String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
            ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds);
    }

    private void time_Tick(object sender, EventArgs e)
    {
        lblField.Content = this.elapsedTime();
    }

}

The timer appears to work, but it still spits updates in chunks - does this mean it's not on its own thread?

like image 473
Wibble Avatar asked Nov 15 '22 03:11

Wibble


1 Answers

You are most likely crashing because you are updating a Windows control when you are not on the UI thread. The easiest way to accomplish updating the label control is to use System.Windows.Forms.Timer not the System.Threading.Timer. The aforementioned SWF Timer can be setup to fire every x milliseconds and the event handler is guaranteed to be run on the UI thread!

like image 73
Richard Schneider Avatar answered Dec 15 '22 05:12

Richard Schneider