how to create multiple countdown timers in c# windows application form? - c#

I had created multiple timers using for loop and the timers are diplayed in the corresponding labels.If i click the button "n" times then "n" times ll be created.This code shows error in time countdown during runtime. Each timer is getting decremented by different intervals.How to resolve this problem?
public Dictionary<Timer, Label> dict = new Dictionary<Timer, Label>();
int n = 1;
int timesec = 10;
private void CreateTimers()
{
for (int i = 1; i <= n; i++)
{
Timer timer = new Timer();
timer = new System.Windows.Forms.Timer();
timer.Tick += new EventHandler(timer_Tick);
timer.Interval = (1000);//1 sec
Label label = new Label();
label.Name = "label" + i;
label.Location = new Point(0, 100 + i * 30);
label.TabIndex = i;
label.Visible = true;
this.Controls.Add(label);
dict[timer] = label;
timer.Enabled = true;
timer.Start();
}
private void button2_Click(object sender, EventArgs e)
{
//function call
CreateTimers();
n++;
}
private void timer_Tick(object sender, EventArgs e)
{
//timer countdown
Timer t = (Timer)sender;
timesec--;
if (timesec == 0)
t.Stop();
dict[t].Text = timesec.ToString();
}

A couple of issues. First and foremost, you have to eliminate that loop, since that creates more timers than you probably realize. Also, since you want each timer to be independent, you can't change the timesec value.
Try using the value of the label to show the count down, something like this:
private void CreateTimer() {
System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
timer.Tick += timer_Tick;
timer.Interval = (1000);//1 sec
Label label = new Label();
label.Name = "label" + n.ToString();
label.Text = timesec.ToString();
label.Location = new Point(0, 100 + n * 30);
label.Visible = true;
this.Controls.Add(label);
dict.Add(timer, label);
timer.Enabled = true;
timer.Start();
n++;
}
private void timer_Tick(object sender, EventArgs e) {
System.Windows.Forms.Timer t = (System.Windows.Forms.Timer)sender;
Label l = dict[t];
int labelTime = 0;
if (Int32.TryParse(l.Text, out labelTime)) {
labelTime -= 1;
}
l.Text = labelTime.ToString();
if (labelTime == 0) {
t.Stop();
}
}

Related

Add multiple timer with for loop C#

I need 40 timers in my program but I want to create these dynamically.
System.Timers.Timer timermatrix1=new System.Timers.Timer();
timermatrix1.Enabled = true;
timermatrix1.Interval = 10;
timermatrix1.Elapsed += Timermatrix1_Elapsed;
private void Timermatrix1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
.....
}
This code can create one timer but I need 40.So How can I do?
Create an array and initialize them in a loop:
System.Timers.Timer[] timerMatrix = new System.Timers.Timer[40];
for(int i=0; i < 40; i++){
timerMatrix[i] = new System.Timers.Timer() {
Enabled = true,
Interval = 10
};
timerMatrix[i].Elapsed += (sender, e) => {
//TODO: add timer logic
};
}

C# panel move with collision

I am new to C# and Winforms and try to make a moving panel. It should move right until the end of my window and then back left. It should bounce from side to side. But the only thing happened after hours of trying is that it moves left and stops.
Using this form tools:
Timer = tmrMoveBox (interval: 50)
Panel = pnlBox
Label = lblXY (for showing the X and Y coordinates in the form)
Here are my first best try:
private void tmrMoveBox(object sender, EventArgs e)
{
if (pnlBox.Location.X <= 316)
{
for (int i = 0; i <= 316; i++)
{
pnlBox.Location = new Point(
pnlBox.Location.X + 2, pnlBox.Location.Y);
string BoxLocationToString = pnlBox.Location.ToString();
lblXY.Text = BoxLocationToString;
}
}
else if (pnlBox.Location.X >= 0)
{
for (int i = 0; i >= 316; i++)
{
pnlBox.Location = new Point(
pnlBox.Location.X - 2, pnlBox.Location.Y);
string BoxLocationToString = pnlBox.Location.ToString();
lblXY.Text = BoxLocationToString;
}
}
}
And the second best try:
private void tmrMoveBox(object sender, EventArgs e)
{
int runBox = 1;
if(runBox == 1)
{
while (pnlBox.Location.X <= 316)
{
pnlBox.Location = new Point(
pnlBox.Location.X + 2, pnlBox.Location.Y);
string BoxLocationString = pnlBox.Location.ToString();
lblXY.Text = BoxLocationString;
runBox = 0;
}
}
else
{
while(pnlBox.Location.X > 0)
{
pnlBox.Location = new Point(
pnlBox.Location.X - 2, pnlBox.Location.Y);
string BoxLocationString = pnlBox.Location.ToString();
lblXY.Text = BoxLocationString;
runBox = 1;
}
}
}
Tried to use a while loop too but then the panel just disappears.
I'm no expert and just set this moving panel as a goal for myself. Hope anyone can give me a tip.
EDIT:
Form1.Designer.cs
this.timer1.Interval = 50;
this.timer1.Tick += new System.EventHandler(this.tmrMoveBox);
this.timer1.Start();
this.timer1.Step = 2;
Depending on what you're using:
Windows Forms
WPF
Create a Timer and subscribe to the Tick event. Also, you should create new int property Step.
1. Windows Forms:
System.Windows.Forms.Timer t = new System.Windows.Forms.Timer();
int Step;
Form1 ()
{
InitializeComponent()
....
t.Interval = 15000; // specify interval time as you want
t.Tick += new EventHandler(timer_Tick);
t.Start();
this.Step = 2;
}
And in ticks event handler put your logic, without while
void timer_Tick(object sender, EventArgs e)
{
if (pnlBox.Location.X >= 316)
{
Step = -2;
}
if (pnlBox.Location.X <= 0)
{
Step = 2;
}
pnlBox.Location = new Point(
pnlBox.Location.X + Step , pnlBox.Location.Y);
string BoxLocationString = pnlBox.Location.ToString();
lblXY.Text = BoxLocationString;
}
So your box will move on one step per one timer tick.
1. WPF:
As System.Windows.Forms.Timer is not available, you may use System.Windows.Threading.DispatcherTimer:
using System.Windows.Threading;
DispatcherTimer t = new DispatcherTimer();
t.Interval = new TimeSpan(0, 0, 15); // hours, minutes, seconds (there are more constructors)
t.Tick += Timer_Tick;
t.Start();
Here is the code I used:
int d= 10;
private void timer1_Tick(object sender, EventArgs e)
{
//Reverse the direction of move after a collision
if(panel1.Left==0 || panel1.Right==this.ClientRectangle.Width)
d = -d;
//Move panel, also prevent it from going beyond the borders event a point.
if(d>0)
panel1.Left = Math.Min(panel1.Left + d, this.ClientRectangle.Width - panel1.Width);
else
panel1.Left = Math.Max(panel1.Left + d, 0);
}
Note:
To check the collision you should check:
Collision with left: panel1.Left==0
Collision with right: panel1.Right==this.ClientRectangle.Width
You should not allow the panel goes beyond the borders even a point, so:
The maximum allowed value for your panel left is this.ClientRectangle.Width - panel1.Width
The minimum allowed value for your panel left is 0
Also It's better to use this.ClientRectangle.Width instead of using hard coded 316.

System.InvalidOperationException in C# WPF

I want to move a rectangle in WPF application using the following code. However, I am getting the following error:
System.InvalidOperationException: Cannot use a DependencyObject that belongs to a different thread
I looked at other problems in stackoverflow but nothing worked.
public partial class MainWindow : Window
{
private Rectangle rect;
int count = 1;
Timer timer;
public MainWindow()
{
InitializeComponent();
Rectangle movedRectangle = new Rectangle();
movedRectangle.Width = 200;
movedRectangle.Height = 50;
movedRectangle.Fill = Brushes.Blue;
movedRectangle.Opacity = 0.5;
TranslateTransform translateTransform1 = new TranslateTransform(50, 20);
movedRectangle.RenderTransform = translateTransform1;
this.can.Children.Add(movedRectangle);
this.rect = movedRectangle;
timer = new Timer(500);
timer.Elapsed += OnTimedEvent;
timer.Enabled = true;
}
private void OnTimedEvent(Object source, ElapsedEventArgs e)
{
count++;
TranslateTransform translateTransform1 = new TranslateTransform(50 + count * 2, 20);
this.rect.Dispatcher.Invoke(new Action(()=>
rect.RenderTransform = translateTransform1));
//this.can.UpdateLayout();
this.can.Dispatcher.Invoke(new Action(()=>
this.can.UpdateLayout()
));
}
I would suggest you to use DispatcherTimer than a normal timer.
Please see the below solution. enjoy.
Note: for DispatcherTimer you will need to add the assembly reference for System.Windows.Threading
public partial class MainWindow : Window
{
private Rectangle rect;
int count = 1;
private DispatcherTimer timer = null;
public MainWindow()
{
InitializeComponent();
Rectangle movedRectangle = new Rectangle();
movedRectangle.Width = 200;
movedRectangle.Height = 50;
movedRectangle.Fill = Brushes.Blue;
movedRectangle.Opacity = 0.5;
TranslateTransform translateTransform1 = new TranslateTransform(50, 20);
movedRectangle.RenderTransform = translateTransform1;
this.can.Children.Add(movedRectangle);
this.rect = movedRectangle;
timer = new DispatcherTimer();
timer.Interval = new TimeSpan(0, 0, 0, 0, 500);
timer.Tick += timer_Tick;
timer.Start();
timer.IsEnabled = true;
}
void timer_Tick(object sender, EventArgs e)
{
count++;
TranslateTransform translateTransform1 = new TranslateTransform(50 + count * 2, 20);
Dispatcher.BeginInvoke(new Action<TranslateTransform>(delegate(TranslateTransform t1)
{
rect.RenderTransform = t1;
this.can.UpdateLayout();
}), System.Windows.Threading.DispatcherPriority.Render, translateTransform1);
}
}
You are constructing a TranslateTransform (which is a DependencyObject) outside the UI thread. Easy fix:
this.rect.Dispatcher.Invoke(new Action(
() =>
{
TranslateTransform translateTransform1 = new TranslateTransform(50 + count * 2, 20);
rect.RenderTransform = translateTransform1;
}));
Arguably a better fix: use a DispatcherTimer instead and get rid of all your Dispatcher.Invoke calls.

How to Increment timer asynchronously ?

I am trying to Update a timer asynchronously On a Button Click .
say example i have set the time = 60 seconds
and when i run the program after few TIME the timer has reached to 45 seconds and when i click the Button ,then it should add j=15 seconds to the time and the timer should change to 60 seconds asynchronously. Please Help
private int time = 60;
DateTime dt = new DateTime();
private j = 15 ;
private DispatcherTimer timer;
public MainWindow()
{
InitializeComponent();
timer = new DispatcherTimer();
timer.Interval = new TimeSpan(0, 0, 1);
timer.Tick += timer_tick;
timer.Start();
}
void timer_tick(object sender, EventArgs e)
{
if (time >0)
{
time--;
text.Text = TimeSpan.FromSeconds(time).ToString();
}
else
{
timer.Stop();
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
text.Text = dt.AddSeconds(j).ToString("HH:mm:ss");
}
Here is my code you can try it it's working.
private int time = 60;
DateTime dt = new DateTime();
private int j = 15;
private Timer timer1 = new Timer();
void timer_tick(object sender, EventArgs e)
{
if (time > 0)
{
time--;
text.Text = TimeSpan.FromSeconds(time).ToString();
}
else
{
timer1.Stop();
}
}
public timer()
{
InitializeComponent();
timer1 = new Timer();
timer1.Interval = 1000;
timer1.Tick += timer_tick;
timer1.Start();
}
private void button1_Click(object sender, EventArgs e)
{
time += j;
}

Multiple timer with different interval in C#.net

I want different timer with different interval that i input.For example, if I input 4, 4 timer create and show time in 4 label, where 1st timer's time change in 1sec,2nd timer's time change in 2sec,3rd timer's time change in 3sec and 4tn timer's time change in 4sec.Here is my code,
string input = textBox2.Text;
int n = Convert.ToInt32(input);
for (i = 1; i <= n; i++)
{
Timer timer = new Timer();
timer.Tick += new EventHandler(timer_Tick);
timer.Interval = (1000) * (i);
timer.Enabled = true;
timer.Start();
Label label = new Label();
label.Name = "label"+i;
label.Location = new Point(100, 100 + i * 30);
label.TabIndex = i;
label.Visible = true;
this.Controls.Add(label);
}
private void timer_Tick(object sender, EventArgs e)
{
label.Text = DateTime.Now.ToString();
}
But i don't get any output.What can i do.I use windows application.
I don't see how the Timer's Tick event handler can access a dynamic label that's not in it's scope.
Try
Label label = new Label();
label.Name = "label"+i;
label.Location = new Point(100, 100 + i * 30);
label.TabIndex = i;
label.Visible = true;
Timer timer = new Timer();
timer.Tick += (s, e) => label.Text = DateTime.Now.ToString();
timer.Interval = (1000) * (i);
timer.Enabled = true;
timer.Start();
Another alternative is to have a Dictionary<Timer, Label> and add controls to this dictionary as they are created and in the timer's tick handler use the dictionary to retrieve its corresponding Label
The other way, than Bala R shown to you is keep reference of variable in a dictionary (dict) for timer and label pairs, and access in event handler by sender reference (Full source code, with 2 text boxes ans a button, 2nd textbox contains text "3"), hope it will help:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace ProjectDocumentationWorkspace.UI
{
public partial class MainForm : Form
{
private Dictionary<Timer, Label> dict = new Dictionary<Timer, Label>();
public MainForm()
{
InitializeComponent();
}
private void CreateTimers()
{
string input = textBox2.Text;
int n = Convert.ToInt32(input);
for (int i = 1; i <= n; i++)
{
Timer timer = new Timer();
timer.Tick += new EventHandler(timer_Tick);
timer.Interval = (1000) * (i);
Label label = new Label();
label.Name = "label" + i;
label.Location = new Point(100, 100 + i * 30);
label.TabIndex = i;
label.Visible = true;
this.Controls.Add(label);
dict[timer] = label;
timer.Enabled = true;
timer.Start();
}
}
private void timer_Tick(object sender, EventArgs e)
{
Timer t = (Timer)sender;
DateTime current = DateTime.Now;
dict[t].Text = string.Format("{0:00}:{1:00}:{2:00}", current.Hour, current.Minute, current.Second);
}
private void button1_Click(object sender, EventArgs e)
{
CreateTimers();
}
}
}

Categories

Resources