Introduction
Since I was 17, I've always used an automatic shutdown software to shutdown my PC after a certain amount of time and for different reasons. But now, after I became a senior in college,
I decided to make my own application to do that simple task for me. It is a useful tool that can come handy whenever needed for anybody and anytime.
Background
I have used various techniques in this application that can be useful for beginners and intermediate programmers.
Before I start explaining the parts of the program, you have to know some variables' names and meanings used in the program.
AutoShutDateTime
: a global variable of type
DateTime
that holds the Date and Time of Automatic Shutdown selected by the user.AutoShutTimeSpan
: a global variable of type
TimeSpan
that holds the difference between AutoShutDatTime
and
System.DateTime.No
w.
Now the parts. This application have four parts:
- Selecting the AutoShut Date and/or Time. The application give the user two options to select a time to shut down:
- Shutdown Exactly At: this option, when selected, a
DateTimePicker
will appear next to it, which will be used to set
the AutoShutDateTime
and AutoShutTimeSpan
. AutoShutTimeSpan
will be used to set the interval of a timer that eventually will shutdown the PC when it ticks. Also, two buttons will appear above the
DateTimePicker
, Today and Tomorrow; clicking on Today will set the
DateTimePicker
to System.DateTime.Now
; clicking on Tomorrow will set the
DateTimePicker
to System.DateTime.Now
+ 1 Day. - Shutdown After: this option, when selected, 4 radio buttons and combo boxes will appear next to it; Minutes, Hours, Days, and Weeks. The
AutoShutDateTime
will be calculated by adding the value of one of the combo boxes next to each radio button and
System.DateTime.Now
, like this:
AutoShutDateTime = System.DateTime.Now.AddMinutes(int.Parse(cmbMinutes.Text));
and so on. Then the AutoShutTimeSpan
will be calculated the same way it was
every time, so I figured, let me make a method that will do that every time
I call it. I called it update_timespan(), and this is it's body:
public void update_timespan()
{
AutoShutTimeSpan = AutoShutDateTime - System.DateTime.Now;
}
- After selecting the
DateTime
of AutoShut, the user can choose to set a reminder that reminds him of AutoShut before the AutoShutDateTime
comes.
- Remind Me Before (Minutes): when this option is selected, a combo box will appear next to it, and another option under it (Play a sound).
If this option was selected when the user clicks on AutoShut button, another timer will be created, which holds the same interval value of the first timer minus
the value selected or entered in the combo box next to it.
- Play a sound: this option is used inside the second timer tick event_handler, which shows a messageBox and weather or not to play a sound.
- A Count Down Clock:
The count down clock is a label that is refreshed using a third timer called Clock every time it ticks. I will explain more about it later.
- The buttons. I added 6 buttons to control the program:
- AutoShut: is the button that'll take the user input from the first section, and will act upon it. More on it later.
- Minimize: this button will minimize the form to tray, by resetting the
WindowState
of the form to FormWindowState.Minimized
.
After minimizing either by this button or by the form's button, a frmAutoShut_Resize
event will happen that'll hide the form and show a balloon
tip from the notifyIcon
of the application that says: "AutoShut is still running." - Pause/Resume: this button will pause resume all timers. More on it later.
- Reset: this button will reset everything, and stop all timers.
- Exit: closes the form.
- Shutdown Now!: Will show a confirmation message, that contains two buttons, yes and cancel:
Yes will shutdown the PC, and cancel will close the message and will call the pause button event handler, that will pause the timers if they were open.
- About: the about box is the default about box from Visual C# items.
Using the code
I will go through the code in the same order I went through the parts of the application in the Background section:
- Taking the user input:
it is a series of if and else commands, that'll determine which way the user chose to enter the
AutoShutDateTime
, it is under the AutoShut button event handler (btnStart
).
private void btnStart_Click(object sender, EventArgs e)
{
timer1.Stop();
timer2.Stop();
btnPause.Show();
btnResume.Hide();
if (rdShutdownExactly.Checked)
{
AutoShutDateTime = dateTimePicker1.Value;
update_timespan();
if (AutoShutTimeSpan.TotalMilliseconds <= 0)
{
MessageBox.Show("Invalid Time! \n" +
"Please pick a time after: " + System.DateTime.Now.ToString());
goto flag;
}
timer1.Interval = (int) AutoShutTimeSpan.TotalMilliseconds;
timer1.Enabled = true;
timer1.Start();
}
else if (rdMinutes.Checked && cmbMinutes.Text != "" && !cmbMinutes.Text.Contains('.'))
{
AutoShutDateTime = System.DateTime.Now.AddMinutes(int.Parse(cmbMinutes.Text));
update_timespan();
timer1.Interval = 60000 * int.Parse(cmbMinutes.Text);
timer1.Enabled = true;
timer1.Start();
}
else if (rdHours.Checked && cmbHours.Text != "" && !cmbHours.Text.Contains('.'))
{
AutoShutDateTime = System.DateTime.Now.AddHours(int.Parse(cmbHours.Text));
update_timespan();
timer1.Interval = 3600000 * int.Parse(cmbHours.Text);
timer1.Enabled = true;
timer1.Start();
}
else if (rdDays.Checked && cmbDays.Text != "" &&
!cmbDays.Text.Contains('.'))
{
AutoShutDateTime = System.DateTime.Now.AddDays(int.Parse(cmbDays.Text));
update_timespan();
timer1.Interval = 86400000 * int.Parse(cmbDays.Text);
timer1.Enabled = true;
timer1.Start();
}
else if (rdWeeks.Checked && cmbWeeks.Text != "" && !cmbWeeks.Text.Contains('.'))
{
AutoShutDateTime = System.DateTime.Now.AddDays(int.Parse(cmbWeeks.Text) * 7);
update_timespan();
timer1.Interval = 86400000 * (7 * int.Parse(cmbWeeks.Text));
timer1.Enabled = true;
timer1.Start();
}
else
{
MessageBox.Show("Please Choose a valid AutoShut Time");
goto flag;
}
if (cbRemind.Checked)
{
update_timespan();
if (AutoShutTimeSpan.TotalSeconds <= 60)
MessageBox.Show("Can not set a reminder now!");
else if (cmbRemindMinutes.Text == "")
{
MessageBox.Show("Please choose or enter a value for the reminder");
goto flag;
}
else if (cmbRemindMinutes.Text.Contains('.'))
{
MessageBox.Show("Invalid Reminder");
goto flag;
}
else if (int.Parse(cmbRemindMinutes.Text) >= AutoShutTimeSpan.TotalMinutes)
{
MessageBox.Show("Reminder is set after AutoShut time");
goto flag;
}
else
{
timer2.Enabled = true;
timer2.Interval = timer1.Interval - (60 * 1000 * int.Parse(cmbRemindMinutes.Text));
timer2.Start();
}
}
Clock.Interval = 1;
Clock.Start();
Clock.Tick += new EventHandler(Timer_Tick);
flag: ;
}
This code checks every radio button, if one of them is selected, it enters it's code, I'll go through each if and else in this code:
- "Shutdown Exactly At:" Radio Button: if this radio button was selected, the value of the
dateTimePicker
will be copied to AutShutDateTime
. The
AutoShutTimeSpan
will be calculated by calling the update_timespan()
method I pointed out earlier. Then we check if
AutoShutTimeSpan
is negative or positive, if negative, an error message will show up and the code will not be completed using a flag in the last point of the code; if positive the code will continue. Lastly, it will set the timer interval to the integer value of
totalmilliseconds
of AutoShutTimeSpan
, and start the timer. Then go to the next if, else code. - "Shutdown After:" Radio Button and:
- Minutes: if this radio button was checked AND the Minutes combo box text wasn't empty AND doesn't contain a "." (which means it's not a double), enter the code: first, calculate the
AutoShutDateTime
by adding the parsed text from the combo box to System.DateTime.Now. Update the
AutoShutTimeSpan
. Set the timer's interval and start it. - Hours: same as Minutes code. But we add hours to
AutoShutDateTime
. - Days: same as Minutes code. But we add Days to
AutoShutDateTime
. - Weeks: same as Minutes code. But we add 7 * parsed text from weeks combo box to
AutoShutDateTime
days.
- "Else": in case of errors like no entered data, show an error message and goto flag (exit the code).
- "Remind me before" CheckBox: first thing we update the
AutoShutTimeSpan
; then checks if it is less than 60 seconds: if yes, we show an error message and don't accept it. Then we check if the combo box of the reminder is empty, if yes, we show an error message, and go to flag. Then we check if the value entered is a double, if yes, we show an error message, and goto flag. Then we check if the value entered is bigger than
AutoShutTimeSpan
's total minutes, if yes, we show an error message, and go to flag. if all that wasn't true, we set the second timer and start it. - The count down clock: if everything went right, set the interval of the count down timer "
Clock
" to 1 (millisecond), and start it so it will tick every 1 millisecond.
- Timers.
I used three timers in the application:
- Timer 1
Timer 1 is the timer that will tick when the AutoShutTimeSpan
reaches zero. When this timer ticks, it will stop the timer, and a message (form last_chance_to_cancel)
will show up reminding the user that his computer will shutdown now, it'll last 10 seconds:
if the user responds with OK, the message will disappear and the computer will shutdown immediately using the
System.Diagnostics.Process.Start("shutdown", "/s /t 0 /f");
command, if he pressed on "Cancel AutoShut" before the 10 seconds finishes, the computer will not shutdown,
if he didn't respond at all, the computer will shutdown when the 10 seconds finishes. I used this technique as a caution,
in case the user forgot that he set an AutoShut, the application gives him an opportunity to cancel the AutoShut even if the time finishes.
- Timer 2
Timer 2 is the timer of the reminder, when it ticks, it'll stop the timer, show a message box of how many minutes remaining,
and whether to play a sound or not. Playing a sound requires that you import the
System.Media;
class, after that you can make a SounderPlayer
variable with the path of the sound you want to play, then play it.
SoundPlayer sound1 = new SoundPlayer(@"C:\Windows\Media\notify.wav");
sound1.Play();
- Timer 3: the Count Down Clock
The count down clock is just a label that is refreshed every second or millisecond depending on weather you want to show the milliseconds or not, using a timer.
The idea is every time the timer ticks, you must refresh the label by the time left, as shown in the following code:
public string GetTime()
{
update_timespan();
string TimeInString = "";
int hour = AutoShutTimeSpan.Hours + (24 * AutoShutTimeSpan.Days);
int min = AutoShutTimeSpan.Minutes;
int sec = AutoShutTimeSpan.Seconds;
int miliSec = AutoShutTimeSpan.Milliseconds;
if (AutoShutTimeSpan.Days >= 1)
miliSec = 0;
TimeInString = (hour < 10) ? "0" + hour.ToString() : hour.ToString();
TimeInString += ":" + ((min < 10) ? "0" + min.ToString() : min.ToString());
TimeInString += ":" + ((sec < 10) ? "0" + sec.ToString() : sec.ToString());
TimeInString += ":" + ((miliSec < 10) ? "0" + miliSec.ToString() : miliSec.ToString());
return TimeInString;
}
public void Timer_Tick(object sender, EventArgs eArgs)
{
if (sender == Clock && AutoShutTimeSpan.TotalSeconds > 0)
lbTimer.Text = GetTime();
if (AutoShutTimeSpan.TotalSeconds <= 60)
lbTimer.ForeColor = System.Drawing.Color.Red;
else
lbTimer.ForeColor = System.Drawing.Color.Black;
if (AutoShutTimeSpan.TotalMilliseconds <= 0)
lbTimer.Text = "00:00:00:00";
}
public void update_timespan()
{
AutoShutTimeSpan = AutoShutDateTime - System.DateTime.Now;
}
Using the update_timespan()
method, we can determine the time left to AutoShutDateTime
anytime in our program. So if we used the count down
timer "Clock
", we can call that method every 1 millisecond. Which means we update the countdown label every 1 millisecond by the time left.
That gives us the countdown clock.
I added some optional features and error prevention to it:
- the color of the text will change to red when it reaches the last minute.
- it has to stop updating the time when the
AutoShutTimeSpan
reaches zero or less. - it resets the label to it's default value when
AutoShutTimeSpan
's total milliseconds reaches zero or below, because it takes more than 0 ms to execute the code. - Milliseconds will not be shown if the the
AutoShutTimeSpan
is more than 24 hours.
- Pause and Resume Buttons:
public void btnPause_Click(object sender, EventArgs e)
{
if (AutoShutTimeSpan.TotalMilliseconds > 0)
{
pausetime = System.DateTime.Now;
btnResume.Show();
btnPause.Hide();
timer2WasEnabled = timer2.Enabled;
Clock.Stop();
timer1.Stop();
timer2.Stop();
}
}
private void btnResume_Click(object sender, EventArgs e)
{
btnResume.Hide();
btnPause.Show();
DateTime resumetime;
resumetime = System.DateTime.Now;
TimeSpan pauseDuration = resumetime.Subtract(pausetime);
AutoShutDateTime += pauseDuration;
update_timespan();
int reminderIntervalDifference = timer1.Interval - timer2.Interval;
timer1.Interval = (int) AutoShutTimeSpan.TotalMilliseconds;
if (timer2WasEnabled)
timer2.Interval = timer1.Interval - reminderIntervalDifference;
Clock.Start();
timer1.Start();
if (timer2WasEnabled)
timer2.Start();
}
Note that pausetime
(type DateTime
) and timer2WasEnabled
(type
bool
) is both global variables.
- Pause Button: the pause operation is simple, it works only if
AutoShutTimeSpan
milliseconds has a value greater than 0, which means you can't pause if the timers aren't running. If that's ok, first we capture the time now and store it in
pausetime
, then we hide the pause button, and show the resume button, then we check if Timer 2 (the reminder) is enabled or disabled and store the bool in timer2WasEnabled, then we stop all Timers. - Resume Button: after we pause, the resume button appears. When the user click on it, we must calculate a new
AutoShutDateTime
and AutoShutTimeSpan
using the
pausetime
, resumetime
(type DateTime
), and
pauseDuration
(type TimeSpan
). First we, capture the time when resuming (resumetime
), calculate the
pauseDuration
, by subtracting resumetime
from
pausetime
. Then we add the pauseDuration
to AutoShutDateTime
, and update
AutoShutTimeSpan
by using update_timespan()
I pointed out earlier. This way we have our new
AutoShutDateTime
and AutoShutTimeSpan
. But before we do any changes to the interval of Timer 1, we have to know how
much time was between Timer 1 and Timer 2 set the reminder correctly after that; so we define an integer called
reminderIntervalDifference
and calculate that time difference. After that we are free to update the intervals, first we set the interval of Timer 1, and check weather Timer 2 was enabled before we pause or not (timer2WasEnabled
), if yes, we update Timer 2's interval, otherwise we don't. Finally, we start back all timers, but not Timer 2 if it wasn't running before pause.
Points of Interest
Because this was my first real program in C#, everything I went through while making it was a discovery for me. I liked the language,
and I will try to learn and make more programs with it in the future.