A WPF/MVVM Countdown Timer

Source: Internet
Author: User

Introduction

This article describes the construction of a countdown timer application written in C # and WPF, using Laurent bugnion ' S mvvmlight Toolkit. This article was based on the work of some previous articles I ' ve written:

    • A WPF Short TimeSpan Custom Control
    • A WPF Spinner Custom Control
    • A XAML only Font ComboBox
    • Mvvmlight Using the

As usual most of the code shown in this article is elided, particularly since No-one likes scrolling through five screens Worth of XAML to see one line of interest. Download the source zip file to see the whole thing.

This is written, and more importantly, tested, in a Windows 7, 64-bit box, but uses the. NET 4.0 framework, so should ' Ju St Work '!

Requirements and Features

The countdown Timer is going to being relatively simple:

    • The starting time can be chosen by the user.
    • Notify the user visually (in the Application and task bar) and audibly.
    • The application has settings, the user can change.
    • The Windows 7 taskbar icon shows the progress of the timer.

The original motivation for this is that I came across the Pomodoro technique whilst browsing the web and thought it Woul D is fun-to-write a countdown timer that could is used for this. It is, in short, a ' getting things do ' idea which can boiled down to:

    • Work for minutes
    • Break for 5 minutes
    • Repeat

So I decided then the default setting for the timer was minutes, and that it should record the number of completed count Downs unobtrusively, should someone wish to use this application in the that.

Choosing the underlying Timer

We Use the WPF to DispatchTimer perform a count. We is not a making any guarantees about the accuracy of the timer.

In fact neither does the documentation:

Timers is guaranteed to execute exactly when the time is interval occurs, but they is guaranteed to not execute before The time interval occurs. This is because DispatcherTimer operations was placed on the Dispatcher queue like other operations. When the operation executes was dependent on the other jobs in the DispatcherTimer queue and their priorities.

By leveraging the. NET Framework, we use a This TimeSpan allows us to increment, and importantly, decrement by a specified AM Ount. We then simply decrement our starting value every time DispatchTimer the ticks, until we get a negative TimeSpan , and then we stop.

The code is written in such a, the is TimerModel just a concrete implementation of and the ITimerModel concrete instantiation Of an are ITimerModel generated from a single factory method:in other words, you could write your own derived ITimerModel class Inste AD and update the factory method as required (e.g., use System.Threading.Timer instead).

MVVM

Since This is a WPF application, we'll use the MVVM pattern to layout the code.

What does this mean? The application is divided into:

    • Views-xaml-only layouts that the application uses:i.e., the GUI and all its windows!
    • Viewmodels-translate the data between the views and the Models.
    • Models-the actual code that does the work (and everything else).

If you find this confusing or want to know more, please see another of my articles: wpf/mvvm Quick Start Tutorial .

Application Settings

All applications has settings and this one are no different:to persist the application ' s settings, we take advantage of T He class System.Configuration.ApplicationSettingsBase . This was subclassed for the WPF application if you create it, so can then just address the application settings p Rogrammatically, for example:

Hide Copy Code
_timer. Duration = Properties.Settings.Default.Duration;

Where we have created a property Duration .

Timer ITimerModel in the same to that we hide the implementation of the behind a interface and we also use an interface called , and use a concrete instance called SettingsModel , along with a builder method to retrieve an instance of the class. This gives us the option, as-before, to-change the settings backing store, to something else in the future (INI file Anyon E?).

Updating Settings between Application Versions

To cater-the application, we can use the following method:define with our UpgradeRequired settings, and set to True B Y default. We then use:

Hide Copy Code
if (Properties.Settings.Default.UpgradeRequired) {  Properties.Settings.Default.Upgrade ();  false;  Properties.Settings.Default.Save ();}

The upgrade of the application settings only when the flag is UpgradeRequired true . For newly versioned assemblies, all settings take their default values, this code was triggered, and the settings are Copie D from a previous application version, if it exists, to the new one.

It is worth noting the-for-this ' trick-to-work, I-need to-define this field in your application settings in The very first version of your application.

The views and ViewModels

The application have several views that is all UserControl s and hosted in the MainWindow . This means no pop-up dialogs! They is:

    • The mainTimerView
    • TheSettingsView
    • TheAboutView

With the corresponding ViewModels:

    • TheTimerViewModel
    • TheSettingsViewModel
    • TheAboutViewModel
changing views and Messaging

As we want to use ' separation of the concerns ', or ' encapsulation ' (if you prefer), we don't want view-models to communicate Directly. In order to do the, we simply use message passing, in other words:

The Mvvmlight Toolkit provides us with a singleton Messenger class so we can register message consumers and message producer S with. So-raise an ' event ' in one view model from another, we simple pass a-message, for example:

Hide Copy Code
Class mainviewmodel:viewmodelbase{public    Mainviewmodel ()    {        //  Lastly, listen for Messages from the other view models.        Messenger.default.register<simplemessage> (// ...}     }}

And in the TimerViewModel :

Hide Copy Code
Class timerviewmodel:viewmodelbase{    void OnTick (object sender, Timermodeleventargs e)    {        Messenger.Default.Send (new Simplemessage (Messagetype.timertick, Timervalue));}}  

What's this achieves TimerViewModel are as follows:the updates TimerView the countdown clock in the main window ' s ContentControl , but we want to Update the window ' s title to also show the countdown. The main window is View bound MainViewModel -the, so-to-do-, and to keep the view-models separate, we pass a message cont Aining the time remaining. The reason we update the window title bar is discussed a little later.

The taskbar Preview and the Window Title

As can see in this screenshot:

The countdown value is shown in the taskbar item thumbnail, and in the main window ' s title. The reason we update the window's title is this when a window is minimzed, the taskbar item thumbnail are not UPDA Ted by Windows, so if you were to hover your mouse pointer over the icon on the task bar when the item is minimized, the T Humbnail Preview would display the countdown at the time you minimized the window. Fortunately, the title of the window is updated on the thumbnail preview, so we ensure that we update this to Pro Vide a visual clue to the user.

Taskbar Messages

We need a second message type to communicate task bar progress updates in Windows 7:since the MainWindow ' view ' are bound to the MainViewModel, we need to receive messages from the that is TimerViewModel appropriate to update the task bar progress indicator. Fortunately this was relatively straightforward, and once again we make use of the Messenger.Default.Register and Messenger.Default.Send pattern we saw earlier.

The second message class is simply:

Hide Copy Code
 public class taskbaritemmessage{public taskbaritemmessage () {state = Taskbaritemprogressstate.none; Value =-1.    0; } public taskbaritemprogressstate State {get; set; } public double Value {get; set; } public bool HasValue {get {return! (Value < 0. 0); } }} 

Our TimerViewModel just sends instances of these messages MainViewModel and the receives them, and via the magic of data-binding, between t He view model ( MainViewModel ) and the View ( MainWindow ) the taskbar progress indicator just updates:

Hide Copy Code
<Windowx:class="Btl.mainwindow "DataContext="{Binding Main, Source={staticresource Locator}} "><Window.taskbariteminfo><TaskbariteminfoProgressstate="{Binding Progressstate} "Progressvalue="{Binding Progressvalue} "><Taskbariteminfo.thumbbuttoninfos><Thumbbuttoninfocollection><ThumbbuttoninfoCommand="{Binding Playcommand} "Description="Start "Dismisswhenclicked="False "ImageSource="Resources\icon.play.png "/><ThumbbuttoninfoCommand="{Binding Pausecommand} "Description="Pause "Dismisswhenclicked="False "ImageSource="Resources\icon.pause.png "/></ Thumbbuttoninfocollection> < /taskbariteminfo.thumbbuttoninfos > </ Taskbariteminfo> </window.taskbariteminfo>  <!-- elided--></window>    

Since TaskBarItemInfo The thumbnail previews offer us more than just the preview, we can add a thumbnail ' Start ' and ' Pause ' button (Just like Media Player), so we can control the countdown timer from the thumbnail preview, hence the ThumbButtonInfo elements above .

A Note on the UI Design

There is some method to the madness of the countdown Timer ui:since the Play and Pause buttons was likely to being the most Used, they is the largest, then the settings and reset buttons is smaller so they is less likely to is clicked on. The ' About ' window was accessed by a small '? ' on the bottom right hand corner.

Similarly, the ' OK ' and ' Cancel ' buttons is widely separated in the Settings view so it's clear which one you want to CL Ick on.

And lastly, aside from the button icons (play, pause, etc.), I ' ve left the theming of the application alone, so that the O S can choose how to theme it. Of course, since this is a MVVM application, you can take the source code, fire up Blend, and change it however.

There is even some third-party libraries that would do a lot of the work for you, e.g., Mahapps.metro.

A WPF/MVVM Countdown Timer

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.