要るかどうかは別にして、時計みたいなのを作った。

仕事では、ステータスバーの右の方に、時刻を表示する実装を行った。
そもそも、OSのタスクバーに既にあるのに、なぜ必要かは疑問に思うところだけども、作ってみるのも悪くないと思い、作った次第だ。Windowを作るたびに設定するのはアホらしいので、不要になったらいつでも外せるように、カスタムコントロールで作った。
追加→新しい項目→カスタムコントロールを選択して、コントロール名を入力すれば楽かな?
カスタムコントロールが項目にないときは、AssemblyInfo.csをチェックしておく
TwClock.cs
using System;
using System.Windows;
using System.Windows.Controls;

namespace TawamureDays.Controls {

/// <summary>
/// Tawamure Clock
/// </summary>
public class TwClock : Control {

/// <summary>
/// staticコンストラクタ
/// </summary>
static TwClock() {
DefaultStyleKeyProperty.OverrideMetadata(typeof(TwClock),
new FrameworkPropertyMetadata(typeof(TwClock)));
}
}
}
Generic.xaml
<Style TargetType="{x:Type local:TwClock}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:TwClock}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
これはあくまで雛形でしかないので、時刻を表示するための実装を行なっていく。

○依存関係プロパティを追加する。
 Intervalプロパティ...時刻表示を更新する時間間隔(S)。型はintやdecimalではなく、TimeSpanにした。
namespace TawamureDays.Controls {

/// <summary>
/// Tawamure Clock
/// </summary>
public class TwClock : Control {

/// <summary>
/// タイマー間隔を取得|設定します。
/// </summary>
public TimeSpan Interval {
get { return (TimeSpan)GetValue(IntervalProperty); }
set { SetValue(IntervalProperty, value); }
}

/// <summary>タイマー間隔</summary>
public static readonly DependencyProperty IntervalProperty =
DependencyProperty.Register("Interval", typeof(TimeSpan),
typeof(TwClock),
new UIPropertyMetadata(
new TimeSpan(0, 0, 1),
OnIntervalPropertyChanged));

/// <summary>
/// Intervalプロパティ値変更イベントハンドラ
/// </summary>
/// <param name="dpObj">イベント発生元</param>
/// <param name="e">イベント引数</param>
private static void OnIntervalPropertyChanged(
DependencyObject dpObj, DependencyPropertyChangedEventArgs e) {

var clock = dpObj as TwClock;

if (clock.timer_ != null && e.NewValue != null) {
if (clock.timer_.IsEnabled) {
//一旦止めて、設定し、再始動
clock.timer_.Stop();
clock.timer_.IsEnabled = false;
clock.timer_.Interval = (TimeSpan)e.NewValue;
clock.timer_.IsEnabled = true;
clock.timer_.Start();
} else {
clock.timer_.Interval = (TimeSpan)e.NewValue;
}
}

return;
}
}
}

○タイマーを設定する。
 時刻の更新には、タイマーを使用する。タイマーにも色々あるんだけども、今回はDispatcherを使うDispatcherタイマーを使ってみる。
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;

namespace TawamureDays.Controls {

/// <summary>
/// Tawamure Clock
/// </summary>
public class TwClock : Control {

/// <summary>
/// コンストラクタ
/// </summary>
public TwClock() {
timer_ = new DispatcherTimer(DispatcherPriority.Background);
timer_.Tick += new EventHandler(Timer_Tick);
timer_.IsEnabled = false;

//終了処理用(リーク対策)
this.Loaded += new RoutedEventHandler(TwClock_Loaded);
this.Unloaded += new RoutedEventHandler(TwClock_Unloaded);
return;
}

/// <summary>
/// タイマーイベントハンドラ
/// </summary>
/// <param name="sender">イベント発生元</param>
/// <param name="e">イベント引数</param>
private void Timer_Tick(object sender, EventArgs e) {
//DataContextを更新します。
this.DataContext = DateTime.Now;
return;
}

/// <summary>
/// loadedイベントハンドラ
/// </summary>
/// <param name="sender">イベント発生元</param>
/// <param name="e">イベント引数</param>
private void TwClock_Loaded(object sender, RoutedEventArgs e) {
this.DataContext = DateTime.Now;
timer_.IsEnabled = true;
timer_.Interval = this.Interval;
timer_.Start();
return;
}

/// <summary>
/// Unloadedイベントハンドラ
/// </summary>
/// <param name="sender">イベント発生元</param>
/// <param name="e">イベント引数</param>
private void TwClock_Unloaded(object sender, RoutedEventArgs e) {
timer_.Stop();
timer_.IsEnabled = false;
return;
}
}
}
DataContextにDateTimeを設定してあるので、ControlTemplateもそのつもりで記述する。
○テンプレート(XAML)編集
<Style TargetType="{x:Type local:TwClock}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:TwClock}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
SnapsToDevicePixels="True">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Month, StringFormat={}{0:D2}}"/>
<TextBlock Text="/"/>
<TextBlock Text="{Binding Day, StringFormat={}{0:D2}}"/>
<TextBlock Text=" "/>
<TextBlock Text="{Binding Hour, StringFormat={}{0:D2}}"/>
<TextBlock Text=":"/>
<TextBlock Text="{Binding Minute, StringFormat={}{0:D2}}"/>
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
「月/日 時:分」となるようにStackPanelで横並びになるようにしてある。
○試しに貼り付けてみる。
<Window x:Class="TawamureDays.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:tw="http://schemas.tawamuredays.jp/wpf/gui"
Title="MainWindow" Height="350" Width="525">
<tw:TawamureContents>
<tw:TwClock Interval="0:0:20"/>
</tw:TawamureContents>
</Window>

実行結果
20120927_1
この実装の場合、日付の書式は固定となっている。なので、秒まで表示しようと思うなら、ControlTemplateを編集する必要がある。あるいは、もう1つControlTemplateを作るのも手かもしれない。x:Keyをつける必要はあるけど。
仕事では、可変にできるようにFormatを指定する為のプロパティを設け、DataContextをDateTimeではなく、Stringにした。上のような細かいレイアウトってのはできなくなるんだけど、仕事ではstringで十分だった。
(追記)
なお、仕事では使わないが、本物の時計っぽく、時間と分の間の「:」を点滅させてみた。
<Style TargetType="{x:Type local:TwClock}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:TwClock}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
SnapsToDevicePixels="True">
<StackPanel Orientation="Horizontal">
<StackPanel.Triggers>
<EventTrigger RoutedEvent="StackPanel.Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard TargetName="coron">
<DoubleAnimation Storyboard.TargetProperty="Opacity"
From="1" To="0"
Duration="0:0:1"
AutoReverse="True"
RepeatBehavior="Forever"
/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</StackPanel.Triggers>

<TextBlock Text="{Binding Month, StringFormat={}{0:D2}}"/>
<TextBlock Text="/"/>
<TextBlock Text="{Binding Day, StringFormat={}{0:D2}}"/>
<TextBlock Text=" "/>
<TextBlock Text="{Binding Hour, StringFormat={}{0:D2}}"/>
<TextBlock Text=":" Name="coron"/>
<TextBlock Text="{Binding Minute, StringFormat={}{0:D2}}"/>
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
透明度を表すOpacityプロパティを、1秒毎に表示したり透明にしたりするアニメーションをXAMLに追記した。AutoReverseプロパティをtrueにすることで、勝手に戻るし、RepeatBehaviorを「Forever」にすることで、画面終了まで永遠に繰り返す事になる。C#側で別個にタイマーを設けず、XAML側のみで実現できるのが、WPFの良いところ。
スポンサーサイト
当サイトは基本をすっ飛ばしてます。基本文法等は、@ITをどうぞ
カテゴリー: WPF4 | コメント: 0 | トラックバック: 0


この記事へのコメント

コメントの投稿

非公開コメント


サイドバー背後固定表示サンプル

当ブログに書かれたソースコードは流用自由です。

バグ、スペルミス等はありうる事です。

ご利用の際は自己責任でお願いしますm(_ _)m