TabControlでの画像の切り替えとRichTextBoxの利用

2010年8月25日(水)
PROJECT KySS

TabControlのタブから選択された画像を、アニメーションで表示する

今回は、2つのサンプルを紹介します。1つは、XMLファイルからTabControlのタブに表示する文字列を読み取って表示し、選択されたタブに該当する画像とコメントをアニメーションで表示するものです。もう1つは、RichTextBox内に入力した文字のサイズや色を変化させ、任意の位置に画像をレイアウトするものです。

まずは、TabControlのサンプルの紹介です。実装する機能の動作は次の通りです。

TabControlのタブに表示されているタイトル名をクリックすると、画像がアニメーションを伴って切り替わります(図1)。

図1: タブをクリックして画像がアニメーションを伴って切り替わっている

サンプル・ファイルはこちらからダウンロードできます。

VS 2010のデザイン画面上で、コントロールをレイアウトする

これまでのサンプル作成時と同様の手順で、新規Silverlight 4プロジェクト(プロジェクト名は「SL4_TabControl」)を作成してください。プロジェクトの依存関係も設定してください。

次に、画像のファイル名を記録したXMLファイル(リスト1)を追加します。XMLデータはLINQ to XMLで処理するため、「プロジェクト(P) > 参照の追加(F)」からSystem.Xml.Linqを追加しておきます。

ソリューションエクスプローラ内にImageというフォルダを作成して、画像も追加しておきます。

ダウンロードされたサンプル・ファイルにはXMLファイルと画像は追加済みです。

リスト1: XML文書ファイル(photo_etc.xml)

01<!--//--><![CDATA[// ><!--
02 
03<?xml version="1.0"?>
04<画像>
05    <情報>
06        <画像名>銀杏.jpg</画像名>
07        <説明>
08        抜けるような青空に,銀杏の木が突き刺さっている。
09        間もなくこの銀杏も黄金色に変わるだろう。
10        そして落ちていく。人生もしかり。
11        </説明>
12    </情報>
13    ~<情報></情報>繰り返し~
14</画像>
15 
16//--><!

UserControlのプロパティ内の[レイアウト]を展開して、Widthに800、Heightに600を指定します。

次にツールボックスからTextBlock、「すべてのSilverlightコントロール」からTabControlをレイアウトします(図2)。ツールボックスにTabControlコントロールが登録されていない場合は、「これからはじめるSilverlight 4」の第2回を参考に登録してください。

図2: TextBlock、TabControlをレイアウトした

書き出されるXAMLコードは省略します。

ロジックコードを記述する

ソリューションエクスプローラ内のMainPage.xamlを展開し、MainPage.xaml.vbをダブルクリックしてコード画面を開きます。

リスト2のようにロジックコードを記述します。

リスト2: ロジックコード(MainPage.xaml.vb)

1<!--//--><![CDATA[// ><!--
2 
3Option Strict On
4 
5//--><!

LINQ to XMLでXMLを処理するクラスの含まれる、System.Xml.Linq名前空間をインポートします。ImageのSourceプロパティに画像を指定するクラスの含まれる、System.Windows.Media.Imaging名前空間をインポートします。DropShadowEffectの影を付けるのに必要なクラスの含まれる、System.Windows.Media.Effects名前空間をインポートします。

1<!--//--><![CDATA[// ><!--
2 
3Imports System.Xml.Linq
4Imports System.Windows.Media.Imaging
5Imports System.Windows.Media.Effects
6~コード略~
7 
8//--><!

StackPanelの新しいリストとして作成するmyStackPanelArrayをメンバ変数として宣言します。

1<!--//--><![CDATA[// ><!--
2 
3    Dim myStackArray As New List(Of StackPanel)
4 
5//--><!

■ページが読み込まれた時の処理

XElement.LoadメソッドでXML文書ファイル(photo_etc.xml)を読み込みます。読み込んだXML文書から要素のコレクションを取得するクエリ(query)を定義します。queryを実行します。クエリコレクション内を変数resultで反復処理しながら以下の処理を実行します。

要素の値を取得し、画像名についている「.jpg」の拡張子を外したものを変数titleImageに格納しておきます。新しいStackPanelのインスタンスmyStackPanelオブジェクトを生成します。また、新しいTabItemのインスタンスmyTabItemオブジェクトを生成します。TabItemオブジェクトのHeaderプロパティに、titleImage変数を指定します。TabControlのタブに画像のタイトルが表示されます。StackPanelオブジェクトのOrientationプロパティにVerticalを指定し、子要素のスタックされる向きを垂直方向とします。画像の下に説明文が表示される形となります。

新しいDropShadowEffectのインスタンスdrEffectオブジェクトを生成します。プロパティであるOpacityに0.6、ShadowDepthに8を指定します。透過度が80%で、画像と画像の影との間の距離が8である影が表示されます。

新しいImageのインスタンスmyImageオブジェクトを生成します。Width、Heightプロパティを指定し、Marginプロパティで余白に10を指定します。Sourceプロパティには、画像を保管しているImageフォルダと要素の値を保持しているimageName変数を連結して、相対Uriで指定します。Effectプロパティに先に設定したdrEffectオブジェクトを指定します。

新しいTextBlockのインスタンスmyTextBlockオブジェクトを生成します。Widthプロパティを指定し、Textプロパティに要素の値を指定します。

myStackPanelオブジェクトにAddメソッドで画像を追加し、同じく説明を追加します。StackPanelの新しいリストとして作成しておいた、myStackArrayオブジェクトにAddメソッドで、画像と説明の追加されたmyStackPanelオブジェクトを追加します。myTabItemオブジェクトのContentプロパティにmyStackPanelオブジェクトを指定し、TabControlにAddメソッドで、myTabItemオブジェクトを指定します。TabControlの中に、タブによって切り替わる、画像とその説明文が配置されることになります。

01<!--//--><![CDATA[// ><!--
02 
03    Private Sub MainPage_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded
04        Dim xmldoc As XElement = XElement.Load("photo_etc.xml")
05        Dim query = From c In xmldoc.Descendants("情報") Select c
06        For Each result In query
07            Dim imageName As String = result.Element("画像名").Value
08            Dim titleImageLen As Integer = Len(imageName) - 4
09            Dim titleImage As String = Left(imageName, titleImageLen)
10 
11            Dim myStackPanel As New StackPanel
12            Dim myTabItem As New TabItem
13            myTabItem.Header = titleImage
14 
15            myStackPanel.Orientation = Orientation.Vertical
16 
17            Dim drEffect As New DropShadowEffect
18            With drEffect
19                .Opacity = 0.6
20                .ShadowDepth = 8
21            End With
22 
23            Dim myImage As New Image
24            With myImage
25                .Width = 320
26                .Height = 240
27                .Margin = New Thickness(10)
28                .Source = New BitmapImage(New Uri("Image/" & imageName, UriKind.Relative))
29                .Effect = drEffect
30            End With
31 
32            Dim myTextBlock As New TextBlock
33            myTextBlock.Width = 320
34            myTextBlock.Text = result.Element("説明").Value
35 
36            myStackPanel.Children.Add(myImage)
37            myStackPanel.Children.Add(myTextBlock)
38 
39            myStackArray.Add(myStackPanel)
40            myTabItem.Content = myStackPanel
41            TabControl1.Items.Add(myTabItem)
42        Next
43    End Sub
44 
45//--><!

■TabControlのタブが切り替えられた時の処理

1<!--//--><![CDATA[// ><!--
2 
3    Private Sub TabControl1_SelectionChanged(ByVal sender As Object, ByVal e As System.Windows.Controls.SelectionChangedEventArgs) Handles TabControl1.SelectionChanged
4 
5//--><!

※画像と説明文のテキストが回転する処理

新しいStoryBoardとDoubleAnimation(myStoryBoardとmyDoubleAnimation)のインスタンスを生成します。2秒かけて0°~360°まで回転させるため、DoubleAnimationのFromに0を指定し、Toには360を指定し、Durationには2秒を指定します。

新しいRotateTransformのインスタンスを生成します。RotateTransformは、指定された点を中心としてオブジェクトを時計回りに回転させるクラスです。CenterXとCenterYに、画像の中心点の座標値を指定します。

TablControlの選択されたタブのインデックス(SelectedIndex)に該当する、myStackArrayオブジェクトのRenderTransformプロパティに、myRotateTransformオブジェクトを指定します。RenderTransFormプロパティでは、UIElement の描画位置に関係する変換情報を設定することができます。myStackArrayオブジェクトにRenderTransformプロパティが設定されていない場合は、新しいRotateTransformオブジェクトのインスタンスを生成し、myStackArrayオブジェクトのRenderTransformプロパティにmyRotateTransformオブジェクトを指定します。

SetTargetメソッドでタイムラインにDoubleAnimationのインスタンスであるmyDoubleAimationを指定し、タイムラインの対象となるオブジェクトにRotateTransformのインスタンスであるmyRotateTransformを指定します。

また、SetTargetPropertyメソッドで、タイムラインにDoubleAnimationのインスタンスであるmyDoubleAimationを指定し、アニメーション化するプロパティにNew PropertyPath("(RotateTransform.Angle)")と指定し、Angleプロパティを指定して回転させます。

StoryBoardのインスタンスmyStoryBoardにAddメソッドでmyDoubleAnimationを追加します。BeginメソッドでStoryBoardを実行します。これで、画像とテキストの追加されたmyStackArrayオブジェクトが回転します。

01<!--//--><![CDATA[// ><!--
02 
03        Dim myStoryBoard As New Storyboard
04        Dim myDoubleAnimation As New DoubleAnimation
05        With myDoubleAnimation
06            .From = 0
07            .To = 360
08            .Duration = New Duration(TimeSpan.FromSeconds(2))
09        End With
10        Dim myRotateTransform As New RotateTransform
11        With myRotateTransform
12            .CenterX = 160
13            .CenterY = 120
14        End With
15 
16        myStackArray(TabControl1.SelectedIndex).RenderTransform = myRotateTransform
17        If myStackArray(TabControl1.SelectedIndex).RenderTransform Is Nothing Then
18            myRotateTransform = New RotateTransform
19            myStackArray(TabControl1.SelectedIndex).RenderTransform = myRotateTransform
20        End If
21 
22        Storyboard.SetTarget(myDoubleAnimation, myRotateTransform)
23        Storyboard.SetTargetProperty(myDoubleAnimation, New PropertyPath("(RotateTransform.Angle)"))
24        myStoryBoard.Children.Add(myDoubleAnimation)
25        myStoryBoard.Begin()
26 
27//--><!

※画像が近づいてくるアニメーション

新しいStoryBoardとDoubleAnimationのインスタンス(myStoryBoard2とmyDoubleAnimation2)を生成します。

2秒をかけて、オブジェクトをZ軸に沿って、-2000~0まで移動させるため、DoubleAnimationのFromに-2000を、Toには0を、Durationには2秒を指定します。

新しいPlaneProjectionのインスタンスを生成します。PlaneProjectionは、オブジェクトに対する遠近法変換を表わすクラスです。TablControlの選択されたタブのインデックス(SelectedIndex)に該当する、myStackArrayオブジェクトのProjectionプロパティに、myPlaneProjectionオブジェクトを指定します。Projectionプロパティは、UIElement のレンダリング時に射影を設定できるプロパティです。

myStackArrayオブジェクトにProjectionプロパティが設定されていない場合は、新しいPlaneProjectionオブジェクトのインスタンスを生成し、myStackArrayオブジェクトのProjectionプロパティにmyPlaneProjectionオブジェクトを指定します。

SetTargetメソッドで、タイムラインにDoubleAnimationのインスタンスであるmyDoubleAimation2を指定し、タイムラインの対象となるオブジェクトにPlaneProjectionのインスタンスであるmyPlaneProjectionを指定します。SetTargetPropertyメソッドで、タイムラインにDoubleAnimationのインスタンスであるmyDoubleAimation2を指定し、アニメーション化するプロパティにNew PropertyPath("(PlaneProjection.LocalOffsetZ)")と指定します。

StoryBoardのインスタンスmyStoryBoard2にAddメソッドでmyDoubleAnimation2を追加します。BeginメソッドでStoryBoardを実行します。これで、画像とテキストの追加されたmyStackArrayオブジェクトが近づくように表示されます。

01<!--//--><![CDATA[// ><!--
02 
03        Dim myStoryBoard2 As New Storyboard
04        Dim myDoubleAnimation2 As New DoubleAnimation
05        With myDoubleAnimation2
06            .From = -2000
07            .To = 0
08            .Duration = New Duration(TimeSpan.FromSeconds(2))
09        End With
10        Dim myPlaneProjection As New PlaneProjection
11 
12        myStackArray(TabControl1.SelectedIndex).Projection = myPlaneProjection
13        If myStackArray(TabControl1.SelectedIndex).Projection Is Nothing Then
14            myPlaneProjection = New PlaneProjection
15            myStackArray(TabControl1.SelectedIndex).Projection = myPlaneProjection
16        End If
17        Storyboard.SetTarget(myDoubleAnimation2, myPlaneProjection)
18        Storyboard.SetTargetProperty(myDoubleAnimation2, New PropertyPath("(PlaneProjection.LocalOffsetZ)"))
19        myStoryBoard2.Children.Add(myDoubleAnimation2)
20        myStoryBoard2.Begin()
21    End Sub
22~コード略~
23 
24//--><!

四国のSOHO。薬師寺国安(VBプログラマ)と、薬師寺聖(デザイナ、エンジニア)によるコラボレーション・ユニット。1997年6月、Dynamic HTMLとDirectAnimationの普及を目的として結成。共同開発やユニット名義での執筆活動を行う。XMLおよび.NETに関する著書や連載多数。最新刊は「Silverlight実践プログラミング」両名とも、Microsoft MVP for Development Platforms - Client App Dev (Oct 2003-Sep 2012)。http://www.PROJECTKySS.NET/

連載バックナンバー

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています