Как использовать таймер в С#

Я использую system.Timers.Timer для создания таймера.

public System.Timers.Timer timer = new System.Timers.Timer(200);
private void btnAutoSend_Click(object sender, EventArgs e)
{
    timer.Enabled = true;
    timer.Elapsed += new System.Timers.ElapsedEventHandler(send);
    timer.AutoReset = true;
}

public void send(object source, System.Timers.ElapsedEventArgs e)
{
    this.rtbMsg.AppendText("psyche-->" + receiver + ": hello\n");
}

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

public void send(object source, System.Timers.ElapsedEventArgs e,string receiver)

Затем он выдает ошибку. После того, как я проверил MSDN, он сказал, что ElapsedEventArgs доступен только для этой функции, которая не будет выводить данные.

Как я могу решить эту проблему? Моя программа - это не windows.Form, поэтому я не могу использовать System.Windows.Forms.Timer.

Ответы

Ответ 1

Вы не можете передавать дополнительные параметры для обратного вызова обработчика события, потому что вы не тот, кто его вызывает - таймер; что вся точка; -)

Но вы можете легко выполнить тот же эффект с закрытием:

private void btnAutoSend_Click(object sender, EventArgs e)
{
    timer.Elapsed += (timerSender, timerEvent) => send(timerSender, timerEvent, receiver);
    timer.AutoReset = true;
    timer.Enabled = true;
}

public void send(object source, System.Timers.ElapsedEventArgs e, string receiver)
{
    this.rtbMsg.AppendText("psyche-->" + receiver + ": hello\n");
}

Теперь обработчик Elapsed - это действие (timerSender, timerEvent) => лямбда, которое закрывается над переменной receiver и вызывает send вручную с дополнительным параметром всякий раз, когда активируется лямбда.

В вашем конкретном случае вам вообще не нужен отправитель или аргументы, поэтому нет необходимости пересылать их. Код будет выглядеть следующим образом:

private void btnAutoSend_Click(object sender, EventArgs e)
{
    timer.Elapsed += (s_, e_) => OnTimerElapsed(receiver);
    timer.AutoReset = true;
    timer.Enabled = true;
}

private void OnTimerElapsed(string receiver)
{
    this.rtbMsg.AppendText("psyche-->" + receiver + ": hello\n");
}

Если вам интересно о накладных расходах всего этого, это довольно минимально. Lambdas - это просто синтаксический сахар и являются простыми функциями за кулисами (с некоторой автоматической упаковкой делегатов, добавленной для материала события). Закрытие выполняется с использованием классов, генерируемых компилятором, но вы не заметите раздувания кода, если у вас действительно есть тонна из них.

Как указано в комментариях, вы, кажется, получаете доступ к элементу пользовательского интерфейса в коде OnTimerElapsed, поскольку вы не используете таймер Windows Forms, есть хорошие шансы, что вы получите исключение, сделав это так как код будет работать в любом потоке, который таймер запускается при запуске события, а элементы управления пользовательского интерфейса в Windows должны быть доступны только из потока, который их создал.

Вы можете обходиться с помощью this.Invoke, чтобы исправить его вручную, но вам проще настроить таймер для события в нужную цепочку для вас через SynchronizingObject свойство:

private void btnAutoSend_Click(object sender, EventArgs e)
{
    timer.SynchronizingObject = this;    // Assumes `this` implements ISynchronizeInvoke
    timer.Elapsed += (s_, e_) => OnTimerElapsed(receiver);
    timer.AutoReset = true;
    timer.Enabled = true;
}

Наконец, в ответ на другой комментарий, здесь вы можете сохранить ссылку на закрытие, чтобы позднее отказаться от подписки:

private void btnAutoSend_Click(object sender, EventArgs e)
{
    timer.SynchronizingObject = this;    // Assumes `this` implements ISynchronizeInvoke
    ElapsedEventHandler onElapsed;
    onElapsed = (s_, e_) => {
        timer.Elapsed -= onElapsed;    // Clean up after firing
        OnTimerElapsed(receiver);
    };
    timer.Elapsed += onElapsed;
    timer.AutoReset = true;
    timer.Enabled = true;
}

Ответ 2

Вы не можете передавать дополнительные параметры обработчику событий.

Сохраните свое значение в переменной уровня объекта, чтобы его можно было получить в обработчике событий.

private string receiver;

public System.Timers.Timer timer = new System.Timers.Timer(200);
private void btnAutoSend_Click(object sender, EventArgs e)
{
    timer.Enabled = true;
    receiver = 'your val';
    timer.Elapsed += new System.Timers.ElapsedEventHandler(send);
    timer.AutoReset = true;
}

public void send(object source, System.Timers.ElapsedEventArgs e)
{
    this.rtbMsg.AppendText("psyche-->" + receiver + ": hello\n");
}

Ответ 3

public partial class Form2 : Form
{
    Timer timer = new Timer();
    public Form2()
    {
        InitializeComponent();
        timer.Tick += new EventHandler(timer_Tick); // Every time timer ticks, timer_Tick will be called
        timer.Interval = (10) * (1000);             // Timer will tick every 10 seconds
        timer.Start();                              // Start the timer
    }
    void timer_Tick(object sender, EventArgs e)
    {
        //MessageBox.Show("Tick");                    // Alert the user
        var time = DateTime.Now;
        label1.Text = $"{time.Hour} : {time.Minute} : {time.Seconds} : {time.Milliseconds}";
    }
    private void Form2_Load(object sender, EventArgs e)
    {

    }
}