how to use Timer in C# - c#

I'm using system.Timers.Timer to create a 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");
}
The receiver in send function is a parameter that I need to set when the function is used, but when I add a parameter in the send function, like:
public void send(object source, System.Timers.ElapsedEventArgs e,string receiver)
Then it throws an error. After I checked the MSDN, it said ElapsedEventArgs is only available for these function which won't produce data.
How can I solve this problem? My program isn't the windows.Form, so I cannot use the System.Windows.Forms.Timer.

You can't pass extra parameters to the event handler callback, because you aren't the one calling it -- the Timer is; that's the whole point ;-)
But, you can easily accomplish the same effect with a closure:
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");
}
Now the Elapsed handler is the (timerSender, timerEvent) => lambda action, which closes over the receiver variable and calls send manually with the extra parameter whenever the lambda is triggered.
In your particular case you don't need the sender or arguments at all, so there's no need to forward them. The code becomes:
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");
}
If you're wondering about the overhead of all this, it's pretty minimal. Lambdas are just syntactic sugar and are plain functions behind the scenes (with some automatic delegate wrapping thrown in for the event stuff). Closures are implemented using compiler-generated classes, but you won't notice any code bloat unless you truly have a ton of them.
As pointed out in the comments, you seem to be accessing a UI element in the OnTimerElapsed code -- since you're not using a Windows Forms timer, there's a good chance you'll get an exception by doing this since the code will run on whatever thread the timer happens to be running in when it fires the event -- and UI controls in Windows must be accessed only from the thread that created them.
You could mess around with this.Invoke to fix it manually, but it's easier to have the timer marshall the event to the right thread for you via the SynchronizingObject property:
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;
}
Finally, prompted by another comment, here's another way you could store a reference to the closure so that you can unsubscribe from the event later:
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;
}

You can't pass extra parameters to an event handler like that.
Store your value in an object level variable so that it can be accessed in the event handler.
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");
}

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)
{
}
}

Related

Access specific timer to stop it by tag

Im starting multiple timer with this Code.
All timers run the same Tick_event where i identify the Timer by tag.
ArrayList list = new ArrayList();
private void button1_Click(object sender, EventArgs e)
{
Timer t = new Timer();
t.Tag = ID;
t.Interval = 60000;
t.Tick += tm_Tick;
list.Add(t);
t.Enabled = true;
t.Start();
}
And on tick event i get the tag ID number with this code, and it works great.
private void tm_Tick(object sender, EventArgs e)
{
Console.WriteLine((sender as Timer).Tag);
}
But how can i access the specific timer with the ID, to stop it?
its .NET Winforms
Why not use a Dictionary
Dictionary<String, Timer> list = new Dictionary<String, Timer>();
private void button1_Click(object sender, EventArgs e)
{
Timer t = new Timer();
t.Tag = ID;
list.Add(ID, t);
...
}
Then to stop it:
list[tag].Stop();
Note: Make sure you Dispose your timers at some point

Can't write to the richTextBox

I have this simple program :
private static System.Timers.Timer t3;
private void button1_Click(object sender, EventArgs e)
{
t3 = new System.Timers.Timer(5000);
t3.AutoReset = true; t3.Enabled = true; t3.Elapsed += OnTimedEvent3;
}
private void OnTimedEvent3(Object source, ElapsedEventArgs e)
{
// MessageBox.Show("event raised");
richTextBox1.Text = "t3 is elapsed ";//
}
PROBLEM : : Nothing appears in the richTextBox1 after event is fired ! I have tried MessageBox and that works fine . what could be the problem ??
Your problem is the following:
The eventhandler of your timer is running on a different thread like your UI. You need to invoke the control like
if(richTextBox1.InvokeRequired == true)
{
richTextBox1.Invoke((MethodInvoker)delegate
{
richTextBox1.Text = "t3 is elapsed "
});
}
else
{
richTextBox1.Text = "t3 is elapsed ";
}
to access it correctly. Thats because UI objects are related to their thread. Creating a MessageBox for example is possible out of every thread - because your Box is not existing already.

Label Text Refresh every second

I'm trying to make a label refresh every second so the countdown updates, having some trouble. I'm extremely new to C# apologies for the noob questions.
private void Form1_Load(object sender, EventArgs e)
{
bool ephCD = true;
int ephHours = (DateTime.Today.AddDays(1) - DateTime.Now).Hours;
int ephMinu = (DateTime.Today.AddDays(1) - DateTime.Now).Minutes;
int ephSecs = (DateTime.Today.AddDays(1) - DateTime.Now).Seconds;
label1.Text = ephHours.ToString() + ":" + ephMinu.ToString() + ":" + ephSecs.ToString();
while (ephCD == true)
{
label1.Refresh();
}
}
When launching this the program doesn't even appear.
Why does the program not appear?
You are performing an infinite loop in Form_Load. This means that the form will never finish loading, and your program will be stuck.
Your refresh loop needs to be on a separate thread, or ideally toss the loop and use a Timer instead of spin locking the CPU on an infinite loop.
Timer myTimer = new Timer(1000);
void Form1_Load()
{
myTimer.Elapsed += UpdateLabel;
myTimer.Start();
}
private void UpdateLabel(object sender, ElapsedEventArgs e)
{
//Update label here
}
Updating the label in a while statement is not a good option, a better approach would be to use Timer class
var aTimer = new System.Timers.Timer(1000);
aTimer.Elapsed += OnTimedEvent;
aTimer.Enabled = true;
private static void OnTimedEvent(Object source, ElapsedEventArgs e)
{
//update the label
}
This will do, just copy and paste:
private void Form1_Load(object sender, EventArgs e)
{
// To update the first time.
label1.Text = (DateTime.Today.AddDays(1)- DateTime.Now).ToString(#"hh\:mm\:ss");
var timer = new Timer {Interval = 1000};
timer.Tick += (o, args) =>
{
label1.Text = (DateTime.Today.AddDays(1)- DateTime.Now).ToString(#"hh\:mm\:ss");
};
timer.Start();
}
I ended up with this simpler solution:
<script>
var myTimer = setInterval(Atualizar, 20000);
function Atualizar() {
__doPostBack('UpdatePanelNew', '');
}
</script>
Make sure you wrap what you want to update within an UpdatePanel.
This code will request a postback in every 20s. So in the code behind I can do this:
protected void Page_Load(object sender, EventArgs e)
{
myLabel.InnerText = GetInDatabaseTheValueIwant();
}

backgroundWorker and progressChanged not working

i cant get the progress bar to work! if i execute the following code the bar remains empty even if the code gets executed the ReportProgress doesnt seem to update anything..:
namespace GPUZ_2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
GPUZdata test = new GPUZdata
{
};
//invio l'oggetto al thread backgroundworker
backgroundWorker1.RunWorkerAsync(test);
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
//
// e.Argument always contains whatever was sent to the background worker
// in RunWorkerAsync. We can simply cast it to its original type.
//
GPUZdata argumentTest = e.Argument as GPUZdata;
argumentTest.OneValue = 6;
Thread.Sleep(2000);
backgroundWorker1.ReportProgress(50);
argumentTest.TwoValue = 3;
Thread.Sleep(2000);
backgroundWorker1.ReportProgress(100);
//
// Now, return the values we generated in this method.
// Always use e.Result.
//
e.Result = argumentTest;
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// Receive the result from DoWork, and display it.
GPUZdata test = e.Result as GPUZdata;
this.Text = test.OneValue.ToString() + " " + test.TwoValue.ToString();
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// Change the value of the ProgressBar to the BackgroundWorker progress.
progressBar1.Value = e.ProgressPercentage;
// Set the text.
this.Text = e.ProgressPercentage.ToString();
}
}
}
thanks in advance for your help
To initialize the BackgroundWorker, you must enable progress reporting and hook up your event handlers:
// Enable progress reporting
backgroundWorker1.WorkerReportsProgress = true;
// Hook up event handlers
backgroundWorker1.DoWork += backgroundWorker1_DoWork;
backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;
I don't see where you set the WorkerReportsProgress property to true - that most likely is the problem:
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.RunWorkerAsync(test);
I had the same problem. In AssemblyInfo.cs you should make this change for ComVisible.
[assembly: ComVisible(true)]

why is this backgroundworker code causing this error: Parameter count mismatch

what is wrong with this code below? The conn_PageDeleted is coming from a background thread and i am trying to update a label every time i get a call back. I get an error stating
Parameter count mismatch.
Here is the code:
private void cmdDeletePage_Click(object sender, EventArgs e)
{
worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
worker.RunWorkerAsync();
}
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
lblDeleteStatus.Text = "";
MessageBox.Show("Complete");
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
Connecter conn = new Connecter("a", "m");
conn.PageDeleted += new Connecter.PageDeletedHandler(conn_PageDeleted);
bool success = conn.DeletePage(txtPageToDelete.Text, chkRecursive.Checked);
}
public delegate void UpdateLabelHandler(object sender, string name);
void conn_PageDeleted(object sender, string name)
{
if (this.InvokeRequired)
{
this.BeginInvoke(new UpdateLabelHandler(UpdateMe));
}
else
{
lblDeleteStatus.Text = name;
}
}
private void UpdateMe(object sender_, string name_)
{
lblDeleteStatus.Text = name_;
}
You should pass the parameters to the UpdateMe method, try this:
void conn_PageDeleted(object sender, string name)
{
if (this.InvokeRequired)
{
this.BeginInvoke(new UpdateLabelHandler(UpdateMe), new object[] {sender, name}); //<-- the update goes here
}
else
{
lblDeleteStatus.Text = name;
}
}
Your delegate has to match the signature of the event handler, something like this:
public delegate void UpdateLabelHandler(object sender, string strArgs);
Edit: Since you have edited the code to include this ... I will amend this accordingly....
Looking at your edited code, I have to question this:
void worker_DoWork(object sender, DoWorkEventArgs e)
{
Connecter conn = new Connecter("a", "m");
conn.PageDeleted += new Connecter.PageDeletedHandler(conn_PageDeleted);
bool success = conn.DeletePage(txtPageToDelete.Text, chkRecursive.Checked);
}
You are wiring up a 'PageDeleted' event handler....and call 'DeletePage' method after it, I presume that in turn invokes the event handler 'conn_PageDeleted' within the 'DoWork' body, it goes out of scope when the 'BackgroundWorker' thread is finished...and since 'conn' is in local scope of the 'worker_DoWork' method, that gets destroyed, and somehow your event handler gets messed up! Can you confirm this?
Hope this helps,
Best regards,
Tom.

Categories

Resources