Temporizador en Biblioteca Portátil


No puedo encontrar un temporizador en portable library / Windows Store. (Dirigido a. net 4.5 y Windows Store aka Metro)

¿Alguien tiene una idea de cómo crear algún tipo de evento de tiempo?

Necesito algún tipo de cronómetro, así que esto debería refrescarse una vez por segundo más o menos

Author: Boas Enkler, 2012-09-23

6 answers

Actualización: Hemos arreglado esto en Visual Studio 2013. Las bibliotecas portátiles que tienen como objetivo el almacén (Windows 8.1) y los proyectos de.NET Framework 4.5.1 ahora pueden hacer referencia al temporizador.

Este es un caso desafortunado de donde nuestros detalles de implementación se están filtrando al usuario. Cuando se dirige solo a. NET 4.5 y aplicaciones de la tienda Windows, en realidad causamos que construya contra algo diferente que cuando se dirige a una plataforma de nivel inferior (. NET 4, SL 4/5, Phone 7.x). Tratamos de tratar a estos dos como lo mismo, pero los cambios limitados debajo comienzan a filtrarse (como el temporizador y la Reflexión). Cubrimos algo de esto aquí: http://channel9.msdn.com/Shows/Going+Deep/NET-45-David-Kean-and-Marcea-Trofin-Portable-Libraries.

Veremos cómo arreglar esto en una versión futura. Hasta entonces, tienes un par de soluciones:

1) Implementa tu propia versión del temporizador usando Task.Delay, aquí hay una copia rápida que estamos usando internamente:

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) Degradar su proyecto a. NET 4.0 y Windows Tienda de aplicaciones, que le dará acceso al temporizador.

3) Crear un nuevo proyecto dirigido a.NET 4.0 y aplicaciones de la tienda Windows, y poner el código que requiere temporizador en eso. Luego haga referencia a eso desde. NET 4.5 y Windows Store apps project.

Como nota al margen, he archivado un elemento de trabajo para mí en el sitio PclContrib para agregar soporte de temporizador: http://pclcontrib.codeplex.com/workitem/12513 .

 44
Author: David Kean,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-10 17:26:59

Siguiendo la sugerencia # 3 de David Kean, aquí está mi adaptador de temporizador hacky: coloque esto en una biblioteca PCL que se dirija a. net 4.0 y haga referencia a ella desde 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);
        }
    }

Y luego para usarlo, puede hacer esto desde su biblioteca PCL 4.5:

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

    }
 7
Author: Henry C,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-13 01:58:15

Implementación de la sugerencia #1 de David Kean con punto:

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(); }
}
 6
Author: Ivan Leonenko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-13 15:42:04

Mejoré la respuesta de Ivan Leonenko al incluir un nuevo parámetro, que pone en cola las llamadas a la devolución de llamada si el período es menor que el tiempo de ejecución de la devolución de llamada. Y reemplazó el TimerCallback heredado con una acción. Y finalmente, use nuestro token de cancelación en el último retraso, y use ConfigureAwait para aumentar la concurrencia, ya que la devolución de llamada se puede ejecutar en cualquier subproceso.

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);
    }
}
 4
Author: Softlion,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-09 14:27:02

Puede crear una interfaz de temporizador utilizando una biblioteca PCL y luego crear una implementación de esa interfaz en una segunda biblioteca W8S utilizando un temporizador W8S.

Entonces podría usar la inyección de dependencias para inyectar la biblioteca W8S en la clase PCL.

 2
Author: Paul,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-16 18:49:09

Terminé con Observable.Timer de Reactive Extensions (Rx). Rx ya estaba incluido en el proyecto, por lo que la referencia adicional no era un problema.

Aquí hay un temporizador que se activa cada segundo:

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 la clase es en PCL friendly Rx-Linq Paquete NuGet.

 1
Author: altso,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-21 02:59:33