Ответ 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;
}