Another excellent tool to enhance your UX are events triggered by time. These can give your software a greater
sense of sentience and promote proactive engagement with the user. You can also use this for specific time
sensitive events to occur. One example of this came to me recently when I was trying to buy movie tickets
online to see Deadpool 2 (
way to date when you wrote these notes, Daniel...). Once seats in the
theater were selected, there was a limited amount of time to complete the purchase, before the server terminated the
transaction and re-opened those seats for reservation. This could be trivially accomplished using a
System.Windows.Forms.Timer that would be initialized to 0 when the "Enter Purchase
Information Here" form was presented, then triggered when X number of seconds had elasped, automatically loading
up the "Sorry, you took too long!" page.
It's important to distinguish between
System.Windows.Forms.Timer and
System.Timers.Timer, which not only share a similar name — love that... — but have a critically
different implementation. The SWFT version attaches itself to your Form, allowing you access to your components
and methods defined within your Form1 class, while the STT version is statically allocated and therefore requires
some trickery to interact with your Form — if it can at all. Visual Studio 2017 allowed me to use the STT
version in the past, which was great because of the addition of the
ElapsedEventArgs
for exam questions, but I believe 2019 put it's foot down and declared this to be "cross-thread hazardous". So I'm
updating these notes accordingly, while keeping the other version for posterity.
Here's a simple example of how to update a
Label every second.
public static System.Windows.Forms.Timer myTimer;
public static int counter = 0;
public Form1()
{
InitializeComponent();
myTimer = new System.Windows.Forms.Timer(); // Interval set to 10 seconds
myTimer.Enabled = true;
myTimer.Interval = 1000; // measured in milliseconds
myTimer.Tick += new EventHandler(UpdateLabel);
}
private void UpdateLabel(object source, EventArgs args)
{
Time_Label.Text = "Counter == " + ++counter;
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
myTimer.Dispose();
}
There's also the
StopWatch class, whose objects are used to function very much like
like the stop watches of the physical world. You create a
StopWatch object, call
the
Start() method, followed by
Stop(), then measure the
Properties of the
StopWatch such as
public TimeSpan Elapsed,
where
TimeSpan has Days, Hours, Minutes, and Seconds Properties, and
public long ElapsedMilliseconds, to simply get the number of milliseconds recorded.
There's also a
public bool IsRunning Property.
Previously
The data available from
MouseEventArgs and
ElapsedEventArgs
together could draw a detailed recreation of user interactions with software, perhaps in an effort to determine
where improvements to the UI could be made so users more easily find what they're looking for... but also to
gather data points about you that can be fed into prediction software to determine what kind of products you're
going to want to buy from Amazon at 11:25pm on a Friday night, after you've spent 20+ minutes looking through
your ex's profile on Facebook. </tinfoil hat>. (... But is it
really too crazy to think that
this is happening to us online?)
Let's shift gears and look at the actual implementation of these timed events, starting with a
Timer. These objects tick in real time, measured by milliseconds, and broadcast an
Elapsed event once the number of measured ticks reaches a programmer-defined
Interval, a
double property of
Timers. You can configure the
Time to trigger this event only the first
time this
Interval has been reached, or have it reset and repeat it for every
Interval number of milliseconds have passed. You will want to
Dispose of
Timers once you finish with them, either by calling the method
directly inside of a try/catch block, or by using the...
using mechanism.
public static void Main()
{
private static void MyTimedEvent(object source, ElapsedEventArgs args)
{
Console.WriteLine("Another 10000 milliseconds have elapsed at {0:HH:mm:ss.fff}", arg.SignalTime);
}
using (Timer myTimer = new Timer(10000)) // Interval set to 10 seconds
{
myTimer.Elapsed += MyTimedEvent;
myTimer.AutoReset = true; // Makes it repeat
myTimer.Enabled = true;
string slacker;
while (slacker != "q")
{
Console.WriteLine("\nEnter 'q' to quit the application: ");
slacker = Console.ReadLine();
}
}
}