简体   繁体   中英

System.Threading Timer

I am having problems converting my DispatcherTimer syntax to the Thread Timer. When i run my application suddenly it shuts down without any error.

Basically i want the timer to execute 2 methods every 5 seconds.

EDIT: The 2 methods are updating the UI. I am trying to attempt to get rid of the DispatcherTimer because i have to much freezes and delays in the UI display.

Dispatcher timer code:

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

Code for the System.Threading Timer:

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

        timerW.Change(0, 5000);
    }

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

Thanks.

The problem most likely is that you are updating your UI in the methods in your timer callback. This is only possible from the UI thread and the timer runs in a background thread.

I suggest you stick with the DispatcherTimer .

An alternate solution would be to split the code up a bit: Extract the work intensive code into other methods and run them in a background thread and update the UI afterwards from the UI thread.

Something like this:

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

Judging by the name DisplayWedgingInfo, I would guess this method updates the UI? System.Threading.Timer executes on a thread that is different than the UI thread, so to be able to update the UI from that thread you would need to marshal those calls back to the Dispatcher thread using Dispatcher::[Begin]Invoke .

So you can leave whatever expensive work that doesn't touch UI elements as is, but for the UI manipulation you would simply do:

string someValue = this.SomeExpensiveOperation();

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

I should point out that there will be some interruption to any UI interaction/rendering that might be going on when the invocation does occur. This is unavoidable as the execution will happen on the main thread. By using DispatcherPriority.Background you at least schedule the update with a priority that keeps it lower than any input that the user might be providing at the time. However, don't expect to be able to make a massive update to the UI without any penalty. If you need to do this it's best to queue up multiple invocations with Background priority so that they can happen with higher priority stuff like input in between if necessary.

I think you need to separate your data retrieval/calculation from your data display .

As Daniel points out, any GUI updating needs to be done on the Dispatcher thread, so the easiest way is to use DispatcherTimer .

However, using DispatcherTimer means that everything in your timer callback gets done in the GUI thread. This is not good if you have any operations that take an appreciable amount of time. The GUI will stutter and lock up as you have found.

You need to work out what is taking the time. From your other question I would guess that it is the SQL retrieval. In this case you would be better doing the actual retrieval on a separate thread (by using System.Threading.Timer ) and once you have the result, update the display by using Dispatcher.BeginInvoke() to marshal to the GUI thread.

I would check for 2 things: 1. As some others have said, make sure that if you are updating the UI, that you are Invoking back to the dispatcher -- you can only update the UI from the UI thread. Even if you are using databinding -- if a timer thread updates a value that is databound to the UI, that "counts" as the wrong thread touching the UI.

  1. Always protect your timeer callback with a try..catch block. .Net's default behavior for unhandled exceptions is to terminate the process. I've seen lots of "just quit", where the real culprit was no exception handling on a timer thread, or a worker thread. (in fact, WPF should be throwing an exception if you try to manipulate the UI from the wrong thread, so it could be that you are getting the exception, and then the program terminates because there is no handler)

Why not simply use a background thread to dispatch events?

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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