简体   繁体   English

Dispatcher Invoke(...)vs BeginInvoke(...)混淆

[英]Dispatcher Invoke(…) vs BeginInvoke(…) confusion

I'm confused why I can't make this test counter application work with 2 (or more) simultaneous running countertextboxes with the use of "BeginInvoke" on my Dispatcher in the Count() method. 我很困惑为什么我不能让这个测试计数器应用程序使用Count()方法在我的Dispatcher上使用“BeginInvoke”的2个(或更多个)同时运行的反文本框。

You can solve the issue by replacing the BeginInvoke by an Invoke. 您可以通过Invoke替换BeginInvoke来解决问题。 But this doesn't solve my confusion. 但这并不能解决我的困惑。

Here's the sample code I'm talking about: 这是我正在谈论的示例代码:

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

When you use Dispatcher.BeginInvoke it means that it schedules the given action for execution in the UI thread at a later point in time, and then returns control to allow the current thread to continue executing. 当您使用Dispatcher.BeginInvoke它意味着它会在稍后的某个时间点调度给定的操作以在UI线程中执行,然后返回控制以允许当前线程继续执行。 Invoke blocks the caller until the scheduled action finishes. Invoke阻止调用者,直到计划的操作完成。

When you use BeginInvoke your loop is going to run super fast since BeginInvoke returns right away. 当您使用BeginInvoke你的循环会因为运行超快 BeginInvoke立即返回。 This means that you're adding lot and lots of actions to the message queue. 这意味着你要添加很多大量的行动,以消息队列。 You're adding them much faster than they can actually be processed. 您添加它们速度比实际处理速度快得多。 This means that there's a long time between when you schedule a message and when it actually gets a chance to be run. 这意味着从您安排消息到实际有机会运行之间需要很长时间。

The actual action that you're running uses the field _number . 您正在运行的实际操作使用字段_number But _number is being modified by the other thread very quickly and while the action is in the queue . 但是_number正在被另一个线程非常快速地修改, 而动作在队列中 This means that it won't display the value of _number at the time you scheduled the action, but rather what it is after it has been continuing on in it's very tight loop. 这意味着它不会在您安排操作时显示_number的值,而是在它继续进行非常紧密的循环之后显示它的值。

If you use Dispatcher.Invoke instead then it prevents the loop from "getting ahead of itself" and having multiple scheduled events, which ensures that the value that it's writing is always the "current" value. 如果你使用Dispatcher.Invoke那么它会阻止循环“超越自身”并拥有多个预定事件,这可以确保它所写的值始终是“当前”值。 Additionally, by forcing each iteration of the loop to wait for the message to be run it makes the loop a lot less "tight", so it can't run as quickly in general. 此外,通过强制循环的每次迭代等待消息运行,它使循环不那么“紧”,因此它通常不能快速运行。

If you want to use BeginInvoke the first thing you really need to do is slow down your loop. 如果你想使用BeginInvoke ,你真正需要做的第一件事就是减慢循环速度。 If you want it to update the text every second, or ever 10ms, or whatever, then you can use Thread.Sleep to wait the appropriate amount of time. 如果您希望它每秒更新文本,或者每隔10毫秒,或者其他任何内容,那么您可以使用Thread.Sleep等待适当的时间。

Next, you need to take a copy of _number before passing it to the Dispatcher so that it displays the value at the time you scheduled it, not at the time it is executed: 接下来,您需要_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();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM