2

Я сделал класс таймера на основе обсуждения this, но у меня проблема с ним, прошедшее событие происходит только один раз. Меньшая проблема: было бы хорошо, если _timer не нужно создавать при каждом вызове Start().Таймер в портативной библиотеке классов

using System; 
using System.Threading; 
using System.Threading.Tasks; 
using System.Diagnostics.Contracts; 

namespace JellystonePark.Model 
{ 
    internal delegate void TimerCallback(object state); 
    internal sealed class Timer : CancellationTokenSource, IDisposable 
    { 
     internal Timer(TimerCallback callback, object state, TimeSpan dueTime, TimeSpan period) 
     { 
      Contract.Assert(period == TimeSpan.FromMilliseconds(-1), "This stub implementation only supports dueTime."); 
      Task.Delay(dueTime, Token).ContinueWith((t, s) => 
      { 
       var tuple = (Tuple<TimerCallback, object>)s; 
       tuple.Item1(tuple.Item2); 
      }, Tuple.Create(callback, state), CancellationToken.None, 
       TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnRanToCompletion, 
       TaskScheduler.Default); 
     } 

     public new void Dispose() { base.Cancel(); } 
    } 
    public class PCLTimer 
    { 
     private Timer _timer; 
     private TimeSpan _interval; 

     /// <summary> 
     /// Interval between signals in milliseconds. 
     /// </summary> 
     public double Interval 
     { 
      get { return _interval.TotalMilliseconds; } 
      set { _interval = TimeSpan.FromMilliseconds(value); Stop(); Start(); } 
     } 

     /// <summary> 
     /// True if PCLTimer is running, false if not. 
     /// </summary> 
     public bool Enabled 
     { 
      get { return null != _timer; } 
      set { if (value) Start(); else Stop(); } 
     } 

     /// <summary> 
     /// Occurs when the specified time has elapsed and the PCLTimer is enabled. 
     /// </summary> 
     public event EventHandler Elapsed; 

     /// <summary> 
     /// Starts the PCLTimer. 
     /// </summary> 
     public void Start() 
     { 
      if (0 == _interval.TotalMilliseconds) 
       throw new InvalidOperationException("Set Elapsed property before calling PCLTimer.Start()."); 
      _timer = new Timer(OnElapsed, null, _interval, _interval); 
     } 

     /// <summary> 
     /// Stops the PCLTimer. 
     /// </summary> 
     public void Stop() 
     { 
      _timer.Dispose(); 
     } 

     /// <summary> 
     /// Releases all resources. 
     /// </summary> 
     public void Dispose() 
     { 
      _timer.Dispose(); 
     } 

     /// <summary> 
     /// Invokes Elapsed event. 
     /// </summary> 
     /// <param name="state"></param> 
     private void OnElapsed(object state) 
     { 
      if (null != _timer && null != Elapsed) 
       Elapsed(this, EventArgs.Empty); 
     } 
    } 
} 
+0

Непонятно, на какой именно вопрос вы ищете ответ? –

+0

Вам нужно указать * период *, чтобы таймер срабатывал более одного раза. Затем вы узнаете, почему этот код сосет. –

+0

@HansPassant У вас есть идея, как определить период? Мне не нужен полный рабочий код, только некоторые рекомендации, как начать с него. Я должен реализовать таймер в библиотеке pcl, я не нашел никаких рабочих решений, если вы лучше этого, пожалуйста, поделитесь со мной. –

ответ

2

Если вы заинтересованы в реализации таймера с задачами, вы можете попробовать этот код:

public delegate void TimerCallback(object state); 

public sealed class Timer : CancellationTokenSource, IDisposable 
{ 
    public Timer(TimerCallback callback, object state, int dueTime, int period) 
    { 
     Task.Delay(dueTime, Token).ContinueWith(async (t, s) => 
     { 
      var tuple = (Tuple<TimerCallback, object>) s; 

      while (true) 
      { 
       if (IsCancellationRequested) 
        break; 
       Task.Run(() => tuple.Item1(tuple.Item2)); 
       await Task.Delay(period); 
      } 

     }, Tuple.Create(callback, state), CancellationToken.None, 
      TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnRanToCompletion, 
      TaskScheduler.Default); 
    } 

    public new void Dispose() { base.Cancel(); } 
} 

Как уже упоминалось вы можете ввести зависимость от какой-то интерфейс и попросить пользователя, чтобы дать вам конкретную реализацию таймера.

+1

Возможно, стоит изменить это на 'while (! IsCancellationRequested)' –

Смежные вопросы