はじめに
Silverlightの特徴の1つは、アニメーションを使って視覚的に操作をすることができる点です。これにより、ユーザーはこれまでにない操作感で、Webページを操作できるようになりました。ComponentOne Studio for SilverlightのC1Knobコントロールは、カセットコンロのノブのような形状をしたコントロールで、ノブを回すことで数値の増減を行うことができます。マウスポインタをドラッグすることでノブを操作することができるため、ユーザーは手でノブを回すのと同じような感覚で、コントロールを操作できます。
そこで、今回はこのC1Knobコントロールと、.NET FrameworkクラスライブラリのDispatcherTimerクラスを組み合わせ、カウントダウンタイマーを持ったWebページを作成してみました。
対象読者
Visual Basic/Visual C# 2008を使ってプログラムを作ったことのある人。また、SilverlightおよびXAMLに対する基礎的な知識が必要になります。
必要な環境
Visual Basic 2008、Visual C# 2008、Visual Studio 2008でプログラムが作れる環境。また、Visual Studio 2008 Silverlight Tools 3.0をインストールしていることが必須条件です。なお、本プログラムはWindows Vista上で動作するVisual Studio 2008およびVisual Studio 2008 Silverlight Tools 3.0を使用して作成し、Intenet Explorer 8で動作確認を行っています。
コンポーネントのインストール
ComponentOne Studio for Silverlightを使用する方は、Visual Studio、Visual Basic、Visual C#の開発環境にComponentOne Studio Enterprise 2010Jをインストールする必要があります。インストーラは、グレープシティのWebページからダウンロードできます。
製品ページの[申込フォーム]をクリックし、グレープシティのWebサイトへ必要情報を登録すると、添付トライアルライセンスキーファイルとダウンロードサイトを記載したE-Mailが送られてきますので、ここからダウンロードします。制限事項などの詳細については、インストーラに同梱されているリリースノートを参照ください。
ComponentOne Studio for SilverlightのC1Knobコントロールについて
ComponentOne Studio for SilverlightのC1Knobコントロールは、ユーザーがポインタを回転して数値を選択できるコントロールです。音楽プレイヤーのボリュームつまみなど、ノブを回転させて数値を入力する処理などに最適です。
「Maximum」「Minimum」プロパティでノブを動かした時の数値の範囲を設定し、「Value」プロパティに現在のノブの位置が格納されます。ノブそのものの動作範囲は、「StartAngle」「SweepAngle」の2つのプロパティで決定します。
ちょっと分かりづらいのですが、ノブの実際の動作範囲とコントロールが返す値の範囲は別々に設定します。例えば、次のC1Knobコントロールは「0」から「120」までの値の範囲で数値の増減を行いますが、実際にノブが動作するのは12時位置を0度として時計回りに200度の位置を開始位置とし、270度の位置まで動作します。
<c1gauge:C1Knob x:Name="c1kb1" Width="200" Minimum="0" Maximum="120" StartAngle="200" SweepAngle="270" InteractionMode="Drag">
また、C1Knobコントロール単体では数値目盛りや目盛り線は付いていません。これらは、「C1GaugeLabel」「C1GaugeMark」クラスを使って設定します。目盛り線は、「DataTemplate」を使用してカスタマイズすることができます。
また、C1Knobコントロールの動作を「InteractionMode」プロパティを使って設定することができます。設定値は「KnobInteractionMode列挙体」のメンバで、次の値を使うことができます。
値 | 説明 |
---|---|
Drag | ユーザーがドラッグすることでポインタが移動します。 |
Click | ユーザーがノブ内をクリックすることでポインタが移動します。 |
ClickOrDrag | ユーザーがノブ内をクリックするか、ポインタをドラッグすることでポインタが移動します。 |
C1Knobコントロールのデフォルトのイベントは「ValueChanged」で、ノブを動かすとこのイベントハンドラが呼び出されます。
Webページの作成
では、さっそくWebページを作成してみましょう。グリッドは1行2列に設定し、左側のグリッドにC1KnobコントロールとButtonコントロールを、右側のグリッドにTextBlockコントロールを配置します。
今回のWebページは、ノブを回して0から120までの間の秒数をセットすると、TextBlockにその値が表示されます。そして、「Start」ボタンを押すとタイマーが作動し、セットした秒数を1秒ごとにカウントダウンしていきます。ノブの設定値が「0」になるとタイマーが停止します。また、「Stop」ボタンを押してもタイマーが停止します。
カウントダウン用タイマーは、「System.Windows.Threading」名前空間にある「DispatcherTimer」クラスを利用します。このクラスのインスタンスは、コードから作成しバックグラウンドプロセスとして作動するので、Webページには表示されません。
Silverlightプロジェクトの作成
まずは、Silverlightプロジェクトの作成からです。
Visual Studio 2008 Silverlight Tools 3.0をインストールし、Visual Studioで新しいプロジェクトを作成すると、「プロジェクトの種類」に[Silverlight]が追加されています。これを選択し、「テンプレート」から[Silverlightアプリケーション]を選びます。
「新しいSilverlightアプリケーション」というダイアログボックスが表示されるので、「新しいWebプロジェクトの種類」を選び、リストから[ASP.NET Webサイト]を選択します。
プロジェクトが作成され、新しいWebサイトに「MainPage.xaml」が作られてXAMLのコードが表示されます。
C1Knobコントロールの作成
まず、グリッドに<ColumnDefinitions>
を設定し、1行2列のグリッドにします。
<Grid x:Name="LayoutRoot" ShowGridLines="True"> <Grid.ColumnDefinitions> <ColumnDefinition Width="300"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions>
ツールボックスにあるStackPanelコントロールをグリッドの左側に配置します。
<StackPanel Grid.Column="0"></StackPanel> </Grid>
StackPanelの中にカーソルを置き、ツールボックスにあるC1Knobコントロールのアイコンをダブルクリックして作成します。
<StackPanel Grid.Column="0"> <c1gauge:C1Knob></c1gauge:C1Knob> </StackPanel>
作成したC1Knobコントロールをカスタマイズします。まず、コードから参照できるようにコントロールに名前を付け、イベントハンドラ「ValueChanged」を作成します。ノブの値の範囲は0から120までとし、「Minimum」「Maximum」プロパティを設定します。また、ノブの動作範囲は、12時位置を0度として時計回りに200度の位置をスタートにし、ここから時計回りに270度の位置で終了するように、「StartAngle」「SweepAngle」プロパティを設定します。そして、ノブがマウスのドラッグで動くように「InteractionMode」プロパティの値を「Drag」に設定します。
<c1gauge:C1Knob x:Name="c1kb1" Width="200" ValueChanged="c1kb1_ValueChanged" VerticalAlignment="Center" Minimum="0" Maximum="120" StartAngle="200" SweepAngle="270" Margin="0,30,0,0" InteractionMode="Drag"> </c1gauge:C1Knob>
これで、次のようなノブが作成されます。プロジェクトを実行し、ノブをマウスでドラッグして動作することを確認します。
目盛りの数値ラベルと目盛り線の設定
ノブが作成できたら、目盛りの数値ラベルと目盛り線を設定します。これは、C1Knobコントロールの「GaugeLabelクラス」と「GaugeMark」クラスを設定します。
「GaugeLabel」は目盛りの数値ラベルを表すオブジェクトです。「Interval」プロパティは数値の間隔を指定します。例えば、このプロパティを「20」に設定すると、「Maximum」プロパティから「Minimum」プロパティの値の範囲で数値を20ごとに自動的に計算し、ラベルで設定してくれます。また、「Location」プロパティは、ノブのどの位置にラベルを表示するかを指定するプロパティで、ゲージの中心が「0」、ゲージの外縁が「1」になります。
今回のノブでは、数値ラベルを20間隔で表示し、ノブの外側に表示するようにしています。
<c1gauge:C1GaugeLabel Interval="20" Location="1.5" />
目盛り線は、「GaugeMark」クラスを使用します。目盛りの間隔は数値ラベルと同じで、「Interval」プロパティで目盛り線の間隔を、「Location」プロパティで目盛り線の位置を指定します。これで、数値ラベルと同じように「Maximum」プロパティから「Minimum」プロパティの値の範囲で、自動的に線の間隔を計算し設定してくれます。
「GaugeMark」クラスを2つ設定すると、2種類の目盛り線を表示できます。ここでは、ノブの縁の内側と外側にそれぞれ違う感覚の目盛り線を設定します。
<c1gauge:C1GaugeMark Interval="10" /> <c1gauge:C1GaugeMark Interval="5" Location="1.15" />
目盛り線を特定の範囲に設定したい場合は、「From」プロパティと「To」プロパティで値の範囲を指定します。
<c1gauge:C1GaugeMark From="0" To="100" Interval="10" />
目盛り線は、デフォルトでは青灰色の四角形として描画されますが、独自の目盛り線にカスタマイズすることもできます。その場合は、目盛り線を表示するためのテンプレートを作成し、このテンプレートを「Template」プロパティで指定します。
ここでは、内側の目盛り線を紫色の太い線にカスタマイズします。テンプレートは、GridコントロールのResource
として作成し、これを「Template」プロパティに設定します。目盛り線は、グラフィックスの四角形を作成しこれを割り当てる、という方法を使用します。
<!-- ゲージマークを表示するためのテンプレート --> <Grid.Resources> <DataTemplate x:Key="MyMarkTemplate"> <Rectangle Width="4" Height="18" Fill="BlueViolet" Stroke="Black" StrokeThickness=".5"/> </DataTemplate> </Grid.Resources> ................. ................. <c1gauge:C1GaugeMark Interval="10" Template="{StaticResource MyMarkTemplate}"/> <c1gauge:C1GaugeMark Interval="5" Location="1.15" /> </c1gauge:C1Knob>
ButtonとTextBlockコントロールの作成
C1Knobコントロールの下にButtonコントロールを2つ作成します。それぞれ、コントロールに名前を付けてClickイベントハンドラを作成しておきます。
<Button x:Name="button1" Click="button1_Click" Content="Start" Width="100" Margin="0,30,0,0" /> <Button x:Name="button2" Click="button2_Click" Content="Stop" Width="100" Margin="0,30,0,0" /> </StackPanel>
また、右側の列のグリッドにTextBlockコントロールを作成します。コードから参照できるようにコントロールに名前を付け、グラデーションで塗りつぶしてドロップシャドウを設定してできあがりです。
<TextBlock Grid.Column="1" x:Name="text1" FontSize="70" Text="00" Margin="50,100,0,0"> <TextBlock.Foreground> <LinearGradientBrush StartPoint="0,0" EndPoint="1,1"> <GradientStop Color="Yellow" Offset="0.0" /> <GradientStop Color="LimeGreen" Offset="1.0" /> </LinearGradientBrush> </TextBlock.Foreground> <TextBlock.Effect> <DropShadowEffect Color="Black"></DropShadowEffect> </TextBlock.Effect> </TextBlock> </Grid>
コードによるタイマー処理
Webページが出来上がったら、コードタイマー処理を作成します。
タイマーの作成
この処理は、「System.Windows.Threading」名前空間の「DispatcherTimer」クラスを使用するので「System.Windows.Threading」名前空間をインポートし、「DispatcherTimer」クラスのインスタンスをモジュールレベル変数で作成しておきます。
Imports System.Windows.Threading Partial Public Class MainPage Inherits UserControl Private WithEvents timer As New DispatcherTimer()
using System.Windows.Threading; namespace sl_timer_cs { public partial class MainPage : UserControl { private DispatcherTimer timer = new DispatcherTimer();
「DispatcherTimer」クラスは、指定した時間の間隔でイベントを発生するタイマーです。WindowsフォームのTimerコントロールと同様、Intervalプロパティでイベント発生の時間間隔を設定し、イベント「Tick」を発生させます。
そこで、Webページのコンストラクタで、Intervalプロパティを1000ミリ秒に設定し、C#ではイベントハンドラを作成しておきます。
Public Sub New() InitializeComponent() Timer.Interval = New TimeSpan(0, 0, 0, 0, 1000) End Sub
public MainPage() { InitializeComponent(); timer.Interval = new TimeSpan(0, 0, 0, 0, 1000); timer.Tick += new EventHandler(timer_Tick); }
ノブを動かした処理の作成
次に、C1Knobコントロールのノブをユーザーが動かした時の処理を作成します。ユーザーがノブを動かすと、C1Knobコントロールには「ValueChanged」イベントが発生するので、このイベントハンドラでC1KnobコントロールのValueプロパティから設定値を取得します。ただし、Valueプロパティの値はdouble型なので一度整数に変換し、TextBlockに設定値を表示します。
Private Sub c1kb1_ValueChanged(ByVal sender As System.Object, ByVal e As C1.Silverlight.PropertyChangedEventArgs(Of System.Double)) Dim i As Int16 i = c1kb1.Value text1.Text = i.ToString() End Sub
private void c1kb1_ValueChanged(object sender, C1.Silverlight.PropertyChangedEventArgs<double> e) { Int16 i; i = (Int16)c1kb1.Value; text1.Text = i.ToString(); }
タイマー動作によるカウントダウン処理の作成
次に、タイマーのTickイベントハンドラで、カウントダウンの処理を行います。
まず、C1Knobコントロールの現在のノブの値をValueプロパティで取得して整数に変換します。そして、その数値から1を差し引き、C1KnobコントロールのValueプロパティに再設定します。こうすると、タイマーの動作に合わせてノブも自動的に数値が下がる方向に動くようになります。TextBlockにも数値を表示します。これで、1秒ごとにノブで設定した数値が1つずつ減っていきカウントダウンしていきます。
もし、このノブの値が「0」になったら、タイマーを停止させます。これは、「DispatcherTimer」クラスのStopメソッドを実行します。
Public Sub timer_Tick(ByVal sender As Object, ByVal e As EventArgs) Handles timer.Tick Dim i As Int16 i = c1kb1.Value i -= 1 If i < 0 Then timer.Stop() Else c1kb1.Value = i text1.Text = i.ToString End If End Sub
void timer_Tick(object sender, EventArgs e) { Int16 i; i = (Int16)c1kb1.Value; i -= 1; if (i < 0) { timer.Stop(); } else { c1kb1.Value = i; text1.Text = i.ToString(); } }
スタート・ストップボタンの処理
2つのButtonコントロールでは、タイマーの停止と開始を実行します。これは、それぞれ「DispatcherTimer」クラスのStart・Stopメソッドを実行します。
Private Sub button1_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) timer.Start() End Sub Private Sub button2_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) timer.Stop() End Sub
private void button1_Click(object sender, RoutedEventArgs e) { timer.Start(); } private void button2_Click(object sender, RoutedEventArgs e) { timer.Stop(); }
<UserControl xmlns:c1gauge="clr-namespace:C1.Silverlight.Gauge;assembly=C1.Silverlight.Gauge" x:Class="sl_timer_cs.MainPage" 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" mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480"> <Grid x:Name="LayoutRoot" ShowGridLines="True"> <Grid.ColumnDefinitions> <ColumnDefinition Width="300"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <!-- ゲージマークを表示するためのテンプレート --> <Grid.Resources> <DataTemplate x:Key="MyMarkTemplate"> <Rectangle Width="4" Height="18" Fill="BlueViolet" Stroke="Black" StrokeThickness=".5"/> </DataTemplate> </Grid.Resources> <StackPanel Grid.Column="0"> <c1gauge:C1Knob x:Name="c1kb1" Width="200" ValueChanged="c1kb1_ValueChanged" VerticalAlignment="Center" Minimum="0" Maximum="120" StartAngle="200" SweepAngle="270" Margin="0,30,0,0" InteractionMode="Drag"> <c1gauge:C1GaugeLabel Interval="20" Location="1.5" /> <c1gauge:C1GaugeMark Interval="10" /> <c1gauge:C1GaugeMark Interval="5" Location="1.15" /> </c1gauge:C1Knob> <Button x:Name="button1" Click="button1_Click" Content="Start" Width="100" Margin="0,30,0,0" /> <Button x:Name="button2" Click="button2_Click" Content="Stop" Width="100" Margin="0,30,0,0" /> </StackPanel> <TextBlock Grid.Column="1" x:Name="text1" FontSize="70" Text="00" Margin="50,100,0,0"> <TextBlock.Foreground> <LinearGradientBrush StartPoint="0,0" EndPoint="1,1"> <GradientStop Color="Yellow" Offset="0.0" /> <GradientStop Color="LimeGreen" Offset="1.0" /> </LinearGradientBrush> </TextBlock.Foreground> <TextBlock.Effect> <DropShadowEffect Color="Black"></DropShadowEffect> </TextBlock.Effect> </TextBlock> </Grid> </UserControl>
まとめ
アニメーションを使ったGUIは、ユーザーに直感的な操作を提示でき、「使いやすいページ」の印象を与えるとともに、新鮮で高度な技術を使ったページという印象も与えます。今回は、簡単なカウントダウンタイマーを作成しましたが、C1Knobコントロールはアイデア次第で色々な入力インターフェイスに使用できるコントロールと言えます。