はじめに
今回はSilverlightアプリケーションで階層構造の表示・選択などに利用されるコントロールTreeViewコントロールのカスタマイズ方法と、Infragisticsの高機能コントロール群であるNetAdvantage for SilverlightにあるXamDataTreeコントロールのカスタマイズ方法についてそれぞれご説明いたします。
対象読者
Silverlightを利用したアプリケーション開発に必要となるXAMLやコンテンツモデル、データバインディング、テンプレートなどのSilverlightの基礎的な知識を有する方。
SilverlightにおけるC#,Visual BasicなどのマネージAPIに関する知識をお持ちの方。
必要環境
Visual Studio 2010もしくはVisual Web Developer 2010 Express Edition、Silverlight 4 Tools for Visual Studioの利用にはNetAdvantage for Silverlight Line of Business、NetAdvantage for .NETまたはNet Advantage Ultimateが必要となります。
なお、今回のサンプルはWindows 7 Ultimate 64bit環境でVisual Studio 2010 Ultimate SP1とSilverlight 4 Tools for Silverlight、NetAdvantage Ultimate 2010 Volume 3を利用しました。
Silverlightのコントロールカスタマイズ機能
TreeViewコントロールのカスタマイズにあたり、まずはSilverlightの持つコントロールのカスタマイズ機能についてご紹介しましょう。
Silverlightではさまざまなレベルでコントロールをカスタマイズするためのシナリオが用意されています。
Silverlightで用意されているコントロールのカスタマイズシナリオは大きく2つあります。1つは「スタイル」によるカスタマイズ、もう一つは「テンプレート」によるカスタマイズです。
スタイルとは、Webにおけるスタイルシートのようなイメージで、各コントロールに対してプロパティの値を適用することができるメカニズムです。
今回はもう一つのカスタマイズ、テンプレートによるカスタマイズを中心にご説明します。
テンプレート
テンプレートは一言で言ってしまえばコントロールの雛形です。
コントロールの雛形は視覚的要素と視覚的な動作を定義できます。
具体的にはそれらの定義はSilverlightでは多くの場合がXAMLのControlTemplateで定義し、各コントロールの各種Templateプロパティへ定義することで従来持っていた視覚的要素・視覚的な動作を再定義できます。
こういったテンプレートを定義する際に覚えておいたほうがいいトピックについていくつかご紹介しましょう。
コントロールコントラクト
Silverlightのコントロールはこのような形でビジュアル定義されています。つまり、実装の見た目の定義と内部のロジックが明確に分離されて実装されています。
これらが分離されていることで、ロジックとは切り離した形で、見た目・振る舞いを設定できます。
しかし、逆に分離するだけではコントロールを使ってデザインする場合に、もともと定義されていた要素の中で、ロジックの中で利用されているなど、必要となる要素を掌握することが難しくなることもあり、あらかじめこういった視覚要素や振る舞いの部分に対して取り決めを行っています。
これをコントロールコントラクトといいます。
コントロールコントラクトでは以下の点について取り決めています。
- コントロールクラスで公開される視覚的表現に利用されるプロパティ
- テンプレートに必要なパーツ
- パーツに関連付けられたテンプレートに必要となるロジック
これらについて取り決めを行うことで、コントロールの実装に影響を及ぼさないでカスタマイズできます。
Parts and Statesモデル
さきほどのコントロールコントラクトに加えて、Silverlightでは視覚的構造と視覚的動作をParts and Statesモデルと呼ばれるモデルによって定義を行います。
先ほどもご説明したとおり、SilverlightのコントロールのカスタマイズはTemplateで行うことが可能ですが、これらのテンプレートはパーツ・状態・状態グループという3つの要素で構成されます。
ここで言うパーツとは具体的には「コントロール」(正確に言うならばFrameworkElementまたはFrameworkElementの派生クラスのオブジェクト)になります。つまり、各コントロールは複数のコントロールを組み合わせることで視覚的な構造を表現することができます。
そして、コントロールコントラクトに沿った実装にするのであれば、MSDNやSilverlightのドキュメントを参照します。
例えばListBoxコントロールの場合、以下のように記述されています。
ご覧いただいたとおり、コントロールのクラス定義の上部にいくつか属性が定義されていますが、1つ取り上げてみるとTemplateVisualStateAttributeという属性はTemplateに実装されているべき状態(VisualState)・状態グループ(VisualStateGroup)を表現しています。
つまり、ListBoxコントロールはこの属性の記述にあるNameという属性で状態の名前となっており、この名前のStateをコントロールのロジックから呼び出していることを表現しています。
言い換えるなら、ここに表記されている状態の名前がテンプレートに定義されていなければ、コードは状態の動作を呼び出すことができないため、該当の状態の表現は行われないということになります。
テンプレートによるカスタマイズの基本
それでは、早速テンプレートを使った具体的なカスタマイズについて行ってみましょう。
いきなりTreeViewコントロールのカスタマイズとなると複雑なので、まずは基本的なところで、単一のコンテンツを表示できるコントロールのカスタマイズ方法から復習しましょう。
単一のコンテンツを表示するコントロールということで、まずはButtonコントロールのTemplateのカスタマイズ方法から順にご紹介します。
単一コンテンツを保持するコントロールのカスタマイズ
ButtonコントロールのテンプレートはTemplateプロパティに定義されています。
このTemplateプロパティにControlTemplateオブジェクトをセットすることでButtonコントロールの見た目を変更できます。
それでは、ButtonコントロールのTemplateを定義してみましょう。
<ControlTemplate TargetType="Button"> ……(1) <Border x:Name="Background" Background="Red" CornerRadius="3"> ……(2) <ContentPresenter x:Name="contentPresenter" /> ……(2) </Border> ……(2) </ControlTemplate>
上記はButtonコントロールのTemplateプロパティに適用することができるControlTemplateのサンプルになります。
- ControlTemplateを定義する場合、最初に対象となるコントロールを定義する必要があります。指定はTargetTypeプロパティに対して行います。今回はButtonコントロールなので、TargetType="Button"を指定します。
- ControlTemplateは前述したように、視覚的構造と視覚的動作を定義することができます。視覚的構造はコントロールを使って指定します。Border、ContentPresenterという2つのコントロールを配置しています。つまり、Borderを背景に、前面にContentPresenterを配置しています。
このControlTemplateをButtonコントロールのTemplateプロパティに設定すると以下のようになります。
<StackPanel x:Name="LayoutRoot" Background="White"> <Button Margin="5" Name="btnNormal" Content="通常のボタン" /> <Button Margin="5" Background="Azure" Name="btnCustomButton" Content="テンプレートを加工したボタン"> <Button.Template> <ControlTemplate TargetType="Button"> <Border x:Name="Background" Background="Red" CornerRadius="3"> <ContentPresenter x:Name="contentPresenter" HorizontalAlignment="Center" VerticalAlignment="Center" /> </Border> </ControlTemplate> </Button.Template> </Button> </StackPanel>
実行結果は以下のような形になります。
ContentPresenterコントロールは説明のような形でControlTemplateを定義する際、ControlTemplateの中に設定して利用されることを前提としたコントロールです。
ContentPresenterの主な役割はTemplateを設定された親オブジェクト内に指定されたContentプロパティの内容を適切な形で表示できるようコントロールに変換することを目的としたコントロールです。
親コントロールのContentプロパティの内容と後述するTemplateBindingを利用してContentPresenter自身のContentプロパティにバインディングします。
Contentプロパティにバインディングによって設定されたオブジェクトの内容に応じて適切な表示が行えるよう各種コントロールへ変換する役割を持ちます。
そうすることによって、ControlTemplate内に定義された他のコントロール同様、表示の際に利用され、反映させることが可能です。
TemplateBinding
このようにSilverlightではコントロールの見た目・振る舞いをTemplateの設定で簡単に加工できます。
しかし、この状態では実際にコントロールに定義されたプロパティ設定がUIに反映させることができません。
List2の太字部分を見ていただきますと、ButtonコントロールにはBackgroundプロパティが"Azure"で設定されていますが、実際のテンプレートではBorderコントロールのBackgroundプロパティに"Red"が定義されているため、実際のUI上に表示されている背景色は赤色の背景色が表示されています。
このように、実際のコントロールに指定されているプロパティ設定をテンプレート内のコントロールに反映させたい場合、TemplateBindingを設定します。
TemplateBindingはマークアップ拡張で指定できますので、以下のList3のように変更することでコントロールの設定内容をテンプレートに反映させることが可能です。
<ControlTemplate TargetType="Button"> <Border x:Name="Background" Background="{TemplateBinding Background}" CornerRadius="3"> <ContentPresenter x:Name="contentPresenter" HorizontalAlignment="Center" VerticalAlignment="Center" /> </Border> </ControlTemplate>
実行結果は以下のような形になります。
複数コンテンツを保持するコントロールのカスタマイズ
前回ご説明した通り、TreeViewコントロールは複数コンテンツを取り扱うItemsControlの派生クラスになります。
ItemsControlも先ほどのコントロール同様、Templateプロパティがあります。もちろん、先ほどと同様ControlTemplateを設定することでコントロールの表示方法をカスタマイズできます。
そして、ItemsControlのTemplateには複数コントロールを取り扱うためのPresenterコントロール、ItemsPresenterコントロールが設定されています。
ItemsPresenterは複数あるコンテンツを表示するため、先ほどのButtonのようなContentControlの派生クラスの役割に加えて、ItemsControlの持つプロパティを利用して複数コンテンツを取り扱うための方法の設定が行うことが可能です。
そこで、ItemsControlはこういったカスタマイズするために4つの主要なプロパティが用意されています。
これらがItemContainerGenerator・ItemContainerStyle・ItemTemplate・ItemsPanelという4つのプロパティになります。
それぞれ、順を追ってご説明しましょう。
ItemContainerGenerator
まず、ItemsControlは複数ある個々のオブジェクトを表示するために、オブジェクト表示用のコントロールの生成を行います。
この生成にはコントロールを生成する役割を持つGeneratorオブジェクトを指定するItemContainerGeneratorプロパティを持ちます。
ItemContainerGeneratorプロパティには、その名前のとおり個々のコンテンツを表示するためのコントロールの生成を行うItemContainerGeneratorクラスのオブジェクトを設定することができます。
ItemsControlはItemsやItemsSourceに設定されたコレクションのオブジェクトの数だけ、このGeneratorオブジェクトを使用してコントロールを生成します。
当然、生成されるコントロールの種類はItemsControlの種類ごとに内容が異なります。
今回の本題であるTreeViewコントロールにはTreeViewItemコントロールが生成されるGeneratorが設定されています。
つまり、TreeViewコントロールの中で表示されている明細を表示しているコントロールはTreeViewItemコントロールになります。
TreeViewItemコントロールはHeaderedItemsControl、つまりヘッダー付の複数コンテンツを取り扱うことができるコントロールとなっています。
ItemContainerStyle
ItemsControlはItemContainerGeneratorで生成されたコントロールを利用して表示を行います。そして、このGeneratorで生成されたコントロールを対象にしたStyleオブジェクトを指定することができるプロパティがこちらのItemContainerStyleプロパティになります。
TreeViewコントロールではTreeViewItemコントロールに対して適用するStyleが設定されています。
ItemTemplate
先ほどご紹介したItemContainerStyleにはGeneratorで生成されたコントロールに適用するControlTemplateも定義されています。特に指定がない場合、個々のコントロールにはこのTemplate設定に基づき表示されますが、これとは別に個々のコントロールに対してのテンプレートの定義を行うことができるのがItemTemplateになります。
ItemControlはItemTemplateに定義されたTemplateがあった場合、ItemContainerStyleに定義されているTemplate設定を上書きします。
そのため、ItemTemplateの設定が存在した場合はそれが優先されてTemplateとして適用されることになります。
ItemsPanel
複数コントロールを取り扱う際に、個々のコントロールが決定しても、それらの表示をどのように行うかというレイアウトの問題が発生します。
このような複数のオブジェクトのレイアウトはItemsPanelに設定されているPanelコントロールにより挙動が決まります。
ItemsPanelプロパティにはItemsPanelTemplateを指定できます。
ItemsPanelTemplateはItemsControlのレイアウト用に利用するパネルコントロールを指定するためのTemplateで、Panelコントロールを指定することができます。
TreeViewコントロールには表示用のパネルとして既定ではStackPanelが設定されていますので、垂直方向へ積み重ねるように表示されています。
TreeViewコントロールのカスタマイズ
TreeViewコントロールにはItemsControlの持つこのようなプロパティを保持していますが、先ほどご説明した通り、TreeViewコントロールは表示のためにHeaderedItemsControlの派生クラスであるTreeViewItemコントロールを利用しています。
ヘッダー付き複数コンテンツを取り扱うコントロールを利用し、それらのコントロールを再帰的に呼び出すことで階層構造となるデータの表示が行われています。
つまり、通常のItemsControlに比べると、階層構造を表現するために新たなHeaderedItemsControlを自動生成するという形になっています。
そのため、そういった階層構造で生成されたコントロールに対して適用するTemplateプロパティとしてHierarchicalDataTemplateプロパティが用意されています。
DataTemplate
Templateプロパティ、ItemTemplateプロパティ、HierarchicalDataTemplateプロパティに設定できるテンプレートはControlTemplateの他にDataTemplateがあります。
DataTemplateはContentControl、ItemsControlなどのコントロールに指定された特定オブジェクトのデータ型に合わせたUI表現を定義することができるTemplateになります。
DataTemplateの代表的な利用方法の一つとしてItemsControlのItemTemplateプロパティに定義するシナリオがあります。
これまでご説明したようにItemsControlは任意データのコレクションを指定することができます。DataTemplateを使うとこれらのコレクションの個々のオブジェクトに合わせて表示をカスタマイズできます。
ItemsControlでは実際にItemsSourceに適用されたコレクション内の各オブジェクトはDataTemplateを使って表示用のオブジェクトツリーを作成します。これを表示ツリーと呼びます。
表示ツリー作成されると、最終的にはテンプレート適用先のコントロールが持つDataContextプロパティにコレクションの個々のオブジェクトが設定されます。
例えばTreeViewコントロールの場合、生成されるコントロールがTreeViewItemコントロールとなるので、最終的にはこのコントロールのTemplateプロパティにDataTemplateが設定され、そしてTreeViewItemコントロールのDataContextプロパティに対して個々のオブジェクトが設定されます。
Bindingは明確なソースの指定がされていなければコントロールのDataContextプロパティを参照するため、DataTemplate内ではBindingを利用して個々のオブジェクトへのプロパティパスを定義することで、表示に反映させることが可能です。
それでは、ここまでItemsControlの説明をまとめると以下のようなイメージになります。
それでは、サンプルにTreeViewコントロールのItemTemplateにDataTemplateを設定してみましょう。
まず、データ表示を行う簡単なエンティティクラス、Personクラス定義から行いましょう。
メンバーはstring型のNameプロパティ、int型のAgeプロパティを実装しておきます。
public class Person : INotifyPropertyChanged { private string _name; public string Name { get { return _name; } set { _name = value; RaisePropertyChanged(Name); } } private int _age; public int Age { get { return _age; } set { _age = value; RaisePropertyChanged("Age"); } } public event PropertyChangedEventHandler PropertyChanged; private void RaisePropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } }
続けて、TreeViewコントロールのItemTemplateに対してPersonクラスに合わせたDataTemplateを作成します。
<sdk:TreeView Name="treeView1"> <sdk:TreeView.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Name}" Width="100" /> <ProgressBar Minimum="0" Maximum="150" Value="{Binding Age}" Width="400" /> </StackPanel> </DataTemplate> </sdk:TreeView.ItemTemplate> </sdk:TreeView>
そして、UserControlのLoadedイベントでサンプルデータをセットします。
private void UserControl_Loaded(object sender, RoutedEventArgs e) { treeView1.ItemsSource = new ObservableCollection<Person>() { new Person() { Name = "しるば太郎", Age = 40}, new Person() { Name = "しるば次郎", Age = 35}, new Person() { Name = "しるば子太郎", Age = 15}, new Person() { Name = "しるば親次郎", Age = 60}, new Person() { Name = "しるば孫太郎", Age = 5} }; }
実行結果は以下のとおりです。
今回利用したコントロールはTreeViewコントロールですが、データが階層構造でないことや、DataTemplateを指定したことで本来のTreeViewコントロールで表示されていた階層構造などは表現されていません。
階層構造を指定する場合は、HierarchicalDataTemplateというテンプレートを利用します。
HierarchicalDataTemplate
TreeViewコントロールで、階層構造を使った表現をカスタマイズする場合はHeaderedItemsControlに特化したDataTemplate、HierarchicalDataTemplateを使用することで実現できます。
このテンプレートをItemTemplateに定義することで階層構造の表示方法をカスタマイズできます。
HierarchicalDataTemplateはTemplate自体にさらにItemsSource, ItemsContainerStyle, ItemTemplateを指定することで、ヘッダー表示用のTemplate、そしてコレクション表示用のTemplateを指定することができます。
TreeViewコントロールでは、このItemTemplateにHierarchicalDataTemplateを指定することで、階層構造を展開できるような仕組みを提供しています。
それでは実際にHierarchicalDataTemplateを使ってTreeViewコントロールをカスタマイズしてみましょう。
まずは先ほどと同様、エンティティクラスの定義から。 先ほどのPersonクラスを少し拡張して、家族データを保持するための下記のようにFamilyプロパティを追加します。
private ObservableCollection<Person> _family = new ObservableCollection<Person>(); public ObservableCollection<Person> Family { get { return _family; } }
続けてHierarchicalDataTemplateを定義し、TreeViewコントロールのItemTemplateに設定します。
<UserControl x:Class="_03_HierarchicalDataTemplate.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:DesignHeight="300" d:DesignWidth="400" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" Loaded="UserControl_Loaded"> <UserControl.Resources> <sdk:HierarchicalDataTemplate x:Key="FamilyTemplate"> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Name}" Width="100" /> <ProgressBar Minimum="0" Maximum="150" Value="{Binding Age}" Width="400" /> </StackPanel> </sdk:HierarchicalDataTemplate> <sdk:HierarchicalDataTemplate x:Key="DetailTemplate" ItemsSource="{Binding Family}" ItemTemplate="{StaticResource FamilyTemplate}"> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Name}" Width="100" /> <ProgressBar Minimum="0" Maximum="100" Value="{Binding Age}" Width="400" /> </StackPanel> </sdk:HierarchicalDataTemplate> </UserControl.Resources> <Grid x:Name="LayoutRoot" Background="White"> <sdk:TreeView Name="treeView1" ItemTemplate="{StaticResource DetailTemplate}" /> </Grid> </UserControl>
そして、UserControlのLoadedイベントでサンプルデータをセットします。
private void UserControl_Loaded(object sender, RoutedEventArgs e) { treeView1.ItemsSource = new ObservableCollection<Person>() { new Person() { Name = "しるば太郎", Age = 40}, new Person() { Name = "しるば次郎", Age = 35, Family = { new Person() { Name = "しるば兄太郎", Age = 25}, new Person() { Name = "しるば弟太郎", Age = 20}, } }, new Person() { Name = "しるば三郎", Age = 60}, }; }
実行結果は以下のとおりです。
XamDataTreeのカスタマイズ
XamDataTreeの場合、Silverlight SDKのTreeViewコントロールと異なり、すでに多くの表示方法や機能が標準でサポートされています。
そのため、TreeViewコントロールのように1からすべてカスタマイズして利用するという利用方法ではなく、通常はすでに存在している機能の中からデータに合わせて表現を選択し、必要に応じてカスタマイズするという利用方法になります。
それではXamDataTreeコントロールではどのような機能を持ち、どのような表現があるのかいくつかご紹介しましょう。
表示するNodeの指定
表示するNodeの指定は、前回もご説明したようにGlobalNodeLayoutsプロパティにNodeLayoutオブジェクトを指定することで、特定型に合わせたメンバー指定を行うことができます。 List9で作成したエンティティクラスの特定メンバーを表示するだけであれば下記の指定で表示できます
<ig:XamDataTree Name="XamDataTree1"> <ig:XamDataTree.GlobalNodeLayouts> <ig:NodeLayout Key="PersonLayout" TargetTypeName="Person" DisplayMemberPath="Name" /> </ig:XamDataTree.GlobalNodeLayouts> </ig:XamDataTree>
これらの指定方法の詳細は前回の記事に記述しましたのでよろしければご参照ください。
Nodeのチェックボックスを表示
XamDataTreeはCheckBox表示をサポートしています。XamDataTreeコントロールのCheckBoxSettingsプロパティにCheckBoxSettingsオブジェクトをセットすることでCheckBoxの表示・非表示を制御することができます。
表示・非表示の切り替えはCheckBoxSettingオブジェクトのCheckBoxVisibilityプロパティを設定することでVisible(表示)/Collapsed(非表示)を切り替えることが可能です。
また、対象となるオブジェクトによってCheckBoxの表示・非表示を切り替えたい場合はNodeLayoutにあるCheckBoxSettingプロパティにCheckBoxSettingOverrideオブジェクトをセットすることで、TypeごとのCheckBox表示・非表示の切り替えが行えます。
そして、同じくNodeLayoutオブジェクトのCheckBoxMemberPathプロパティにメンバー名を指定するとCheckBoxの結果がバインドします。
それでは早速CheckBoxを表示してみましょう。
まず、先ほどのPersonクラスにCheckBoxの結果を格納するためのbool型のプロパティ、IsExistプロパティを追加します。
private bool _isExist; public bool IsExist { get { return _isExist; } set { _isExist = value; RaisePropertyChanged("IsExist"); } }
そして、XamDataTreeコントロールのCheckBoxSettingsプロパティにCheckBoxSettingsオブジェクトを設定し、CheckBoxVisibilityプロパティをTrueに続けてNodeLayoutオブジェクトのCheckBoxMemberPathプロパティに"IsExist"の記述を追加します。
<UserControl x:Class="_04_XamDataTreeCheckBox.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:DesignHeight="300" d:DesignWidth="400" xmlns:ig="http://schemas.infragistics.com/xaml" Loaded="UserControl_Loaded"> <Grid x:Name="LayoutRoot" Background="White"> <ig:XamDataTree Name="XamDataTree1"> <ig:XamDataTree.CheckBoxSettings> <ig:CheckBoxSettings CheckBoxVisibility="Visible" /> </ig:XamDataTree.CheckBoxSettings> <ig:XamDataTree.GlobalNodeLayouts> <ig:NodeLayout Key="PersonLayout" TargetTypeName="Person" DisplayMemberPath="Name" CheckBoxMemberPath="IsExist"> <!--NodeLayout単位で表示・非表示を設定したい場合は以下のように指定する--> <!--<ig:NodeLayout.CheckBoxSettings> <ig:CheckBoxSettingsOverride CheckBoxVisibility="Visible" /> </ig:NodeLayout.CheckBoxSettings>--> </ig:NodeLayout> </ig:XamDataTree.GlobalNodeLayouts> </ig:XamDataTree> </Grid> </UserControl>
LoadedイベントではList9で追加したデータをそのままXamDataTree1コントロールのItemsSourceプロパティに設定します。
実行結果は以下のような形になります。
ドラッグアンドドロップのサポート
XamDataTreeコントロールではNodeからNodeへのドラッグアンドドロップを指定できます。
指定はドラッグ可能・不可能を指定するIsDraggableプロパティ、ドロップ可能・不可能を指定するIsDropTargetプロパティの2種類で指定を行います。
ドラッグアンドドロップを行うとItemsSource内のTree構造も連動して変更します。
そのため、制約としては親Nodeが自身の子Nodeへはドラッグアンドドロップすることができません。
それでは、先ほどのデータを使って、ドラッグアンドドロップを指定してみましょう。
テストデータおよびエンティティクラスはList9,List11のものをそのまま利用します。
次に先ほどのXamDataTreeコントロールのIsDraggable、IsDropTargetをTrueで設定します。
<ig:XamDataTree Name="xamDataTree1" IsDraggable="True" IsDropTarget="True"> <ig:XamDataTree.GlobalNodeLayouts> <ig:NodeLayout Key="PersonLayout" TargetTypeName="Person" DisplayMemberPath="Name"> </ig:NodeLayout> </ig:XamDataTree.GlobalNodeLayouts> </ig:XamDataTree>
実行結果は以下のような形になります。
NodeLayoutのItemTemplateの指定、展開・縮小用Templateの指定
NodeLayoutクラスはItemTemplateプロパティを持っていますので、各データの表現にDataTemplateを利用して指定できます。
また、Treeの展開・縮小を指定する際のアイコンなどもTemplateによって指定できます。
XamDataTreeコントロールに対して、展開時のTemplateはExpandedIconTemplateプロパティに、縮小時のTemplateはCollapsedIconTemplateプロパティにそれぞれDataTemplateで指定することで置き換えが可能です。
それでは、先ほどのデータを利用して、ExpandedIconTemplateプロパティ、CollapsedIconTemplateプロパティ、そしてNodeLayoutのItemTemplateプロパティに対してDataTemplateを設定します。
前述のサンプルデータを使ってItemTemplateおよび、拡大縮小のTemplateを指定して作成してみましょう。
- サンプルプログラム6: 06-XamDataTreeItemTemplate.zip[#dl]]
<ig:XamDataTree Name="xamDataTree1"> <ig:XamDataTree.ExpandedIconTemplate> <DataTemplate> <Ellipse Width="10" Height="10" Margin="5" Fill="Red"/> </DataTemplate> </ig:XamDataTree.ExpandedIconTemplate> <ig:XamDataTree.CollapsedIconTemplate> <DataTemplate> <Ellipse Width="10" Height="10" Margin="5" Fill="Blue" /> </DataTemplate> </ig:XamDataTree.CollapsedIconTemplate> <ig:XamDataTree.GlobalNodeLayouts> <ig:NodeLayout Key="PersonLayout" TargetTypeName="Person" DisplayMemberPath="Name"> <ig:NodeLayout.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Data.Name}" Width="100" /> <ProgressBar Minimum="0" Maximum="100" Value="{Binding Data.Age}" Width="400" /> </StackPanel> </DataTemplate> </ig:NodeLayout.ItemTemplate> </ig:NodeLayout> </ig:XamDataTree.GlobalNodeLayouts> </ig:XamDataTree>
実行結果は以下のとおりになります。
大規模データの取り扱い
XamDataTreeコントロールでは大量データに対しての処理も非常に高速に行えるようパフォーマンスチューニングされています。
List14のような加工が行われたXamDataTreeコントロールでも非常に高速に動作します。
それでは、Loadedイベントに以下のようなデータを追加して動作させてみたいと思います。
private void UserControl_Loaded(object sender, RoutedEventArgs e) { var bigdata = from i in Enumerable.Range(1, 10000) select new Person() { Name = string.Format("しるば{0}太郎", i), Age = i%100, Family = from j in Enumerable.Range(1,10) select new Person() { Name = string.Format("しるば子{0}太郎", j), Age = j } }; MessageBox.Show("データ生成が完了しました。"); xamDataTree1.ItemsSource = bigdata; }
こちらを実行した結果は以下のとおりです。
上記の図では実行速度が確認できませんがサンプルプログラムを実行していただくと「データ生成が完了しました」のMessageBox表示後、10000件に及ぶテンプレート付データが非常に高速に表示できていることをご確認いただけます。
このように大量データに対して高パフォーマンスで動作できます。
おわりに
今回はSilverlightコントロールのカスタマイズからTreeViewコントロール、そしてXamDataTreeコントロールのカスタマイズについてご説明させていただきました。
ここまでの説明を見ていただいても分かるようにSilverlightのコントロールも非常にカスタマイズ性の高いコントロールとなっているため、労力を惜しまなければ、かなり高度なカスタマイズが行えるように設計されております。
しかし、実際の開発現場では、こういったカスタマイズ以外にもコントロールやエンティティのデザイン、そしてテストなど、さまざまな工数が必要となることも同時に予想されます。
今回ご紹介したXamDataTreeコントロールは標準で非常に多くの機能の実装や業務利用に耐えるパフォーマンスチューニングが施されており、十分なコストメリットを得られることができるかと思います。
今回の記事ではすべての機能をご紹介することができませんでしたが、まだまだ利便性の高い機能を多数実装されていますので、ぜひ、一度お試しいただければと思います。