Dispatcher.BeginInvoke 从不执行操作?

Dispatcher.BeginInvoke never execute action?

我有我的操作从未执行过的代码:

private static Timer timer = new Timer(TimerCallback, null, 5000, 5000);
private static DispatcherOperation dispatcherOperationPrevious = null;
private static void TimerCallback(object state)
{
    DispatcherOperation dispatcherOperation = 
        Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() =>
    {
        Debug.Print("Pass here at: " + DateTime.Now.ToString("O"));
    }));

    dispatcherOperationPrevious = dispatcherOperation;
}

我没有关于 "Pass here..." 的调试痕迹。

如果我查看 BeginInvoke 的结果,即 dispatcherOperation,我得到(当前或先前的 dispatcherOperation):

dispatcherOperation.Status = Pending
dispatcherOperation.Task.Status = WaitingForActivation

_dispatcherOperationPrevious .Status = Pending
_dispatcherOperationPrevious .Task.Status = WaitingForActivation

为什么 "Debug.Print..." 永远不会执行?

这是因为在另一个线程上调用了 TimeCallback。当您在没有 Dispatcher 的线程上调用 Dispatcher.CurrentDispatcher 时,它将创建一个新的。 (Dispatcher 绑定到线程。)

因此,您正在创建一个新的调度程序,但这个新的调度程序永远不会 Run() 并且您的 Action 将在非 运行 调度程序上排队。

我想你想调用 GUI 调度程序上的操作。

每个 WPF 控件都是从 DispatcherObject 派生的,并且将包含一个 属性 Dispatcher,其中包含创建它们的调度程序。用那个。

所以Dispatcher.Invoke可以解释为静态方法调用,但实际上是控件中存储的Dispatcher实例的方法调用属性Dispatcher.

修复:

private static Timer timer = new Timer(TimerCallback, null, 5000, 5000);
private static DispatcherOperation dispatcherOperationPrevious = null;
private static void TimerCallback(object state)
{
    DispatcherOperation dispatcherOperation = 

    // Dispatcher here is using the controls dispatcher, the BeginInvoke is not a static method.. (like you probably assumed..
    // So calling the BeginInvoke of the controls property 'Dispatcher'
    Dispatcher.BeginInvoke(new Action(() =>
    {
        Debug.Print("Pass here at: " + DateTime.Now.ToString("O"));
    }));

    dispatcherOperationPrevious = dispatcherOperation;
}

如果 Dispatcher 属性 在 TimeCallback 中不可用,例如,如果您在业务层 类 深处的某个 类 中创建时间 (不良做法),你可以调用Application.Current.Dispatcher获取'main/gui' Dispatcher。

如本 post 所述,Dispatcher.CurrentDispatcher 将从当前线程获取 Dispatcher,在您的例子中,是 Timer 的线程。如果您想从 GUI 线程调用调试调用,则需要改用 Application.CurrentDispatcher

private static void TimerCallback(object state)
{
    DispatcherOperation dispatcherOperation = 
        Application.CurrentDispatcher.BeginInvoke(new Action(() =>
    {
        Debug.Print("Pass here at: " + DateTime.Now.ToString("O"));
    }));

    dispatcherOperationPrevious = dispatcherOperation;
}

不过,我不使用标准 Timer,而是 推荐 使用 DispatcherTimerDispatcherTimer 旨在在更新 UI 时使用(无需显式调用)。

If a System.Timers.Timer is used in a WPF application, it is worth noting that the System.Timers.Timer runs on a different thread then the user interface (UI) thread. In order to access objects on the user interface (UI) thread, it is necessary to post the operation onto the Dispatcher of the user interface (UI) thread using Invoke or BeginInvoke. Reasons for using a DispatcherTimer opposed to a System.Timers.Timer are that the DispatcherTimer runs on the same thread as the Dispatcher and a DispatcherPriority can be set on the DispatcherTimer.