【问题标题】:UI button running on separate thread?UI按钮在单独的线程上运行?
【发布时间】:2015-10-22 13:28:32
【问题描述】:

我的问题如下:

1.我有一个密集的方法可以在一个while循环中更新GUI元素(图表)

2.当按下按钮时,我需要跳出这个循环。

3.问题是按钮事件处理程序在while循环完成之前不会被执行。

4.我尝试在单独的线程上运行该方法,但这很成问题,因为它设置和读取许多 UI 元素,我几乎无法让它工作,所以我希望有一种方法在单独的线程上运行停止按钮并更新一个全局变量,让我跳出循环。

知道如何实现吗?

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

【问题讨论】:

  • 如果您可以显示当前代码的相关部分,那将很有帮助。

标签: c# user-interface button interrupt


【解决方案1】:

在您的 while 循环中,您可以调用 Application.DoEvents()。它将从事件队列中获取 UI 事件,并处理这些事件。然后,您的按钮事件将被处理。

您可以通过关键字Application.DoEvents()C# 进行搜索。有很多关于它的话题。

更新:

在您的代码中,它是一个无限的 while 循环。我不喜欢在主线程中运行无限。我更喜欢在worker-thread 中运行它。并发送消息以在主线程中进行UI 更新。一般UI事件需要在主线程中处理。

如果无限 while 循环已经在 worker-thread 中,它应该在每个循环中休眠大约 5~10 毫秒,以便释放 CPU 资源来处理其他线程中的一些事件。

【讨论】:

  • 这正是我所需要的。谢谢!
  • 我不知道该怎么做(向 UI 部分发送消息)。如果您有时间可以给我一个简短的例子吗?
  • 正如@GEEF 所说,或参考this link。您可以在另一个线程中调用 Dispatcher.BeginInvoke() 来更新 UI(在主线程中运行)。 Or this MSDN document.
  • Toro,@GEEF,我觉得这有点过头了,我之前尝试过使用 invoke 但我从来没有让它正常工作。这些链接对初学者不太友好,并且它们不显示如何从控件中读取。
  • 希望this MSDN link 可以提供帮助。 This SO thread is similar to that MSDN。关于worker thread的话题很多,你可以google一下。我在编码MFC applications 时学会了它。它的概念在不同的编程语言下很有用且相似。
【解决方案2】:

您应该考虑将您的 UI 元素(图表)数据绑定到 DependencyProperty。这允许您在非 UI 线程上运行密集方法,从而允许您的 UI 线程响应按钮单击。在后台线程中,只需调用 Dispatcher.BeginInvoke() 来更新您的 DependencyProperty(因为它只能从 UI 线程更新),这将更新您绑定到它的控件。

就您的按钮中断而言,一个简单的解决方案是从您的 UI 中设置一个标志,该标志会在每次循环迭代中检查。一个更复杂的解决方案是在任务Task 中运行这个密集的方法,给它CancellationTokenSource,然后在单击按钮时取消源。

【讨论】:

  • 方法的密集性来自于它正在更新一个包含数千个数据点的图表,这些数据点已经通过不同的方法计算,并且图表在这个while循环中更新了数百次。所以几乎没有工作可以转移到不同的线程
  • DependencyProperty 方法并不意味着卸载到另一个线程。这只是意味着让您提到的线程(或 for 循环或其他任何可能)更新 DependencyProperty,并将您的图表数据绑定到该 DependencyProperty。与在后面的代码中手动更新图表相比,这是更常见的 WPF 做法。
猜你喜欢
  • 1970-01-01
  • 2019-03-09
  • 1970-01-01
  • 2012-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多