我感到困惑,为什么不能在Count()方法中在我的Dispatcher上使用“BeginInvoke”使此测试计数器应用程序不能同时运行2个(或更多)计数器文本框。

您可以通过将Invoke替换为BeginInvoke来解决此问题。但这并不能解决我的困惑。

这是我正在谈论的示例代码:

public class CounterTextBox : TextBox
{
    private int _number;

    public void Start()
    {
        (new Action(Count)).BeginInvoke(null, null);
    }

    private void Count()
    {
        while (true)
        {
            if (_number++ > 10000) _number = 0;
            this.Dispatcher.BeginInvoke(new Action(UpdateText), System.Windows.Threading.DispatcherPriority.Background, null);
        }
    }

    private void UpdateText()
    {
        this.Text = "" + _number;
    }
}

最佳答案

当您使用Dispatcher.BeginInvoke时,它意味着它计划给定的操作在以后的某个时间点在UI线程中执行,然后返回控制权以允许当前线程继续执行。 Invoke阻止调用者,直到计划的操作完成。

当您使用BeginInvoke时,由于BeginInvoke立即返回,因此您的循环将快速运行和 super 。这意味着您要向消息队列添加很多 Action 。您添加它们的速度比实际处理速度快得多。这意味着从安排消息到实际有机会运行之间有一段很长的时间。

您正在运行的实际操作使用字段_number。但是,在操作处于队列中时,另一个线程很快地修改了_number。这意味着在您计划操作时,它不会显示_number的值,而是在紧密循环中继续显示之后的值。

如果改用Dispatcher.Invoke,则它可以防止循环“超前”并具有多个计划的事件,从而确保其写入的值始终为“当前”值。另外,通过强制循环的每次迭代等待消息运行,它使循环“紧缩”了很多,因此一般来说运行速度不会如此之快。

如果要使用BeginInvoke,您真正需要做的第一件事就是减慢循环速度。如果您希望它每秒更新一次文本,或者每10ms更新一次,则可以使用Thread.Sleep等待适当的时间。

接下来,您需要先复制一份_number,然后再将其传递给Dispatcher,以便它在您计划时显示值,而不是在执行时显示值:

while (true)
{
    if (_number++ > 10000)
        _number = 0;
    int copy = _number;
    this.Dispatcher.BeginInvoke(new Action(() => UpdateText(copy))
        , System.Windows.Threading.DispatcherPriority.Background, null);
    Thread.Sleep(200);
}
private void UpdateText(int number)
{
    this.Text = number.ToString();
}

关于c# - Dispatcher Invoke(…)vs BeginInvoke(…)的困惑,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/19009174/

10-11 22:24