locked
Dispatcher Thread Start Stop Cancel RRS feed

  • Question

  • My Start Stop/Cancel button does not respond.

    Here is my StartStop button action. ProcessMaster loops on bWait, as long as bContinue is true, checking if bWait is true and incrementing the next check time, posting messages to my label on DispatcherPriority.Normal.

           private void StartStop_Process(object sender, RoutedEventArgs e)
            {
                ThreadStart startProcess = delegate()
                {
                    DispatcherOperation dop = Dispatcher.BeginInvoke(
                        DispatcherPriority.Background,
                        new Action<bool>(ProcessMaster), bContinue);
                    DispatcherOperationStatus dopStatus = new DispatcherOperationStatus();
                    dopStatus = dop.Status;
                    while (dopStatus != DispatcherOperationStatus.Completed)
                    {
                        dopStatus = dop.Wait(TimeSpan.FromMilliseconds((double)gsSRValue - 2));
                        if (dopStatus == DispatcherOperationStatus.Aborted)
                        {
                            Dispatcher.Invoke(DispatcherPriority.Normal,
                                new Action<string>(RefreshStatus), "Process Canceled");
                        }
                    }
                };
                if ((string)btnProcess.Content == "Cancel")
                {
                    bContinue = false;
                    RefreshStatus("Click to begin Processing", 0);
                    btnProcess.Content = "Start";
                    btnProcess.Refresh();
                    startProcess.EndInvoke(null);
                }
                if ((string)btnProcess.Content == "Start")
                {
                    InitializeApp();
                }
                if (bContinue == true)
                {
                    btnProcess.Content = "Cancel";
                    btnProcess.Refresh();
                    new Thread(startProcess).Start();
                }            
            }
    Any hints or clues as to how to make active the start stop button are welcome...

    JeffP...

    Tuesday, March 20, 2012 5:29 PM

Answers

  • Jeff;

       The new Task class is really cool, to start a new thread just do something like this:

    Task t = Task.Factory.StartNew(() => { //all this stuff executes in another thread

    t.ContinueWith( // a continuation which allows you to order aysnchronous tasks...); });

    I then always use event to post data back and use Dispatcher.Invoke(....) to get data onto GUI thread!  CancellationTokens are supported as well.  Plus..... Tasks have no processor affinty which means you will get the max CPU utilization possible.  If you have 5 processors and 5 different tasks they run in parrallel!!!!

     


    JP Cowboy Coders Unite!

    • Marked as answer by JeffPGMT Tuesday, March 20, 2012 11:38 PM
    Tuesday, March 20, 2012 7:22 PM

All replies

  • I made a few changes with the same results, my UI is un-responsive...

    I added an overload method ProcessMaster() that returns ThreadStart. I tried a Stop button, but that too failed.

    private void StartStop_Process(object sender, RoutedEventArgs e) { if ((string)btnProcess.Content == "Cancel") { bContinue = false; RefreshStatus("Click to begin Processing", 0); btnProcess.Content = "Start"; btnProcess.Refresh(); startProcess.EndInvoke(null); } if ((string)btnProcess.Content == "Start") { InitializeApp(); } if (bContinue == true) { btnProcess.Content = "Cancel"; btnProcess.Refresh(); new ThreadStart(startProcess).BeginInvoke(null, null); } } private ThreadStart ProcessMaster() { ThreadStart myThread = delegate() { DispatcherOperation dop = Dispatcher.BeginInvoke( DispatcherPriority.Background, new Action<bool>(ProcessMaster), bContinue); DispatcherOperationStatus dopStatus = new DispatcherOperationStatus(); dopStatus = dop.Status; while (dopStatus != DispatcherOperationStatus.Completed) { dopStatus = dop.Wait(TimeSpan.FromMilliseconds((double)gsSRValue * 2)); if (dopStatus == DispatcherOperationStatus.Aborted) { Dispatcher.Invoke(DispatcherPriority.Normal, new Action<string>(RefreshStatus), "Process Canceled"); } } }; return myThread; } private void ProcessMaster(bool bContinue) { string tmpMsg = string.Empty; while (bContinue == true) { DateTime dLast; DateTime dNextTmp; bWait = ProcessNext(dLog, out dNextTmp); dLast = dNextTmp; while (!bWait == true & bContinue == true) { tmpMsg = "Next Send/Receive: " + dNextTmp.ToString(); Dispatcher.Invoke(DispatcherPriority.Normal, new Action<string>(RefreshStatus), tmpMsg); emailAddress = null; QueueCheck(); if (emailAddress != null & emailAddress != "") { tmpMsg = "Send/Receive: " + emailAddress + ", at:" + dNextTmp.ToString(); Dispatcher.Invoke(DispatcherPriority.Normal, new Action<string>(RefreshStatus), tmpMsg); int iRes = SendReceive(); if (iRes == 1) { dLast = dLast.AddSeconds((double)gsSRValue); tmpMsg = "Sent: " + emailAddress + ", Sucess! at:" + dLast.ToString(); Dispatcher.Invoke(DispatcherPriority.Normal, new Action<string>(RefreshStatus), tmpMsg); } } dNextTmp = new DateTime(); bWait = ProcessNext(dLast.AddSeconds(2), out dNextTmp); dLast = dNextTmp; tmpMsg = "Next Send/Receive: " + dNextTmp.ToString(); Dispatcher.Invoke(DispatcherPriority.Normal, new Action<string>(RefreshStatus), tmpMsg); } } if (bContinue == false) { tmpMsg = "Cancel Processing"; Dispatcher.Invoke(DispatcherPriority.Normal, new Action<string>(RefreshStatus), tmpMsg); } }

    fjslfs
    Debugging, I'm able to step through the ProcessMaster(bContinue) and it checks the Queue, waits and updates the lablel.

            private void ProcessMaster(bool bContinue)
            {
                string tmpMsg = string.Empty;
                while (bContinue == true)
                {
                    DateTime dLast;
                    DateTime dNextTmp;                
                    bWait = ProcessNext(dLog, out dNextTmp);
                    dLast = dNextTmp;                
                    while (!bWait == true & bContinue == true)
                    {
                        tmpMsg = "Next Send/Receive: " + dNextTmp.ToString();
                        Dispatcher.Invoke(DispatcherPriority.Normal,
                                new Action<string>(RefreshStatus), tmpMsg);
                        emailAddress = null;
                        QueueCheck();
                        if (emailAddress != null & emailAddress != "")
                        {
                            tmpMsg = "Send/Receive: " + emailAddress + ", at:" + dNextTmp.ToString();
                            Dispatcher.Invoke(DispatcherPriority.Normal,
                                    new Action<string>(RefreshStatus), tmpMsg);
                            int iRes = SendReceive();
                            if (iRes == 1)
                            {
                                dLast = dLast.AddSeconds((double)gsSRValue);
                                tmpMsg = "Sent: " + emailAddress + ", Sucess! at:" + dLast.ToString();                            
                                Dispatcher.Invoke(DispatcherPriority.Normal,
                                    new Action<string>(RefreshStatus), tmpMsg);
                            }
                        }
                        dNextTmp = new DateTime();                    
                        bWait = ProcessNext(dLast.AddSeconds(2), out dNextTmp);
                        dLast = dNextTmp;
                        tmpMsg = "Next Send/Receive: " + dNextTmp.ToString();
                        Dispatcher.Invoke(DispatcherPriority.Normal,
                            new Action<string>(RefreshStatus), tmpMsg);
                    }
                }
                if (bContinue == false)
                {
                    tmpMsg = "Cancel Processing";
                    Dispatcher.Invoke(DispatcherPriority.Normal,
                        new Action<string>(RefreshStatus), tmpMsg);
                }
            }


    JeffP...

    Tuesday, March 20, 2012 6:59 PM
  • Jeff;

       The new Task class is really cool, to start a new thread just do something like this:

    Task t = Task.Factory.StartNew(() => { //all this stuff executes in another thread

    t.ContinueWith( // a continuation which allows you to order aysnchronous tasks...); });

    I then always use event to post data back and use Dispatcher.Invoke(....) to get data onto GUI thread!  CancellationTokens are supported as well.  Plus..... Tasks have no processor affinty which means you will get the max CPU utilization possible.  If you have 5 processors and 5 different tasks they run in parrallel!!!!

     


    JP Cowboy Coders Unite!

    • Marked as answer by JeffPGMT Tuesday, March 20, 2012 11:38 PM
    Tuesday, March 20, 2012 7:22 PM
  • If you want something even cooler look into Reactive Extensions which alter this design from a PULL based to a PUSH based architecture.

    JP Cowboy Coders Unite!

    Tuesday, March 20, 2012 7:24 PM
  • Tuesday, March 20, 2012 7:39 PM
  • After trying, Thread, ThreadStart & Dispatcher w/varying degrees of success, I was not confident that Task.Factory would lead to a solution...

            bool bContinue { get; set; }
            bool bWait { get; set; }
            CancellationTokenSource TaskToken { get; set; }
          private void StartStop_Process(object sender, RoutedEventArgs e)
            {
                if ((string)btnProcess.Content == "Start")
                {
                    //btnProcess.Content = "Wait";
                    //btnProcess.Refresh();
                    btnContent(btnProcess, "Wait");
                    InitializeApp();
                }
                if ((string)btnProcess.Content == "Cancel")
                {                
                    btnProcess.Refresh();
                    TaskToken.Cancel();
                    bContinue = false;
                    //btnProcess.Content = "Start";
                    btnContent(btnProcess, "Start");                
                    sProcessMsg = "Click to begin Processing";
                    Dispatcher.Invoke(DispatcherPriority.Render,
                        new Action<string>(RefreshStatus), sProcessMsg);                                
                }
                if (bContinue == true)
                {                
                    btnContent(btnProcess, "Cancel");
                    TaskToken = new CancellationTokenSource();
                    var taskproc = Task.Factory.StartNew(() =>
                    {
                        ProcessMaster(bContinue);
                    }, TaskToken.Token);                
                }            
            }
            private void btnContent(Button bt, string sc)
            {
                bt.Content = sc;
                bt.Refresh();        
            }

    ...and...

       public void RefreshStatus(string sMsg, int iTSInt)
            {
                lblProcessMsg.Content = sMsg;
                lblProcessMsg.Refresh();
                if (iTSInt != 0) { Thread.Sleep(iTSInt); }
                else { Thread.Sleep(500); }
            }
            public void RefreshStatus(string sMsg)
            {
                RefreshStatus(sMsg, 0);
            }
            // located just outside of my main class
            public static class ExtensionMethods
            {
                private static Action EmptyDelegate = delegate() { };
                public static void Refresh(this UIElement uiElement)
                {
                    uiElement.Dispatcher.Invoke(DispatcherPriority.Render, EmptyDelegate);
                }
            }

    A few links that helped me...
     Task Parallelism (Task Parallel Library)
     http://msdn.microsoft.com/en-us/library/dd537609.aspx

    Parallel Programming: Task Cancellation
    http://blogs.msdn.com/b/csharpfaq/archive/2010/07/19/parallel-programming-task-cancellation.aspx

    And last but not least, THANKS TO YOU... Sir "Mr. Javaman II", thanks

    JeffP...


    JeffP...


    • Edited by JeffPGMT Tuesday, March 20, 2012 11:48 PM
    Tuesday, March 20, 2012 11:47 PM