2

my issue is the following:

1.I have an intensive method which updates GUI element (chart) in a while loop

2.I need to break out of this loop when a button is pressed.

3.Problem is the button event handler doesn't get executed until the while loop is finished.

4.I've tried running the method on separate thread but that is very problematic since it sets and reads many UI elements, pretty much I couldn't get that to work, so I'm hoping of there being a way to run just the stop button on a separate thread and update a global variable which let's me break out of the loop.

Any Idea how that can be accomplished?

private void playBack(int playTime, int runUntil)
        {
            var frameTime = new DateTime(); var frameTime_ = new DateTime();

            bool fwd = true;
            if (runUntil < playTime) fwd = false;

            playTime = trPlay.Value;

            playGoStop = true;

            lbPlayTime.Text = (playTime * numDtStepSize.Value).ToString();

            while (true) //trPlay.Maximum + 1)
            {
                frameTime = DateTime.UtcNow;
                if ((frameTime - frameTime_).TotalMilliseconds > (double)(1000 / numFps.Value))
                {
                    systemUpdate(playTime);
                    trPlay.Value = playTime;
                    trPlay.Update();

                    lbPlayTime.Update();


                    frameTime_ = frameTime;
                    if (fwd)
                    {
                        playTime++;
                        if (playTime > runUntil) break;
                    }
                    else
                    {
                        playTime--;
                        if (playTime < runUntil) break;
                    }
                }
                if (!playGoStop) break;
            }
        }
Jesse Myers
  • 69
  • 1
  • 8

2 Answers2

1

In your while loop, you can call Application.DoEvents(). It will fetch UI events from event queue, and process those events. Then, your button events will be processed.

You can search by the keyword Application.DoEvents() and C#. There are many topics about it.

UPDATE:

In your codes, it is a infinite while loop inside. I don't like to run a infinite in main thread. I will prefer to run it in a worker-thread. And send message to do UI updates in main-thread. Generally, UI events needs to be processed in the main-thread.

If the infinite while loop is already in the worker-thread, it should sleep about 5~10 ms per loop, in order to free CPU resources to process some events in the other threads.

AechoLiu
  • 17,522
  • 9
  • 100
  • 118
  • This was exactly what I needed. Thank You! – Jesse Myers Jul 31 '15 at 01:15
  • I have no idea how to do that (the sending messages to the UI part). Would you give me a short example if you have a minute to spare? – Jesse Myers Jul 31 '15 at 01:22
  • As @GEEF said, or refer [this link](http://stackoverflow.com/a/1136406/419348). You can call `Dispatcher.BeginInvoke()` in another thread do update UI (which runs in the main thread). [Or this MSDN document.](https://msdn.microsoft.com/en-us/library/cc190259(v=vs.95).aspx) – AechoLiu Jul 31 '15 at 01:31
  • Toro, @GEEF, I think this is a little over my head at the moment, I'v tried to use invoke before but I've never gotten it to work properly. Those links are not very beginner friendly, and they don show how to read from a control. – Jesse Myers Jul 31 '15 at 01:52
  • Hope [this MSDN link](https://goo.gl/Oa5OaI) could help. [This SO thread is similar to that MSDN](http://stackoverflow.com/a/17123286/419348). There are many topics about `worker thread`, you can google it. I learned it when I coding `MFC applications`. Its concept is useful and similar under different programming languages. – AechoLiu Jul 31 '15 at 07:53
  • `Invoke` or `BeginInvoke()` are some ways to **execute methods in the main-thread from another thread.** Different language will have different syntax to do such things. – AechoLiu Jul 31 '15 at 07:56
0

You should look at binding your UI element (chart) data to a DependencyProperty. This allows you to run the intensive method on a non-UI thread, allowing your UI thread to be responsive to button clicks. While on the background thread, simply make Dispatcher.BeginInvoke() calls to update your DependencyProperty (as it can only be updated from the UI thread) and this will update your control bound to it.

As far as your button interrupt goes, a simple solution is to set a flag from your UI which is checked within each loop iteration. A more complex solution would be to run this intensive method in a task Task, giving it CancellationTokenSource, then cancel the source upon button click.

GEEF
  • 1,175
  • 5
  • 17
  • the method intensiveness comes from the fact that it's updating a chart with several thousand data points which have already been computed by a different method, and the chart is updated several hundred times in this while loop. so there is pretty much no work to be off-sorced to a different thread – Jesse Myers Jul 31 '15 at 01:10
  • The DependencyProperty method doesn't mean offloading to another thread. It just means have your mentioned thread (or for loop or whatever it may be) update a DependencyProperty, and bind your Chart data to that DependencyProperty. This is more common WPF practice as compared to manually updating your Chart in code behind. – GEEF Jul 31 '15 at 01:13