var startTime = DateTime.Now;
var timer = new Timer() { Interval = 1000 };
timer.Tick += (obj, args) =>
label14.Text =
(TimeSpan.FromMinutes(Convert.ToDouble( comboBox3.Text)*60) - (DateTime.Now - startTime))
.ToString("hh\\:mm\\:ss");
MessageBox.Show("Timer started");
timer.Enabled = true;
im strating a timer in a specific form when pressing a button, i want the timer to continue counting time after closing the form in order to give me a notification.
but when closing the form the timer stops,
any ideas?
You can't "Close" the form and have the Timer object still work (if you're calling the timer on the main form). (That's like saying I can't click the button and have a function run after closing the form). However, on the OnFormClosing argument, you could have the form.Visible = false and cancel the actual closing of the form. See here: Timer doesn't fire after Form closed
If you want to truly close the form and have it run, one option could be to look at possibly creating a Task Scheduler object that would complete the task at a certain time.
A quick hit: call "Hide()" instead - that will keep the timer running.
Now that's out the way, You can still make your timer static - ideally put it in a completely separate class, or, if you insist, make it static on your main form. Then have your notification code sit on your main form.
You can still add a listener to the Tick event on that specific form and just remember to remove it when you hide the form (i.e. Tick -= your_label_event_handler)
Related
My goal is to make a desktop pet. I've already programmed a lot of logic that executes in a while loop and updates every iteration. To display the creature I'm looking to use windows forms, but that has brought up a dilemma.
I want to be able to execute the logic, and then update the window in the same loop (process events and redraw), without having to deal with Application.Run() or multi threading. As an example, and as someone who's come from python, using tkinter it's possible to call the update() method on a window in a loop, which is essentially the same as calling mainloop() once, except it doesn't block the program.
Do forms offer any similar functionality?
As Scott Chamberlain mentioned, you should use a timer to run your 'loop'. Winforms is event based so adding an infinite loop will freeze the program since events are blocked.
This code illustrates how to use a timer. I added a picture box to the form and it moves across the screen as the timer fires.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Timer tmr = new Timer();
tmr.Interval = 50; // milliseconds
tmr.Tick += Tmr_Tick; // set handler
tmr.Start();
}
private void Tmr_Tick(object sender, EventArgs e) //run this logic each timer tick
{
pictureBox1.Left += 1; // move image across screen, picture box is control so no repaint needed
}
}
So I have an app that on a button press: starts a timer, cycles through one (++) piece of data and hides the start button and instead shows a stop and next button.
I have looked into messaging center and I thought it was fixing the problem (here's the link Xamarin.Forms how do I access a public function from another CS file?) but it didn't fix the problem completely.
If the app has the timer running (aka you hit the start button) and then interrupt the process by hitting the home button on your phone, the app works fine and the app hides the stop/next buttons and shows the start button and stops the timer. If you haven't started the process at all (aka you haven't hit the start button) and you hit the home button on your phone the app throws an exception error because what I'm changing with messaging center "doesn't need changing because it never changed". Is there a better way to handle this situation?
Can I use if/else statements in app state with messagingcenter?? I'm stuck.
App.xaml.cs
protected override void OnSleep()
{
// Handle when your app sleeps
Debug.WriteLine("~~~~~~~~~~~~~~OnSleep~~~~~~~~~~~~~");
MessagingCenter.Send<App>(this, "OnSleep");
}
MainPage.xaml.cs
MessagingCenter.Subscribe<App>(this, "OnSleep", (sender) => {
//shows start button instead of stop button
StartGrid.IsVisible = true;
//hides stop button
StopNextGrid.IsVisible = false;
//stops timer
timer.Stop();
timer = null;
//stops sound
startSound.Stop();
stopSound.Play();
});
Just can see the partial code,you should check if your timer is initialized before executing the method.
When you do not click the start button, you need to check whether the timer is initialized, in order to perform the following timer operation.
If no want to know whether timer is initialized. You can try this:
Modify in your notification handling method.If the state of your timer and button has not changed, you don't need to do anything in the notification.Here I use the timer as a judgment.
MessagingCenter.Subscribe<App>(this, "OnSleep", (sender) => {
//shows start button instead of stop button
if (null != timer)
{
StartGrid.IsVisible = true;
//hides stop button
StopNextGrid.IsVisible = false;
//stops timer
timer.Stop();
timer = null;
//stops sound
startSound.Stop();
stopSound.Play();
}
});
this is my first time posting, but I was wondering how i can get a timer to increment once i start my program. I have the timer and the stop button, and i can get it to start if i have a start button to press, but i want it to start once the application is opened as there are multiple timers one after another in the game i'm making. thanks everyone. i tried searching this, but couldn't find anything. I'm still pretty new to app programming so it's not something i have done before and don't even know what to try for it.
Welcome,
I would suggest to locate the FormLoad eventhandler (either by double clicking the form or by looking in the properties window (look for the lightening icon) and search for the Load eventhandler.
Or you could try to use the FormShown eventhandler, which will be triggered when the form is actually shown instead of loaded. Depending on what you are trying to achieve, this might be a better option.
Either way, you will need to put
Timer.Start()
inside such an event handler.
Hope it helps.
In Form's Load event (doubleclick on form) you can use
timer1.Start();
You can start a timer by simply calling Timer.Start()
When to call this depends on the trigger. Typically you write this in an event handler, of the "button click event" like you mention, or the app's "app start event" such as the Main method, but this depends on what kind of app (WinForms?) you are writing.
You can start timer on starting the program either by starting the timer in the following way:
public Form1()
{
InitializeComponent();
time.Start();
time.Tick += time_Tick;
}
or by initiating the timer in Form Load Event Handler
I am trying to create a windows form that gets displayed for 2 seconds when triggerd by an event, and then closes automatically.
I have tried several options. This is my current code:
this.aletPopup.StartPosition = FormStartPosition.CenterScreen;
this.aletPopup.Show();
Thread.Sleep(2000);
this.aletPopup.Close();
This preforms the actions that I desire, however, when the form loads it does not load the label or image which is on the form. Instead, the area where the image and label are become transparent. My desired output is this:
I have also tried using this.aletPopup.ShowDialog();, which does display the graphics. However, the form will not close automatically when using this method.
EDIT: I am attempting to use
Michael Perrenoud's solution. However, I cannot get the form to close. I have a timer set at a 2000ms interval which is initally disabled. Am I overriding the OnShown correctly?
public AlertPopForm()
{
InitializeComponent();
}
private void closingTimer_Tick(object sender, EventArgs e)
{
closingTimer.Enabled = false;
this.Close();
}
private void AlertPopForm_OnShown(object sender, System.EventArgs e)
{
closingTimer.Enabled = true;
closingTimer.Start();
}
Instead, how about leveraging ShowDialog, and then using a Timer on the dialog form. In the Tick event of the Timer, close the form.
this.aletPopup.StartPosition = FormStartPosition.CenterScreen;
this.aletPopup.ShowDialog();
You could even pass the interval into the .ctor of the dialog form if you wanted some flexibility.
It's very important to note here that you'd need to leverage the OnShown override to actually Start the Timer so the form is in fact shown to the user.
The reason can be in Message Loop. When you block your thread by Thread.Sleep, it also blocks Message loop.
You can make like this:
this.aletPopup.StartPosition = FormStartPosition.CenterScreen;
this.aletPopup.Show();
for(var i = 0; i<= 200; i++)
{
Thread.Sleep(10);
Application.DoEvents();
}
this.aletPopup.Close();
DoEvents will process messages from message queue during that time.
When calling Thread.Sleep you're blocking the UI thread, thus preventing it from processing UI events.
You need to ensure that Close is called after 2 seconds without actually blocking the main thread. There are a number of ways of doing this, such as using a Timer, or something like Task.Delay:
aletPopup.StartPosition = FormStartPosition.CenterScreen;
aletPopup.Show();
Task.Delay(TimeSpan.FromSeconds(2))
.ContinueWith(t => aletPopup.Close(),
TaskScheduler.FromCurrentSynchronizationContext());
The reason this is happening, is that you are halting the thread that draws the form. So the form has time to display, but as it's being drawn, the thread is being stopped.
Easy enough to fix....
Add an event handler to the popup for the Load event with the following handler:
private async void handleLoad(Object sender, EventArgs args)
{
await Task.Delay(2000);
Close();
}
Remark
Because you used Show(), the user could always click around this popup. If this is undesirable, then use ShowDialog() instead.
Did you try a refresh to redraw the form?
this.aletPopup.StartPosition = FormStartPosition.CenterScreen;
this.aletPopup.Show();
this.alertPopup.Refresh();
Thread.Sleep(2000);
this.aletPopup.Close();
In the UI thread I have a piece of code that goes like this:
SomeForm form = new SomeForm();
(...)
form.Show();
SomeForm class particularly has a System.Windows.Forms.Timer instance as a member that is being initialized by auto-generated code of InitializeComponent() that looks like this:
this.UploadStatusTimer.Enabled = true;
this.UploadStatusTimer.Interval = 1000;
this.UploadStatusTimer.Tick += new System.EventHandler(this.UploadStatusTimer_Tick);
form.Show() will in the end raise Form.Load event that is being handled by SomeForm_Load(object sender, EventArgs e).
My question is: is there a possibility that UploadStatusTime_Tick was being processed before SomeForm_Load?
InitializeComponent() is called by the constructor of the Form, so it is possible that UloadStatusTimer_Tick is already called, before you call form.Show().
If you want the timer to start after you call form.Show(), set UploadStatusTimer.Enabled = false in the designer, override OnShow and use this method to set this.UploadStatusTimer.Enabled = true.
What you are asking is "can it take longer than one second from the time I construct my form for the Load event to fire?"
Beyond the theoretical answer of "yes, this is always possible" it really comes down to how long (...) takes in your example code. The timer is going to start counting down as soon as Enabled is set to true (when it is constructed).
It's important to note that UI interactions are processed via a message pump. So thinking of the winforms timer, the timer itself is off running in the background (outside of .net even; it is using the native windows timer) and when the timer expires it sends a message to your application, which then queues a message on the message pump that says "hey, timer tick happened." Same thing applies to your form load event, it is triggered via a message on the message pump. So if the timer expires before the form "loads" then the timer message will be in front of the 'form load' message on the queue and get processed first.
If you're interested in learning more, there many articles or stack overflow questions on the winforms message pump (or message loop as some may call it).
To ensure that the timer does NOT go off before Form_Load, disable it in the designer and call timer.Start(); in the Form_Load event.
To ensure that it does go off before Form_Load, move the code in the timer_Tick function to a central method and call that from the constructor.