我的代码从未执行过我的操作:
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;
}
我没有调试痕迹"通过这里......"。
如果我查看BeginInvoke的结果是dispatcherOperation,我得到(对于当前或以前的dispatcherOperation):
dispatcherOperation.Status = Pending
dispatcherOperation.Task.Status = WaitingForActivation
_dispatcherOperationPrevious .Status = Pending
_dispatcherOperationPrevious .Task.Status = WaitingForActivation
为什么" Debug.Print ......"永远不会被执行?
答案 0 :(得分:1)
这是因为在另一个线程上调用了TimeCallback。当您在没有Dispatcher的线程上调用Dispatcher.CurrentDispatcher时,它将创建一个新的Dispatcher .CurrentDispatcher。 (Dispatcher绑定到一个线程。)
所以,你正在创建一个新的调度程序,但是这个新的调度程序永远不会Run()
,你的Action将在非运行的调度程序上排队。
我想你想在GUI调度程序上调用Action。
每个WPF控件都来自DispatcherObject
,并且将包含一个属性Dispatcher
,其中包含调度程序所在的位置。使用那个。
因此Dispatcher.Invoke
可以解释为静态方法调用,但它实际上是存储在controls属性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;
}
如果TimeCallback中的Dispatcher属性不可用,例如,如果您在业务层(不良做法)深处的某些类中创建了时间,则可以调用Application.Current.Dispatcher
得到'main / gui'调度员。
答案 1 :(得分:1)
正如此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
推荐,而不是使用标准DispatcherTimer
。 DispatcherTimer
旨在用于更新UI(无需显式调用)。
如果在WPF应用程序中使用System.Timers.Timer,则值得 注意到System.Timers.Timer在不同的线程上运行 用户界面(UI)线程。为了访问用户的对象 接口(UI)线程,有必要将操作发布到 使用Invoke或用户界面(UI)线程的调度程序 BeginInvoke的。使用DispatcherTimer的原因与 System.Timers.Timer是DispatcherTimer在同一个上运行的 线程作为Dispatcher和DispatcherPriority可以在上面设置 DispatcherTimer。