WPFのDispatcherTimerクラスを使い簡易アナログ時計を作成する   


## はじめに

WPFのDispatcherTimerクラスを使い、簡単なアナログ時計のサンプルコードです。

概要は以下のとおり。

- 秒針、分針、時針の３つをLineオブジェクトとして表す。
- ３つのLineオブジェクトの、RenderTransformプロパティには、RotateTransformを設定する。
- DispatcherTimerで、１秒おきに、上記RotateTransformの回転角度を変化させる。
 
## 実行例

以下に、作成したアプリのスクリーンショットを示します。秒針は１秒おきに動いていきます。



![2019-06-01 14_18_29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29415/8f9a8dfa-459c-1c27-49a0-c710a97ae6dc.png "2019-06-01 14_18_29.png")


 
## XAMLを定義する

XAMLを示します。
Canvasの中に、3つのLine（時針、分針、秒針）を定義しています。

RotateTransformのAngleプロパティを変化させることで、それぞれの針を動かします。

```xml
<Window x:Class="WpfAnalogClock1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfAnalogClock1"
        mc:Ignorable="d"
        Title="Clock" Height="230" Width="220" Loaded="Window_Loaded" >
    <Canvas Width="200" Height="200">
        <Line x:Name="HourLine"  Stroke="Black" Fill="Black" 
              X1="100" Y1="100" X2="100" Y2="35"              
               StrokeThickness="3" >
            <Line.RenderTransform>
                <RotateTransform  x:Name="AngleHour" Angle="0" 
                                  CenterX="100" CenterY="100"/>
            </Line.RenderTransform>
        </Line>
        <Line x:Name="MinuteLine"  Stroke="Black" Fill="Black" 
              X1="100" Y1="100" X2="100" Y2="15"              
               StrokeThickness="2" >
            <Line.RenderTransform>
                <RotateTransform x:Name="AngleMinute"  Angle="0" 
                                 CenterX="100" CenterY="100"/>
            </Line.RenderTransform>
        </Line>
        <Line x:Name="SecondLine"  Stroke="Black" Fill="LightGray"
              X1="100" Y1="120" X2="100" Y2="10"  >
            <Line.RenderTransform>
                <RotateTransform x:Name="AngleSecond" Angle="0"  
                                 CenterX="100" CenterY="100"/>
            </Line.RenderTransform>
        </Line>
        <Ellipse Fill="Black" Width="6" Height="6" HorizontalAlignment="Center"
            VerticalAlignment="Center" 
            Canvas.Top="97" Canvas.Left="97"/>
    </Canvas>
</Window>
```

 
絵心のない僕は、時針、分針、秒針の描画にLineオブジェクトを使いましたが、PolygonやPathを使ってもうすこし時計らしい針にし、背景に文字盤を加えれば、見栄えも良くなると思います。

その際、C#のコードでは、RotateTransform の名前に対して、値を設定していますので、C#側は一切手を入れる必要はないはずです。

## C#のコード


C#のコードは、オブジェクトの回転角度を変えるだけですので、とても単純なコードになっています。 

WindowのLoadedイベントで、DispatcherTimerオブジェクトを生成し、タイマーをスタートさせます。

Tickイベントが１秒おきに発生しますので、 そのイベントハンドラで、Updateメソッドを呼び出しています。 Updateメソッドでは、現在の時刻を取得し、秒針、分針、時針の針の角度を求め、 それぞれの針に対応するLineオブジェクトの回転角度を更新しています。


このコードは、[GitHub](https://github.com/gushwell/WpfAnalogClock)で公開しています。



```cs
using System;
using System.Windows;
using System.Windows.Threading;

namespace WpfAnalogClock1
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            Update();
            DispatcherTimer timer = 
                new DispatcherTimer(DispatcherPriority.Normal, this.Dispatcher);
            timer.Interval = new TimeSpan(0, 0, 1);
            timer.Tick += Timer_Tick;
            timer.Start();
        }

        void Update()
        {
            DateTime dt = DateTime.Now;
            this.AngleSecond.Angle = dt.Second * 360.0 / 60.0;
            this.AngleMinute.Angle = (dt.Minute + dt.Second / 60.0) * 360.0 / 60.0;
            this.AngleHour.Angle = (dt.Hour + dt.Minute / 60.0) * 360.0 / 12;
        }

        void Timer_Tick(object sender, EventArgs e)
        {
            Update();
        }
    }
}
```