4

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

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

编辑:这两种方法正在更新 UI。 我正在尝试摆脱 DispatcherTimer,因为我必须在 UI 显示中出现很多冻结和延迟。

调度程序计时器代码:

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 计时器的代码:

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

        timerW.Change(0, 5000);
    }

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

谢谢。

4

5 回答 5

3

问题很可能是您在计时器回调的方法中更新 UI。这只能通过 UI 线程实现,并且计时器在后台线程中运行。

我建议你坚持使用DispatcherTimer.

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

像这样的东西:

private void MyTimerCallBack(object state)
{
    LongCalculationsThatDontNeedTheUI();
    _dispatcherUIThread.Invoke(new Action(UpdateUI));
}
于 2012-04-16T15:07:38.760 回答
2

从 DisplayWedgingInfo 的名称来看,我猜这个方法会更新 UI?System.Threading.Timer 在不同于 UI 线程的线程上执行,因此为了能够从该线程更新 UI,您需要Dispatcher使用Dispatcher::[Begin]Invoke.

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

string someValue = this.SomeExpensiveOperation();

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

我应该指出,当调用确实发生时,任何可能正在进行的 UI 交互/渲染都会出现一些中断。这是不可避免的,因为执行将发生在主线程上。通过使用DispatcherPriority.Background您,至少安排更新的优先级使其低于用户当时可能提供的任何输入。但是,不要期望能够对 UI 进行大规模更新而不会受到任何惩罚。如果您需要这样做,最好将多个Background优先级调用排队,以便它们可以在必要时以更高优先级的东西发生,例如在两者之间输入。

于 2012-04-16T15:11:07.593 回答
0

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

  1. 始终使用 try..catch 块保护您的计时器回调。.Net 对于未处理异常的默认行为是终止进程。我见过很多“只是退出”,真正的罪魁祸首是计时器线程或工作线程上没有异常处理。(实际上,如果您尝试从错误的线程操作 UI,WPF 应该抛出异常,因此可能是您收到异常,然后程序因没有处理程序而终止)
于 2012-04-16T15:21:40.710 回答
0

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

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

但是,使用DispatcherTimer意味着计时器回调中的所有内容都在 GUI 线程中完成。如果您有任何需要花费大量时间的操作,这并不好。如您所见,GUI 会卡住并锁定。

你需要弄清楚什么是花时间。从你的另一个问题我猜它是 SQL 检索。在这种情况下,您最好在单独的线程上进行实际检索System.Threading.Timer(通过使用),一旦获得结果,通过使用to 编组到 GUI 线程来更新显示。Dispatcher.BeginInvoke()

于 2012-04-16T15:19:20.570 回答
-3

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

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

               this.Dispatcher.BeginInvoke(new Action(() =>
                  {
                       DisplayWegingInfo();
                       CalculateTimen();
                  }), null);
          }
     });
于 2012-04-16T15:09:24.827 回答