Timer in Portable Library

后端 未结 6 848
我寻月下人不归
我寻月下人不归 2020-11-29 03:41

I can\'t find a timer in portable library / Windows Store. (Targeting .net 4.5 and Windows Store aka Metro)

Does any have an idea on how to created some kind of timi

相关标签:
6条回答
  • 2020-11-29 03:49

    I improved Ivan Leonenko answer by including a new parameter, which queue calls to you callback if the period is less than the callback run time. And replaced the legacy TimerCallback with an action. And finally, use our cancel token in the last delay, and used ConfigureAwait to increase concurrency, as the callback can be executed on any thread.

    internal sealed class Timer : CancellationTokenSource
    {
        internal Timer(Action<object> callback, object state, int millisecondsDueTime, int millisecondsPeriod, bool waitForCallbackBeforeNextPeriod = false)
        {
            //Contract.Assert(period == -1, "This stub implementation only supports dueTime.");
    
            Task.Delay(millisecondsDueTime, Token).ContinueWith(async (t, s) =>
            {
                var tuple = (Tuple<Action<object>, object>) s;
    
                while (!IsCancellationRequested)
                {
                    if (waitForCallbackBeforeNextPeriod)
                        tuple.Item1(tuple.Item2);
                    else
                        Task.Run(() => tuple.Item1(tuple.Item2));
    
                    await Task.Delay(millisecondsPeriod, Token).ConfigureAwait(false);
                }
    
            }, Tuple.Create(callback, state), CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Default);
        }
    
        protected override void Dispose(bool disposing)
        {
            if(disposing)
                Cancel();
    
            base.Dispose(disposing);
        }
    }
    
    0 讨论(0)
  • 2020-11-29 03:49

    I ended up with Observable.Timer from Reactive Extensions (Rx). Rx was already included in the project, so additional reference was not an issue.

    Here is a timer that triggers every second:

    IDisposable timer = Observable.Timer(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1))
        .Subscribe(_ => /* your useful code here */);
    
    // unsubscribe/stop when timer is no longer needed
    timer.Dispose();
    

    System.Reactive.Linq.Observable class is in PCL friendly Rx-Linq NuGet package.

    0 讨论(0)
  • 2020-11-29 04:00

    Following suggestion #3 from David Kean, here's my hacky Timer adapter - put this in a PCL library that targets .net 4.0, and reference it from 4.5:

        public class PCLTimer
        {
            private Timer _timer;
    
            private Action _action;
    
            public PCLTimer(Action action, TimeSpan dueTime, TimeSpan period)
            {
                _action = action;
    
                _timer = new Timer(PCLTimerCallback, null, dueTime, period);           
            }
    
            private void PCLTimerCallback(object state)
            {
                _action.Invoke();
            }
    
            public bool Change(TimeSpan dueTime, TimeSpan period)
            {
                return _timer.Change(dueTime, period);
            }
        }
    

    And then to use it, you can do this from your 4.5 PCL library:

        private void TimeEvent()
        {            
            //place your timer callback code here
        }
    
        public void SetupTimer()
        {            
            //set up timer to run every second
            PCLTimer _pageTimer = new PCLTimer(new Action(TimeEvent), TimeSpan.FromMilliseconds(-1), TimeSpan.FromSeconds(1));
    
            //timer starts one second from now
            _pageTimer.Change(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1));
    
        }
    
    0 讨论(0)
  • 2020-11-29 04:06

    Update: We have fixed this in Visual Studio 2013. Portable libraries targeting Store (Windows 8.1) and .NET Framework 4.5.1 projects can now reference Timer.

    This is unfortunate case of where our implementation details are leaking to the user. When you target just .NET 4.5 and Windows Store apps, we actually cause you to build against something different then when you target a down-level platform (.NET 4, SL 4/5, Phone 7.x). We try treat these two as the same, but limited changes underneath start to leak (such as Timer, and Reflection). We cover some of this here: http://channel9.msdn.com/Shows/Going+Deep/NET-45-David-Kean-and-Marcea-Trofin-Portable-Libraries.

    We'll look at fixing this in a future version. Until then, you have a couple of workarounds:

    1) Implement your own version of Timer using Task.Delay, here's a quick copy that we're using internally:

    internal delegate void TimerCallback(object state);
    
    internal sealed class Timer : CancellationTokenSource, IDisposable
    {
        internal Timer(TimerCallback callback, object state, int dueTime, int period)
        {
            Contract.Assert(period == -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(); }
    }
    

    2) Downgrade your project to .NET 4.0 and Windows Store apps, which will give you access to Timer.

    3) Create a new project targeting .NET 4.0 and Windows Store apps, and put the code that requires timer in that. Then reference that from the .NET 4.5 and Windows Store apps project.

    As a side note, I've filed a work item for myself over on PclContrib site to add Timer support: http://pclcontrib.codeplex.com/workitem/12513.

    0 讨论(0)
  • 2020-11-29 04:06

    Implementation of suggestion #1 from David Kean with period:

    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(); }
    }
    
    0 讨论(0)
  • 2020-11-29 04:06

    You could create a timer interface using a PCL library and then create an implementation of that interface in a second W8S library using a W8S timer.

    Then you could use dependency injection to inject the W8S library into the PCL class.

    0 讨论(0)
提交回复
热议问题