【问题标题】:How to allow messages while inside cycle如何在循环内允许消息
【发布时间】:2014-01-09 10:23:54
【问题描述】:

我编写模拟寻路算法的应用程序。我可以运行算法或单步执行(如调试)。但是当我运行算法时,在算法完成之前我无法绘制任何更改。

private void menu_run_Click(object sender, EventArgs e)
{
    algorithm.Reset();
    while (algorithm.status == Algorithm.Status.Searching )
    {
        algorithm.MakeStep();
        if (this.speed != 0) System.Threading.Thread.Sleep(this.speed);

        drawing_area.Invalidate();
    }
}

我猜是因为我在一个周期内完成所有操作,系统无法处理我触发的新消息(事件)。

那么我应该如何更改我的代码才能在每次迭代后重新绘制更改?

  1. 我是否应该以某种方式调用 Message Dispatcher 让他在每次迭代后处理新消息?
  2. 我应该创建自己的消息并使用消息在循环内完成所有工作吗?
  3. 或者我还有什么更优雅的方式吗?

【问题讨论】:

  • 作为一个快速回答,Application.DoEvents 运行消息队列处理,因此它可能是您想要的。在Invalidate 之后调用它,它应该处理重绘绘图区域。不过,Timer 组件可能会更有用。

标签: c# events message-queue


【解决方案1】:

有很多不同的方法可以做到这一点。

对于您的情况,可以说最简单的方法是在表单上使用 System.Windows.Forms.Timer 对象,而不是在无限循环中调用 Sleep()。

  1. 从工具箱中将计时器添加到您的表单中。
  2. 将其Interval 属性设置为this.speed。
  3. 将其Enabled 属性设置为true。
  4. 订阅计时器的Tick 事件。

处理程序看起来像这样:

private void OnTimerTick(object sender, EventArgs e)
{
    if (algorithm.Status == Algorithm.Status.Searching)
    {
        algorithm.MakeStep();
        drawing_area.Invalidate();
    }
}

您可能需要稍微重新安排您的控制逻辑(算法开始和停止的位置)。如果有帮助,您可以使用计时器的 Enabled 属性。

另一种解决方案是创建一个带有后台线程的对象,该线程在算法运行时引发周期性事件,并且表单将订阅这些事件并相应地重绘(不要忘记在事件上使用Invoke,因为它们'将来自非 GUI 线程)。

还有BackgroundWorker,您可以将其作为第三种选择。但我认为计时器对你来说是最简单的。

【讨论】:

    猜你喜欢
    • 2017-05-13
    • 2021-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多