Analogue Clock

Analogue Clock is a Simple User Control to display the current time using Silverlight on Windows Phone 7.

Printer Friendly Download Tutorial (526KB) Download Source Code (18.3KB)

Step 1

Start Microsoft Visual Studio 2010 Express for Windows Phone, then Select File then New Project... Select "Visual C#" then "Silverlight for Windows Phone" and then "Windows Phone Application" from Templates, select a Location if you wish, then enter a name for the Project and then click OK, see below:

New Project

Step 2

A Windows Phone application Page named MainPage.xaml should then appear, see below:

MainPage.xaml

Step 3

Select Project then "Add New Item...", and select the "Windows Phone User Control" Template, then change the "Name" to Clock.xaml see below:

Clock User Control

Step 4

Add the new User Control to the Project by Clicking on Add, then in the XAML Pane for the User Control.
Remove Background="{StaticResource PhoneChromeBrush}" from <Grid x:Name="LayoutRoot" ...>, see below:

Clock UserControl Attributes

Step 5

While still in XAML Pane between the <Grid x:Name="LayoutRoot"> and </Grid> lines type the following XAML:

<Canvas Height="400" Width="400" Name="Display"/>

XAML:

User Control XAML Pane

Design:

User Control Design View

Step 6

Right Click on the User Control or the entry for "Clock.xaml" in Solution Explorer and choose the "View Code" option.
In the Code View for Clock.xaml.cs, above "namespace AnalogueClock" type the following:

using System.Windows.Threading;

Also in the CodeView below the "{" of the line "public partial class Clock : UserControl" type the following:

private DispatcherTimer _timer = new DispatcherTimer();
private DateTime _time = DateTime.Now;
private Canvas _markers = new Canvas();
private Canvas _face = new Canvas();
private Rectangle _secondsHand;
private Rectangle _minutesHand;
private Rectangle _hoursHand;
private double _diameter;
private int _secondsWidth = 1;
private int _secondsHeight;
private int _minutesWidth = 5;
private int _minutesHeight;
private int _hoursWidth = 8;
private int _hoursHeight;
private bool _isRealTime = true;
private bool _showSeconds = true;
private bool _showMinutes = true;
private bool _showHours = true;
private Brush _faceBackground = ((Brush)App.Current.Resources["PhoneBackgroundBrush"]);
private Brush _faceForeground = ((Brush)App.Current.Resources["PhoneForegroundBrush"]);
private Brush _rimForeground = ((Brush)App.Current.Resources["PhoneBorderBrush"]);
private Brush _rimBackground = ((Brush)App.Current.Resources["PhoneAccentBrush"]);

See Below:

Clock.xaml Include and Declarations

Step 7

While still in the Code View for Clock.xaml.cs, above "public Clock()" line type the following Methods:

private Rectangle Hand(double width, double height, 
Brush background, double radiusX, double radiusY, double thickness)
{
  Rectangle _hand = new Rectangle();
  _hand.Width = width;
  _hand.Height = height;
  _hand.Fill = background;
  _hand.StrokeThickness = thickness;
  _hand.RadiusX = radiusX;
  _hand.RadiusY = radiusY;
  return _hand;
}

private void RemoveHand(ref Rectangle hand)
{
  if (hand != null && _face.Children.Contains(hand))
  {
    _face.Children.Remove(hand);
  }
}

private void AddHand(ref Rectangle hand)
{
  if (!_face.Children.Contains(hand))
  {
    _face.Children.Add(hand);
  }
}

private TransformGroup TransformGroup(double Angle, double X, double Y)
{
  TransformGroup _transformGroup = new TransformGroup();
  TranslateTransform _firstTranslate = new TranslateTransform();
  _firstTranslate.X = X;
  _firstTranslate.Y = Y;
  _transformGroup.Children.Add(_firstTranslate);
  RotateTransform _rotateTransform = new RotateTransform();
  _rotateTransform.Angle = Angle;
  _transformGroup.Children.Add(_rotateTransform);
  TranslateTransform _secondTranslate = new TranslateTransform();
  _secondTranslate.X = _diameter / 2;
  _secondTranslate.Y = _diameter / 2;
  _transformGroup.Children.Add(_secondTranslate);
  return _transformGroup;
}

See Below:

Clock Methods

Step 8

While still in the Code View for Clock.xaml.cs, above "public Clock()" line type the following Methods:

private void SecondHand(int seconds)
{
  RemoveHand(ref _secondsHand);
  if (_showSeconds)
  {
    _secondsHand = Hand(_secondsWidth,_secondsHeight,_faceForeground,0, 0, 0);
    _secondsHand.RenderTransform = TransformGroup(seconds * 6, 
    -_secondsWidth / 2, -_secondsHeight + 4.25);
    AddHand(ref _secondsHand);
  }
}

private void MinuteHand(int minutes, int seconds)
{
  RemoveHand(ref _minutesHand);
  if (_showMinutes)
  {
    _minutesHand = Hand(_minutesWidth, _minutesHeight, _rimForeground, 2, 2, 0.6);
    _minutesHand.RenderTransform = TransformGroup(6 * minutes + seconds / 10, 
    -_minutesWidth / 2, -_minutesHeight + 4.25);
    AddHand(ref _minutesHand);
  }
}

private void HourHand(int hours, int minutes, int seconds)
{
  RemoveHand(ref _hoursHand);
  if (_showHours)
  {
    _hoursHand = Hand(_hoursWidth, _hoursHeight, _rimBackground, 3, 3, 0.6);
    _hoursHand.RenderTransform = TransformGroup(30 * hours + minutes / 2 + seconds / 120,
    -_hoursWidth / 2, -_hoursHeight + 4.25);
    AddHand(ref _hoursHand);
  }
}

private void Layout(ref Canvas canvas)
{
  Ellipse _rim = new Ellipse();
  Ellipse _inner = new Ellipse();
  canvas.Children.Clear();
  _diameter = canvas.Width;
  _rim.Height = _diameter;
  _rim.Width = _diameter;
  _rim.Fill = _rimBackground;
  canvas.Children.Add(_rim);
  _inner.Width = _diameter - 40;
  _inner.Height = _diameter - 40;
  _inner.Fill = _faceBackground;
  Canvas.SetTop(_inner, 20);
  Canvas.SetLeft(_inner, 20);
  canvas.Children.Add(_inner);
  _markers.Children.Clear();
  _markers.Width = _diameter;
  _markers.Height = _diameter;
  for (int i = 0; i < 60; i++)
  {
    Rectangle _marker = new Rectangle();
    _marker.Fill = _rimForeground;
    if ((i % 5) == 0)
    {
      _marker.Width = 3;
      _marker.Height = 8;
      _marker.RenderTransform = TransformGroup(i * 6, -(_marker.Width / 2),
      -(_marker.Height * 2 + 4.5 - _rim.StrokeThickness / 2 - _diameter / 2 - 6));
    }
    else
    {
      _marker.Width = 1;
      _marker.Height = 4;
      _marker.RenderTransform = TransformGroup(i * 6, -(_marker.Width / 2),
      -(_marker.Height * 2 + 12.75 - _rim.StrokeThickness / 2 - _diameter / 2 - 8));
    }
    _markers.Children.Add(_marker);
  }
  canvas.Children.Add(_markers);
  _face.Width = _diameter;
  _face.Height = _diameter;
  canvas.Children.Add(_face);
  _secondsHeight = (int)_diameter / 2 - 20;
  _minutesHeight = (int)_diameter / 2 - 40;
  _hoursHeight = (int)_diameter / 2 - 60;
}

See Below:

Clock Methods

Step 9

While still in the Code View for Clock.xaml.cs in the "public Clock()" Constructor below "InitializeComponent();" type the following:

Layout(ref Display);
_timer.Tick += (object sender, EventArgs e) =>
{
  if (_isRealTime) _time = DateTime.Now;
  SecondHand(_time.Second);
  MinuteHand(_time.Minute, _time.Second);
  HourHand(_time.Hour, _time.Minute, _time.Second);
};
_timer.Start();

See Below:

User Control Constructor

Step 10

While still in the Code View for Clock.xaml.cs, above "public Clock()" line type the following Properties:

public Brush FaceForeground
{
  get { return _faceForeground; }
  set 
  {
    _faceForeground = value == null ? 
    ((Brush)App.Current.Resources["PhoneForegroundBrush"]) : 
    value;
  }
}

public Brush FaceBackground
{
  get { return _faceBackground; }
  set 
  {
    _faceBackground = value == null ? 
    ((Brush)App.Current.Resources["PhoneBackgroundBrush"]) :
    value;
  }
}

public Brush RimForeground
{
  get { return _rimForeground; }
  set 
  {
    _rimForeground = value == null ? 
    ((Brush)App.Current.Resources["PhoneAccentBrush"]) :
    value;
  }
}

public Brush RimBackground
{
  get { return _rimBackground; }
  set 
  {
    _rimBackground = value == null ?
    ((Brush)App.Current.Resources["PhoneSubtleBrush"]) :
    value;
  }
}

public bool Enabled
{
  get { return _timer.IsEnabled;}
  set 
  {
    if (_timer.IsEnabled)
    {
      _timer.Stop();
    }
    else
    {
      _timer.Start();
    }
  }
}

public bool IsRealTime
{
  get {return _isRealTime; }
  set {_isRealTime = value;}
}

public bool ShowSeconds
{
  get {return _showSeconds; }
  set {_showSeconds = value;}
}

public bool ShowMinutes
{
  get {return _showMinutes; }
  set {_showMinutes = value;}
}

public bool ShowHours
{
  get {return _showHours; }
  set {_showHours = value;}
}

public DateTime Time
{
  get {return _time;}
  set {_time = value;}
}

See Below:

Clock Properties

Step 11

Select "Build Solution" from the Debug menu, see below:

Build Solution

Step 12

When the Build completes, return to the MainPage Designer View by selecting the "MainPage.xaml" Tab.
Then from the AnalogueClock Controls section in the Toolbox select the Clock control:

Clock User Control

Step 13

Draw a Clock onto the Page and in the XAML Pane for MainPage.xaml change the "Clock1" line to the following:

<my:Clock x:Name="Clock"/>

See below:

MainPage with Clock

Step 14

Save the Project as you have now finished the Windows Phone Silverlight application. Select the Windows Phone Emulator option then Select Debug then Start Debugging or click on Start Debugging:

Start Debugging

After you do, the following will appear in the Windows Phone Emulator after it has been loaded:

Application Running

Step 15

You can then Stop the application by selecting the Visual Studio 2010 application window and clicking on the Stop Debugging button:

Stop Debugging

This is a simple Analogue Clock, you can change the Colours used by selecting the Clock and goto the Properties box and find the FaceForeground, RimBackground etc. and change them. You could also make the clock use gradients or other effects - make it your own!

Share

Creative Commons License

Copyright Comentsys © 2009 - 2010, All rights reserved. About | Contact | Link to Page
Valid XHTML 1.1! Valid CSS Level Double-A conformance icon, W3C-WAI Web Content Accessibility Guidelines 1.0 This website is ICRA rated Creative Commons License