Timer Tick after FormClosing? - c#

Is there any chance that timer_Tick could be called after myForm_FormClosing
in the code below.
If there is a chance: Is it sufficient to call timer.Stop() within myForm_FormClosing in order to avoid that timer_Tick gets called after myForm_FormClosing?
using System;
using System.Windows.Forms;
using System.ComponentModel;
namespace Test
{
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MyForm());
}
}
class MyForm : Form
{
private IContainer components;
private Timer timer;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
public MyForm()
{
components = new Container();
timer = new Timer(components);
timer.Interval = 50;
timer.Tick += timer_Tick;
timer.Enabled = true;
FormClosing += myForm_FormClosing;
}
private void timer_Tick(object sender, EventArgs e)
{
}
private void myForm_FormClosing(object sender, FormClosingEventArgs e)
{
}
}
}
Update:
After receving a few hints (thanks for helping) I basically have chosen the following code to achive what I want.
Please not that timer1_Tick could still be called after myForm_FormClosing was called!
This solution just introduces a flag (i called it doWork) which stops the code within timer1_Tick to be executed after myForm_FormClosing was called.
using System;
using System.Windows.Forms;
using System.ComponentModel;
namespace Test
{
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MyForm());
}
}
class MyForm : Form
{
private IContainer components;
private Timer timer;
private bool doWork = true;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
public MyForm()
{
components = new Container();
timer = new Timer(components);
timer.Interval = 50;
timer.Tick += timer_Tick;
timer.Enabled = true;
FormClosing += myForm_FormClosing;
}
private void timer_Tick(object sender, EventArgs e)
{
if (doWork)
{
//do the work
}
}
private void myForm_FormClosing(object sender, FormClosingEventArgs e)
{
doWork = false;
}
}
}

Yes it is possible. According to the docs ...
Occurs before the form is closed.
When a form is closed, it is disposed, releasing all resources
associated with the form.
The timer will not be disposed until after the FormClosing event. Here is a very contrived example of how it can happen. You will see that you hit the debugger breakpoint on the Timer tick after FormClosing has been called.
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;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Threading;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
private System.Windows.Forms.Timer _time = new System.Windows.Forms.Timer();
private Task _t1 = null;
private Task _t2 = null;
private bool _closingFlag = false;
public Form1()
{
InitializeComponent();
_time.Interval = 50;
_time.Tick += (s, e) => {
textBox1.Text = DateTime.Now.ToString();
if (_closingFlag) Debugger.Break();
};
_time.Start();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
_closingFlag = true;
_t1 = Task.Factory.StartNew(() => { Thread.Sleep(1000); });
_t2 = Task.Factory.StartNew(() => { Thread.Sleep(1000); });
Task.WaitAll(_t1, _t2);
}
}
}

If you use a the timer System.Windows.Forms.Timer the UI thread must be idle to process a tick from the timer, so from my understanding that's is not possible.
Could happen if you use a timer with its own thread, as a System.Timers.Timer. In this case we could avoid what you mention by implementing something like this:
class MyForm : Form
{
private System.Timers.Timer timer;
private Object justForLocking = new Object();
private Boolean safeToProceed = true;
[...]
public MyForm()
{
components = new Container();
timer = new System.Timers.Timer();
timer.Interval = 50;
timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
timer.Start();
FormClosing += myForm_FormClosing;
}
void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
// In case that this code is being executed after
// the method myForm_FormClosing has adquired the
// exclusive lock over our dummy resource,
// the timer thread will wait until the resource if released.
// Once is released, our control flag will be set to false
// and the timer should just return and never execute again.
lock(justForLocking)
{
if (safeToProceed)
{
// Do whatever you want to do at this point
}
}
}
private void myForm_FormClosing(object sender, FormClosingEventArgs e)
{
lock(justForLocking)
{
safeToProceed = false;
}
timer.Stop();
// Do something else
}
[...]
}
This other SO question has relevant information.
EDIT: the code above is only valid if a System.Timers.Timer is used instead of System.Windows.Forms.Timer

I dont believe so but it would be best anyways to call timer.stop() regardless. if you were needing it to though you should create the timer object in program.cs

Related

Hide form when main form run is hide also in start up

I have a small project about manage time use on computer.
Form1:
public partial class Form1 : Form
{
private Timer t = new Timer();
public static int counter = 60;
public Form1()
{
InitializeComponent();
t.Tick += new EventHandler(Timer_Tick);
t.Interval = 1000;
t.Enabled = true;
t.Start();
Form2 TheForm2 = new Form2();
TheForm2.ShowDialog();
}
void Timer_Tick(object sender, EventArgs e)
{
counter -= 1;
if (counter==20)
{
MessageBox.Show("Time remaining "+counter.ToString());
}
}
}
And Form2:
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
int userVal = int.Parse(textBox2.Text);
Form1.counter += userVal;
}
private void textBox2_TextChanged(object sender, EventArgs e)
{
}
private void button2_Click(object sender, EventArgs e)
{
textBox1.Text = Form1.counter.ToString();
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
}
}
Final program:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form1 TheForm = new Form1();
Application.Run();
}
}
I try to make this application run on Windows start up and the Form1 is hide. But I wanna make form2 invisible also. And it just show when user excute the application. How can I solve it?
I just put this exe to folder start up to make it run on start.(I'll try to make it with Registry)
If I understand correctly, you want to control the visibility of one form from another form. To do so, use the .Visible attribute of the form. For example:
public Form1()
{
InitializeComponent();
t.Tick += new EventHandler(Timer_Tick);
t.Interval = 1000;
t.Enabled = true;
t.Start();
Form2 TheForm2 = new Form2();
TheForm2.ShowDialog();
TheForm2.Visible = false;
}
There are other issues with the way you are doing this, but I presume you will sort those out over time, or post other questions :)
Edit:
OK, I have modified your code to demonstrate how to make this work. The code compiles and runs for me, and shows how to make form2 initially invisible, then make it visible after 10 seconds have elapsed.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace TwoForms
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
// If you do it this way you'll have to stop the application yourself
// Form1 TheForm = new Form1();
// Application.Run();
Application.Run(new Form1()); // When Form1 is closed, the application will exit.
}
}
}
Form1:
using System;
using System.Windows.Forms;
namespace TwoForms
{
public partial class Form1 : Form
{
private Timer t = new Timer();
public static int counter = 60;
public Form TheForm2;
public Form1()
{
InitializeComponent();
t.Tick += new EventHandler(Timer_Tick);
t.Interval = 1000;
t.Enabled = true;
t.Start();
this.Show(); // show Form1 just so we know it's really there
TheForm2 = new Form2();
// TheForm2.ShowDialog(); // Don't do this unless you really want a modal dialog
TheForm2.Show();
TheForm2.Visible = false; // A timer tick will later set visible true
}
void Timer_Tick(object sender, EventArgs e)
{
counter -= 1;
if (counter == 50)
TheForm2.Visible = true;
if (counter == 40)
MessageBox.Show("Time remaining " + counter.ToString());
}
}
}
Form2:
using System;
using System.Windows.Forms;
namespace TwoForms
{
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
int userVal = int.Parse(textBox2.Text);
Form1.counter += userVal;
}
private void textBox2_TextChanged(object sender, EventArgs e)
{
}
private void button2_Click(object sender, EventArgs e)
{
textBox1.Text = Form1.counter.ToString();
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
}
}
}

sending context of form to other class

hi, i have send form context to another class to run function there, but the fun show out the messagebox but not update form text , why ?
i need the function start to update form title
i sending form context to timer class as parameter
the function start work in interval but the method cant update the
form control
this is form class
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication8
{
public partial class Form1 : Form
{
public Form1()
{
//form constractor
InitializeComponent();
}
timer mytimer;
private void Form1_Load(object sender, EventArgs e)
{
}
private void Elipse()
{ //the code for timer :) //yazeed coding
//MessageBox.Show(" ");
this.Text=" jkghjg";
}
private void button1_Click(object sender, EventArgs e)
{
mytimer = new timer();
mytimer.elipse += Elipse;
mytimer.Interval = 1000;
mytimer.start(this);
}
}
}
this is timer class
class timer
{
bool isstart;
public delegate void Del();
public Del elipse;
public static void UserRep() { }
public bool Enable { get; set; }
public int Interval { get; set; }
public timer()
{
Enable = false;
Interval = 1000;//default is 1 sec
isstart = false;
elipse = new Del(UserRep);
}
public void start(Form Context)
{
Context.BeginInvoke((MethodInvoker)async delegate
{
Enable = true;
isstart = true;
do
{
await Task.Delay(Interval);
new Thread(() =>
{
elipse(); //the replacment running now (interface thrad protected)
}).Start();
}
while (isstart);
Enable = false;
});
}
public void stop()
{
isstart = false;
}
}
AND thanks
As you are starting a new thread, you need to call elipse in the Form context:
Replace:
new Thread(() =>
{
elipse();
}).Start();
with
new Thread(() =>
{
Context.BeginInvoke(elipse);
}).Start();
Thanks Robert, good improvement , the code running successfully i add the post to see what others say, for code correct :) i keep this method like this for other developer to understand that they can add more code here
i find lot of post that they use long code to perform small task,
here is light code for many methods used in many project and helpful
this code is same as Microsoft timer implemented by me
here it is
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication8
{
public partial class Form1 : Form
{
public Form1()
{
//form constractor
InitializeComponent();
}
timer mytimer;
private void Form1_Load(object sender, EventArgs e)
{
//perform event click for button automaticly
button1.PerformClick();
}
private void Elipse()
{
//the code for timer :) //yazeed coding ,,,, write any other code
new Thread(() => MessageBox.Show("Successful")).Start();
Text = DateTime.Now.TimeOfDay.Seconds.ToString();
}
private void button1_Click(object sender, EventArgs e)
{
mytimer = new timer();
mytimer.elipse += Elipse;
mytimer.Interval = 1000;
mytimer.Enable = true;
mytimer.start(this);
}
}
}
class timer
{
bool isstart;
internal delegate void Del();
internal Del elipse;
static void UserRep() { }
internal bool Enable { get; set; }
internal int Interval { get; set; }
internal timer(int val=100)
{
Enable = false;
Interval = val>0?val:100;//default is 1 sec
isstart = false;
elipse = new Del(UserRep);
}
internal void start(Form Context)
{
new Thread(async () =>
{
isstart = true;
do
{
await Task.Delay(Interval);
new Thread(() => Context.BeginInvoke((MethodInvoker)delegate
{
elipse(); //the replacment running now (interface thrad protected)
})).Start();
}
while (isstart);
}).Start();
}
internal void stop()
{
isstart = false;
}
}

My Timer won't tick c#

My timer won't tick, I've tried with printing to check if the timer is started, it starts but it never ticks.
Here's the code:
public Form1()
{
InitializeComponent();
this.DoubleBuffered = true;
timer = new Timer();
timer.Enabled = true;
timer.Interval = 50;
timer.Tick += new EventHandler(timer_Tick);
//Console.WriteLine("STARTING TIMER");
timer.Start();
NewFile();
}
private void timer_Tick(object sender, EventArgs e)
{
MessageBox.Show("TIMER TICKS");
doc.MoveBalls(leftX, topY, width, height);
doc.CheckCollision();
Invalidate(true);
Console.WriteLine("Moving2");
}
Apart from the answers given above, you may also use a thread of Timer which takes callback and a state object to keep your working thread safe like below
After you include the library before your namespace
using System.Threading;
// your namespace
private readonly TimeSpan _updateInterval = TimeSpan.FromSeconds(10);
private Timer _timer = new Timer(CallBakFunction, null, _updateInterval, _updateInterval);
private void CallBakFunction(object state)
{
}
In your case, this can be done as follows:
private readonly TimeSpan _updateInterval = TimeSpan.FromSeconds(10);
private Timer _timer ;
public Form1()
{
InitializeComponent();
this.DoubleBuffered = true;
_timer = new Timer(timer_Tick, null, _updateInterval, _updateInterval);
NewFile();
}
private void timer_Tick(object state)
{
MessageBox.Show("TIMER TICKS");
doc.MoveBalls(leftX, topY, width, height);
doc.CheckCollision();
Invalidate(true);
Console.WriteLine("Moving2");
}
I have updated a final result video for your assistance please view this:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
private readonly TimeSpan _updateInterval = TimeSpan.FromSeconds(1);
private System.Threading.Timer _timer;
public Form1()
{
InitializeComponent(); this.DoubleBuffered = true;
_timer = new System.Threading.Timer(timer_Tick, null, _updateInterval, _updateInterval);
NewFile();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void NewFile() { }
private void timer_Tick(object state)
{
MessageBox.Show("TIMER TICKS");
//doc.MoveBalls(leftX, topY, width, height);
//doc.CheckCollision();
//Invalidate(true);
Console.WriteLine("Moving2");
}
}
}
You enabled the timer before you attach the OnTick event. Setting Enabled to true is basically the same as timer.Start(). Remove the Enabled assignment, or replace the Start() call with it.
Use System.Windows.Forms.Timer to work with winform
public Form1()
{
InitializeComponent();
this.DoubleBuffered = true;
System.Windows.Forms.Timer timer = new Timer();
timer.Enabled = true;
timer.Interval = 50;
timer.Tick += new EventHandler(timer_Tick);
//Console.WriteLine("STARTING TIMER");
timer.Start();
}

Rerun method as soon as it has finished

Right now I'm using a timer to trigger my method. But how can I make the service run my method as soon as it has finished?
private Timer timer;
public Service()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
DoSomething();
timer = new Timer();
timer.Enabled = true;
timer.Interval = 60000;
timer.AutoReset = true;
timer.Start();
timer.Elapsed += timer_Elapsed;
}
protected override void OnStop()
{
base.OnStop();
}
private void timer_Elapsed(object sender, ElapsedEventArgs e)
{
DoSomething();
}
Get rid of the timer and use recursion:
public Service()
{
InitializeComponent();
DoSomething();
}
private void DoSomething()
{
// some code that takes a while to execute
// make recursive call to self
DoSomething();
}
EDIT The answer as accepted won't work in the context of a service (actually, it will execute, but the service itself will be forever stuck in 'Starting' status, and will generate a 1503 error).
Here is the full code for a service that will continuously execute a method:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
namespace recursion
{
public partial class Service1 : ServiceBase
{
public Service1()
{
InitializeComponent();
}
System.Threading.Thread thread;
protected override void OnStart(string[] args)
{
System.IO.File.WriteAllText(#"C:\Temp\Foo.txt", "Starting at: " + System.DateTime.Now.ToString());
thread = new System.Threading.Thread(DoSomething);
thread.Name = "Worker Thread";
thread.IsBackground = true;
thread.Start();
}
private void DoSomething() {
while (true)
{
System.IO.File.WriteAllText(#"C:\Temp\Foo.txt", "The Time is now: " + System.DateTime.Now.ToString());
System.Threading.Thread.Sleep(1000);
}
}
protected override void OnStop()
{
}
}
}
#cslecours you were wrong that it would cause a StackOverflow, but you were right in that causing the OnStart method not to exit would cause and error for a Windows service.
Use a Thread and an infinite while loop.
private void Start()
{
while(true)
DoSomething();
}
protected override void OnStart(string[] args)
{
Task.Factory.StartNew(() => Start());
}

How can I multithread (effectively) on Windows Forms?

This one is giving me a hard time.
The thing is that I have a code that plays some notes in MIDI, and I wanted to be able to pause it, so I made a simple Form like this:
namespace Music
{
public partial class Form1 : Form
{
static BackgroundWorker _bw = new BackgroundWorker
{
WorkerSupportsCancellation = true
};
private void button1_Click(object sender, EventArgs e)
{
if (!Playing)
{
Playing = true;
_bw.DoWork += Start_Playing;
_bw.RunWorkerAsync("Hello to worker");
}
else
{
Playing = false;
_bw.CancelAsync();
}
}
static void Start_Playing(object sender, DoWorkEventArgs e)
{
//Plays some music
}
}
}
And when I click it starts playing, but no matter what I do, it can't stop. But the thing is that if I do the same thing in the console it works perfect.
Did I miss something?
How can I control a separate thread from the form?
This seems to work...
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;
using System.Threading;
namespace WindowsFormsApplication2
{
public partial class Form1 : Form
{
private BackgroundWorker _bw = new BackgroundWorker { WorkerSupportsCancellation = true,
WorkerReportsProgress = true};
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
if (_bw.IsBusy)
{
_bw.CancelAsync();
}
else
{
_bw.ProgressChanged += new ProgressChangedEventHandler(_bw_ProgressChanged);
_bw.DoWork += new DoWorkEventHandler(_bw_DoWork);
_bw.RunWorkerAsync();
}
}
void _bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
textBox1.Text += (string)e.UserState;
}
void _bw_DoWork(object sender, DoWorkEventArgs e)
{
int count = 0;
while (!_bw.CancellationPending)
{
_bw.ReportProgress(0, string.Format("worker working {0}", count));
++count;
Thread.Sleep(2000);
}
}
}
}

Categories