web-dev-qa-db-fra.com

Comment passer un objet dans un événement de minuterie?

Ok donc j'utilise System.Timers.Timer dans .Net 4 avec C #.

J'ai mon objet timer comme ceci:

var timer = new Timer {Interval = 123};

J'ai mon gestionnaire d'événements Timer Elapsed pointé sur une méthode comme celle-ci:

timer.Elapsed += MyElapsedMethod;

Et ma méthode ressemble à ceci:

static void MyElapsedMethod(object sender, ElapsedEventArgs e)
{
    Console.WriteLine("Foo Bar");
}

Je veux passer une chaîne dans cette méthode, comment faire?

Merci

28
JMK

La façon la plus simple de procéder consiste à transformer le gestionnaire d'événements en une fonction anonyme. Il vous permet de passer la chaîne au point de déclaration.

string theString = ...;
timer.Elapsed += (sender, e) => MyElapsedMethod(sender, e, theString);

static void MyElapsedMethod(object sender, ElapsedEventArgs e, string theString) {
  ...
}
70
JaredPar

Si vous voulez pouvoir à nouveau désenregistrer votre gestionnaire d'événements "Elapsed", vous ne devez pas utiliser un délégué sans vous en souvenir dans une variable.

Une autre solution pourrait donc être de créer une classe personnalisée basée sur Timer. Ajoutez simplement les membres que vous aimez et récupérez votre objet Timer personnalisé à partir de l'argument "sender" du gestionnaire d'événements "Elapsed":

class CustomTimer : System.Timers.Timer
{
    public string Data;
}

private void StartTimer()
{
    var timer = new CustomTimer
    {
        Interval = 3000,
        Data = "Foo Bar"
    };

    timer.Elapsed += timer_Elapsed;
    timer.Start();
}

void timer_Elapsed(object sender, ElapsedEventArgs e)
{
    string data = ((CustomTimer)sender).Data;
}

Cette stratégie fonctionne bien sûr pour d'autres événements et classes aussi, tant que la classe de base n'est pas scellée.

16
Michael Geier

Vous pouvez enregistrer la chaîne dans un objet et la lire dans le gestionnaire d'événements:

static string _value;

static void MyElapsedMethod(object sender, ElapsedEventArgs e)
{
    Console.WriteLine(_value);
}

MISE À JOUR: même code via une syntaxe différente: timer.Elapsed += (s,e) => Console.WriteLine(_value);

MISE À JOUR: Pensez également à utiliser System.Threading.Timer à la place

State state = new State();
Timer timer = new Timer(OnTimer, state, 0, 123);
state.Value = "FooBar"; // change state object

Vous pouvez récupérer l'état dans le rappel du minuteur:

static void OnTimer(object obj)
{
    State state = obj as State;
    if (state == null)
        return;        

    Console.WriteLine(state.Value);
}
2
 Timer aTimer = new Timer(300);
                aTimer.Elapsed += delegate { PublishGPSData(channel, locationViewModel); };
                // Hook up the Elapsed event for the timer. 
                aTimer.AutoReset = true;
                aTimer.Enabled = true;
private void PublishGPSData(IModel channel, LocationViewModel locationViewModel)
{
};
1
Mahendra

J'ai écrit cette classe simple pour gérer cela:

using System;
using System.Timers;

namespace MyProject.Helpers
{
    public class MyTimer
    {
        private volatile Timer _timer = new Timer();
        private volatile bool _requestStop = false;
        private MyElapsedEventHandler _eventHander;
        private MyElapsedEventHandlerWithParam _eventHandlerWithParam;
        private object _param;

        public MyTimer(int interval, MyElapsedEventHandler elapsedEventHandler, bool autoReset = false)
        {
            _timer.Interval = interval;
            _timer.Elapsed += ElapsedWrapper;
            _timer.AutoReset = autoReset;

            _eventHander = elapsedEventHandler;

            Start();
        }

        public MyTimer(int interval, MyElapsedEventHandlerWithParam elapsedEventHandler, object param, bool autoReset = false)
        {
            _timer.Interval = interval;
            _timer.Elapsed += ElapsedWrapperWithParam;
            _timer.AutoReset = autoReset;

            _eventHandlerWithParam = elapsedEventHandler;
            _param = param;

            Start();
        }

        private void ElapsedWrapper(object sender, ElapsedEventArgs e)
        {
            if (!_requestStop && _eventHander != null)
            {
                _eventHander();
            }
        }

        private void ElapsedWrapperWithParam(object sender, ElapsedEventArgs e)
        {
            if (!_requestStop && _eventHandlerWithParam != null)
            {
                _eventHandlerWithParam(_param);
            }
        }

        public void Stop()
        {
            _requestStop = true;
            _timer.Stop();
        }

        public void Start()
        {
            _requestStop = false;
            _timer.Start();
        }
    }

    public delegate void MyElapsedEventHandlerWithParam(object param);
    public delegate void MyElapsedEventHandler();
}

utilisez-le comme ceci:

void Main(string[] args){
    new MyTimer(durationInSeconds * 1000, EventHandler, "some string");
}

void EventHandler(object param){
    doSomethingWithString((string)param);
}

vous pouvez également passer les arguments d'événement ou tout type de paramètres si vous modifiez le délégué (et l'appel du gestionnaire d'événements dans la classe MyTimer).

0
lennyy

Utilisez un champ de la même classe pour contenir la chaîne de votre choix, puis récupérez-la dans votre gestionnaire d'événements écoulé. Vous devrez cependant faire attention aux problèmes de cross-threading.

0
Matt Burland