Click here to Skip to main content
15,867,453 members
Articles / Desktop Programming / WPF
Tip/Trick

WPF Timer Behavior

Rate me:
Please Sign up or sign in to vote.
4.18/5 (7 votes)
18 Mar 2016CPOL2 min read 10.7K   74   5   2
There may be times when it would be nice to have a timer on a window. This is a behavior that when attached to a TextBlock, will display the time in minutes and seconds since the control was created.

Introduction

I wanted to put a simple timer on a window that is displayed when the system is busy. It seemed to me that this really did not belong in the ViewModel, and seemed like it should not use code-behind. The solution was this behavior.

The Dependency Property

This behaviour has really two parts.

The static part is two DependencyPropertys, a public IsEnabled DependencyProperty to enable the timer, and a private TimerBehaviour DependencyProperty to save an instance of the class.

C#
public static readonly DependencyProperty IsEnabledProperty =
  DependencyProperty.RegisterAttached("IsEnabled", typeof(bool),
  typeof(TimerBehaviour), new UIPropertyMetadata(false, OnValueChanged));

public static bool GetIsEnabled(FrameworkElement o) { return (bool)o.GetValue(IsEnabledProperty); }
public static void SetIsEnabled(FrameworkElement o, bool value) { o.SetValue(IsEnabledProperty, value); }

private static readonly DependencyProperty TimerBehaviourProperty =
DependencyProperty.RegisterAttached("TimerBehaviour", typeof(TimerBehaviour),
typeof(TimerBehaviour), new UIPropertyMetadata(null));

private static TimerBehaviour GetTimerBehaviour(FrameworkElement o)
   { return (TimerBehaviour)o.GetValue(TimerBehaviourProperty); }
private static void SetTimerBehaviour(FrameworkElement o, TimerBehaviour value)
   { o.SetValue(TimerBehaviourProperty, value); }

private static void OnValueChanged(DependencyObject dependencyObject,
  DependencyPropertyChangedEventArgs e)
{
 var frameworkElement = dependencyObject as FrameworkElement;
 if (frameworkElement == null) return;
 if (e.NewValue is bool && (bool)e.NewValue)
 {
  SetTimerBehaviour(frameworkElement, new TimerBehaviour(frameworkElement));
 }
 else
 {
  GetTimerBehaviour(frameworkElement).Dispose();
  SetTimerBehaviour(frameworkElement, null);
 }
}

Only the IsEnabled DependencyProperty has an event handler which creates a new instance of the TimerBehaviour class and saves it in the TimerBehaviour DependencyProperty when IsEnabled is set to true.

The non-static part of the class has a constructor that saves information about the FrameworkElement to which this DependencyProperty is attached, creates a new DispatcherTimer instance that will trigger every second and call the event handler, SecondEvent, and saves the current time, which is used to determine the elapsed time. It then starts the DispatcherTimer.

C#
private readonly DateTime _startTime;
 private readonly FrameworkElement _frameworkElement;
 private readonly DispatcherTimer _timer;

 public TimerBehaviour(FrameworkElement frameworkElement)
 {
  _frameworkElement = frameworkElement;
  _startTime = DateTime.Now;
  _timer = new DispatcherTimer(new TimeSpan(0, 0, 1), DispatcherPriority.Render,
           SecondEvent, frameworkElement.Dispatcher);
  _timer.Start();
  SecondEvent(_timer, new EventArgs());
 }

 private void SecondEvent(object sender, EventArgs e)
 {
  var timerString = DateTime.Now.Subtract(_startTime).ToString("mm\\:ss");
  if (_frameworkElement is TextBlock)
   ((TextBlock)_frameworkElement).Text = timerString;
 }

The SecondEvent event handler then subtracts the saved time from the current time, and, if the FrameworkElement is a TextBlock, will set the Text property of the TextBlock to the elapsed time in minutes and seconds.

Using the Code

All that needs to be done is to include a TextBlock in the XAML file, and then include the TimerBehaviour and set its IsEnabled property to true:

XML
<TextBlock local:TimerBehaviour.IsEnabled="True" />

Conclusion

This behaviour allows a timer to easily be added to any WPF form by only adding a TextBox and attaching this behaviour.

I can easily see where this can be enhanced, and also see where it might be modified to display just the time of day, which actually may be more useful considering that there is more need to display the time than just a timer. I could also add the ability to reset the timer, or allow flexibility of display.

History

  • 03/18/2016: Initial version
  • 03/22/2016: Updated code to show zero time when initialized
  • 09/13/2017: Fixed bugs when cursor is at last position

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Clifford Nelson Consulting
United States United States
Has been working as a C# developer on contract for the last several years, including 3 years at Microsoft. Previously worked with Visual Basic and Microsoft Access VBA, and have developed code for Word, Excel and Outlook. Started working with WPF in 2007 when part of the Microsoft WPF team. For the last eight years has been working primarily as a senior WPF/C# and Silverlight/C# developer. Currently working as WPF developer with BioNano Genomics in San Diego, CA redesigning their UI for their camera system. he can be reached at qck1@hotmail.com.

Comments and Discussions

 
BugCan't download attached demo Pin
LinRaise25-Oct-19 22:36
LinRaise25-Oct-19 22:36 
QuestionProblems with downloading sample Pin
Medtronic WPF Developer30-Apr-18 13:30
Medtronic WPF Developer30-Apr-18 13:30 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.