System.Threading Timer

时间:2012-04-16 15:04:41

标签: c# wpf timer

我在将DispatcherTimer语法转换为线程计时器时遇到问题。当我突然运行我的应用程序时,它会关闭而没有任何错误。

基本上我希望计时器每5秒执行2个方法。

编辑:这两种方法正在更新用户界面。 我试图摆脱DispatcherTimer,因为我必须在UI显示中冻结和延迟。

Dispatcher计时器代码:

timerW = new DispatcherTimer();
    timerW.Tick += new EventHandler(timerW_Tick);
    timerW.Interval = new TimeSpan(0, 0, 5000);
    timerW.Start();



 private void timerW_Tick(object sender, EventArgs e)
        {
            DisplayWegingInfo();
            CaculateTimen();
        }

System.Threading Timer的代码:

public void InitializeDispatcherTimerW()
    {
        TimerCallback callback = MyTimerCallBack;
        timerW = new Timer(callback);

        timerW.Change(0, 5000);
    }

    private void MyTimerCallBack(object state)
    {
        DisplayWegingInfo();
        CaculateTime();
    }

感谢。

5 个答案:

答案 0 :(得分:3)

最有可能的问题是您正在更新计时器回调中的方法中的UI。这只能从UI线程开始,而计时器在后台线程中运行。

我建议您坚持使用DispatcherTimer

另一种解决方案是将代码分解一下:将工作密集型代码解压缩到其他方法并在后台线程中运行,然后从UI线程更新UI。

这样的事情:

private void MyTimerCallBack(object state)
{
    LongCalculationsThatDontNeedTheUI();
    _dispatcherUIThread.Invoke(new Action(UpdateUI));
}

答案 1 :(得分:2)

根据名称DisplayWedgingInfo判断,我猜这个方法会更新UI吗? System.Threading.Timer在与UI线程不同的线程上执行,因此为了能够从该线程更新UI,您需要使用Dispatcher::[Begin]Invoke将这些调用封送回Dispatcher线程。

因此,您可以保留任何不会触及UI元素的昂贵工作,但对于UI操作,您只需执行以下操作:

string someValue = this.SomeExpensiveOperation();

this.Dispatcher.BeginInvoke(
    DispatcherPriority.Background,
    new Action(() => 
   { 
          this.myControl.Text = someValue; 
   }));

我应该指出,在调用确实发生时,可能会发生任何UI交互/呈现的中断。这是不可避免的,因为执行将在主线程上发生。通过使用DispatcherPriority.Background,您至少可以使用优先级来安排更新,该优先级使其低于用户当时可能提供的任何输入。但是,不要期望能够在没有任何惩罚的情况下对UI进行大规模更新。如果你需要这样做,最好排队多个Background优先级的调用,以便它们可以发生更高优先级的事情,如必要时输入。

答案 2 :(得分:0)

我认为您需要将数据检索/计算数据显示分开。

Daniel指出,任何GUI更新都需要在Dispatcher线程上完成,因此最简单的方法是使用DispatcherTimer

但是,使用DispatcherTimer表示计时器回调中的所有在GUI线程中完成。如果您有任何需要花费大量时间的操作,这并不好。如您所见,GUI会断断续续并锁定。

你需要找出花时间的东西。从你的其他问题我猜它是SQL检索。在这种情况下,您最好在单独的线程上进行实际的检索(使用System.Threading.Timer),一旦获得结果,请使用更新显示 Dispatcher.BeginInvoke()编组到GUI线程。

答案 3 :(得分:0)

我会检查两件事: 1.正如其他人所说,确保如果您正在更新UI,那么您正在调用回调度程序 - 您只能从UI线程更新UI。即使您正在使用数据绑定 - 如果计时器线程更新了数据绑定到UI的值,那么“计数”为触摸UI的错误线程。

  1. 始终使用try..catch块保护您的定时器回调。 .Net未处理异常的默认行为是终止进程。我已经看到很多“刚刚退出”,真正的罪魁祸首是在计时器线程或工作线程上没有异常处理。 (实际上,如果你试图从错误的线程操作UI,WPF应该抛出一个异常,所以可能是你得到了异常,然后程序终止,因为没有处理程序)

答案 4 :(得分:-3)

为什么不简单地使用后台线程来分派事件?

  CancellationTokenSource cts = new CancellationTokenSource();
  Task.Factory.StartNew(() =>
     {
          while(!cts.IsCancellationRequested)
          {
               Thread.Sleep(5000);

               this.Dispatcher.BeginInvoke(new Action(() =>
                  {
                       DisplayWegingInfo();
                       CalculateTimen();
                  }), null);
          }
     });