チュートリアル : Expression Blend または Visual Studio を使用した WPF 時計の作成

MSDN の記事 チュートリアル : Expression Blend または Visual Studio を使用した Silverlight 時計の作成 は非常に判りやすいチュートリアルだと思います。私も何回かこのチュートリアルにしたがって Expression Blend を使っているうち、徐々に Blend の使い方が判ってきました。

でも当面 Silverlight は用がないので、WPF で作ってみてはどうだろうと思いつきました。で、このチュートリアルに従って WPF アプリケーション作っていたら、WPF だと引っかかるとこが幾つかあるのが判りました。以下、注意点を列挙します。
(注:以下の実行画面ですが、チュートリアルのデザインは微妙にださいので少し変えてます)


時計の針のアニメーションを追加するには

4.4. UserControl 開始要素の後に次のマークアップを追加して、時計の針のアニメーションを追加します。



  
    ・・・・・・・
  


ここの XAML ですが、WPF は Window で作成しているので UserControl を Window に変更します。

<Window.Resources>
    <Storyboard x:Name="clockStoryboard">
        ・・・・・・・
    </Storyboard>
</Window.Resources>


次にこの XAML をリソースに貼り付けただけでは Key 属性がないため

エラー IDictionary に追加されるすべてのオブジェクトは、Key 属性またはオブジェクトに関連する別の型のキーを保持している必要があります。


というエラーが発生します。どうやら Silverlight は Resource に Key 属性がなくても大丈夫なようですが*1WPF の場合は通りません。そこで

<Window.Resources>
    <Storyboard x:Key="clockStoryboard" x:Name="clockStoryboard">
        ・・・・・・・
    </Storyboard>
</Window.Resources>


というように Key 属性を追加します。


7.7.MainPage クラスに、Storyboard を開始する次の SetAndStartClock メソッドを追加します。


Private Sub SetAndStartClock(ByVal sender As Object, ByVal e As EventArgs)

  ' Start the storyboard.
  clockStoryboard.Begin()
End Sub


このコードなんですが、WPF の場合、

エラー 'clockStoryboard' は宣言されていません。アクセスできない保護レベルになっています。


と怒られます。WPF ではリソースで宣言されたオブジェクトにはダイレクトにアクセスできないようです。
そこで、リソース内のオブジェクトにアクセスするには、まず System.Windows.Media.Animation をインポートし

Imports System.Windows.Media.Animation

以下のようにコードを変更します。

Private Sub SetAndStartClock(ByVal sender As Object, ByVal e As EventArgs)
    ' Start the storyboard.
    Dim storyboard = DirectCast(Me.Resources("clockStoryboard"), Storyboard)
    storyboard.Begin()
End Sub


これで時計が動き始めます。


時計を現在の時刻に設定するには

2.SetAndStartClock プロシージャを次のコードに置き換えます。このコードによって、時計の針が現在の時刻に設定されます。


Private Sub SetAndStartClock(ByVal sender As Object, ByVal e As EventArgs)
    ・・・・・・・
End Sub


このコードも、直接リソース内のオブジェクトにアクセスできないため、当然ながら動きません。そこで以下のように変更します。ちなみにコードの変更箇所が判りにくいので、コメントは省きました。なお System.Windows.Media.Animation をインポートするのを忘れないでください。

Private Sub SetAndStartClock(ByVal sender As Object, ByVal e As EventArgs)

    Dim currentDate As Date = DateTime.Now
    Dim hourangle As Double = (((CType(currentDate.Hour, Single) / 12) * 360) + (currentDate.Minute / 2))
    Dim minangle As Double = ((CType(currentDate.Minute, Single) / 60) * 360)
    Dim secangle As Double = ((CType(currentDate.Second, Single) / 60) * 360)

    Dim storyboard = DirectCast(Me.Resources("clockStoryboard"), Storyboard)
    Dim hourAnimation = DirectCast(storyboard.Children(0), DoubleAnimation)
    hourAnimation.From = hourangle
    hourAnimation.To = (hourangle + 360)

    Dim minuteAnimation = DirectCast(storyboard.Children(1), DoubleAnimation)
    minuteAnimation.From = minangle
    minuteAnimation.To = (minangle + 360)

    Dim secondAnimation = DirectCast(storyboard.Children(2), DoubleAnimation)
    secondAnimation.From = secangle
    secondAnimation.To = (secangle + 360)

    storyboard.Begin()
End Sub


3.アプリケーションを実行します。時計の針が現在の時刻に設定されるようになりました。



え、C# のコードはないのかって?CShaper なら VB.NET のコードくらいすぐ判ると思ってますので書いてません。あしからず。