XAML/Silverlightでデータ バインディング:連載:次世代技術につながるSilverlight入門(1/3 ページ)
データの種類に応じてUI表示をカスタマイズしたい?! XAMLなら簡単。データ・バインディングとデータ・テンプレートを解説。
powered by Insider.NET
前回説明したようなUI(ユーザー・インターフェイス)のカスタマイズを行う動機として最も多いものは、データの種類に応じた表示方法の変更だろう。この要求に対して、Silverlightではデータ・バインディングとデータ・テンプレートという非常に強力な機能を提供していて、コントロールの自作やオーナー・ドローのような作業は不要である。
今回と次回の2回にわたって、このデータ・バインディングとデータ・テンプレートについて説明していく。
データの表示
本稿では、サンプル・データの表示に当たって、リスト 1に示すようなクラスを用意して使うものとする。
using System.Collections.Generic;
namespace TemplateSample.DataModels
{
public class Point
{
public int X { get; set; }
public int Y { get; set; }
}
public class Triangle
{
public Point A { get; set; }
public Point B { get; set; }
public Point C { get; set; }
public IEnumerable<Point> Points
{
get
{
yield return A;
yield return B;
yield return C;
}
}
}
}
Namespace Global.TemplateSample.DataModels
Public Class Point
Public Property X As Integer
Public Property Y As Integer
End Class
Public Class Triangle
Public Property A As Point
Public Property B As Point
Public Property C As Point
Public ReadOnly Iterator Property Points As IEnumerable(Of Points)
Get
Yield A
Yield B
Yield C
End Get
End Property
End Class
End Namespace
リスト 1: サンプル・データ用のクラス(上:C#、下:VB)
本題に入る前に、データ・バインディングやデータ・テンプレートの仕組みを使わない場合の書き方を挙げて、その問題点を説明しておこう。
●テンプレートを使わない書き方
Silverlightでも、リスト 2のように、C#やVB(Visual Basic)などのプログラム・コード中でUIを生成することも可能である。
using System.Windows.Controls;
using TemplateSample.DataModels;
namespace TemplateSample.Views
{
public class NoXamlControl : ContentControl
{
StackPanel Panel { get; set; }
public NoXamlControl()
{
Content = Panel = new StackPanel();
}
public void SetData(Triangle triangle)
{
this.Panel.Children.Clear();
foreach (var p in triangle.Points)
{
var item = new StackPanel
{
Orientation = Orientation.Horizontal,
Children =
{
new TextBox { Text = p.X.ToString() },
new TextBox { Text = p.Y.ToString() },
}
};
this.Panel.Children.Add(item);
}
}
}
}
Imports System.Windows.Controls
Imports TemplateSample.DataModels
Namespace Global.TemplateSample.Views
Public Class NoXamlControl
Inherits ContentControl
Public Property Panel As StackPanel
Public Sub New()
Content = New StackPanel()
Panel = Content
End Sub
Public Sub SetData(triangle As Triangle)
Me.Panel.Children.Clear()
For Each p In triangle.Points
Dim item As New StackPanel With {.Orientation = Orientation.Horizontal}
item.Children.Add(New TextBox With {.Text = p.X.ToString()})
item.Children.Add(New TextBox With {.Text = p.Y.ToString()})
Me.Panel.Children.Add(item)
Next
End Sub
End Class
End Namespace
リスト 2: プログラム・コードでのUI生成(上:C#、下:VB)
テンプレートの仕組みを持たないUIフレームワークの場合には、このようなコードを頻繁に書くことになるだろう。複数の(特に可変長の)データをUI上に表示するために、「foreach」(C#の場合。VBでは「For Each」)などの反復ステートメントを使う。
「foreachステートメントのような基礎的な文法だけで書けて、XAMLなどの追加の知識が必要ない」という意味で、一見すると簡単そうなコードに思える。しかし実際のところ、簡単なコードで書けるのはUIに求められる要件自体が簡素なうちだけで、実用的なUIを作ろうとするとすぐにコードが複雑化してしまう。例えば、以下のようなことを考えてみてほしい。
この例のコードでは、SetDataメソッドを呼ぶことで、データをUIに反映させている。そこでまず問題になるのは、「データが更新されたことを確認してSetDataメソッドを呼び直す処理をどこで行うか」である。この処理を行う管理者のようなものが別途必要になる。
また、今の作りでは、SetDataメソッドを呼ぶたびにUI要素を作り直している。部分的にしかデータを更新していない場合でもすべてのUI要素を作り直すため、無駄が多く、性能問題を引き起こす。無駄をなくすためには、以下のような仕組みが必要になる。
- プロパティ値の更新通知を受け取って、対応する部分だけ書き換える
- 項目の追加/削除通知を受け取って、対応するUI要素だけを生成/破棄する
- レイアウトの結果、画面上に表示された部分だけUI要素を生成し、画面から外れたときに破棄する(=「UIの仮想化(virtualization)」と呼ぶ)
さらに、エンド・ユーザーの操作による値の変更を元データに反映させる必要も出てくる。生成したTextBoxオブジェクトの1つ1つに対して、TextChangedイベントやLostFocusイベントを拾って、元データへの反映処理を書く必要が出てくる。
これらの要件にきっちり対応するためには、非常に大きな手間がかかる。そこでSilverlightは(同じXAMLを基盤にするWPFやWindowsストア・アプリでも)、このような手間のかかる部分をフレームワーク内で行い、UI開発を簡単にするための仕組みとして、「データ・バインディング(data binding)」や「データ・テンプレート(data template)」という機能を提供している。
●Silverlightのデータ表示機能
リスト 2に示すようなコードによるUI生成が、Silverlightではどう変わるかを見ていこう。リスト 2と同様のことを行うには、リスト 3に示すようなXAMLコードを記述する(分離コード側の編集は不要)。
<UserControl x:Class="TemplateSample.Views.DataTemplateSampleControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ItemsControl ItemsSource="{Binding Points}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding X}" />
<TextBox Text="{Binding Y}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</UserControl>
リスト 3: データ・テンプレートを使ってデータの表示を行う例(XAML)
XAMLコード中のBindingマークアップ拡張の部分がデータ・バインディング、<DataTemplate>要素の部分がデータ・テンプレートである。詳細は後述していくことになるが、このXAMLコードが行っていることを概念図化すると図 1に示すようになる。
「表示したいデータ」「データの項目ごとにどう表示したいかを表すひな形(=データ・テンプレート)」「項目のレイアウト方法」を個別に与えて「表示結果」を得る(リスト 3のコード中ではデータは未設定で、外部から与えて使う)。
前述のような手間のかかる処理(=プロパティ値や要素の変更/追加/削除に応じたUIの更新、エンド・ユーザー操作の元データへの反映や、仮想化など)はSilverlightのフレームワーク内で行われる。
それではこれらの詳細について説明していこう。今回の説明はデータ・バインディングが中心となる。
Copyright© Digital Advantage Corp. All Rights Reserved.