クライアント側実装 DataGridコントロールの自動列生成のテスト
続いてクライアント側実装に移りましょう。Page.xamlをExpression Blendで編集します。デフォルトでは参照情報が足りないためDataGridコントロールが利用できません。Expression BlendでDataGridを利用するため、Visual Studio側で参照情報を設定しておきます。Visual Studioのソリューションエクスプローラで[参照設定]を右クリックし[参照の追加]でSystem.Windows.Controls.Dataを追加しておきましょう。これでDataGridコントロールが有効になります。また、DataGridコントロールとは関係ありませんが、後で使用するので、ついでにSystem.Xml.Linqの参照も追加しておきます。
編集時の画面は次のとおりです。
上段グリッドにTextBlockを配置し下段グリッドにはアセットライブラリからDataGridとButtonをドロップします。それぞれマウスで適当な位置に配置し、大きさなどのスタイルを整えます。
DataGridに設定するプロパティですが、AutoGenerateColumns
プロパティにTrueを設定しました。これはバインドするデータによって自動的に列を生成する機能です。まずはこの機能を利用してDataGridの基本的な動作を試してみましょう。
バインドに関する設定を行うには、プロパティウィンドウからItemSourceのボックスをクリックします。以下の画面が出現します。
メニューから[カスタム式]を選択します。ここに「{Binding}」とだけ入力します。今回、データソースを指定するDataContext
プロパティはビハインドコードで設定しますのでPage.xaml側に記述するのはこれだけで十分です。
さらにUserControlには読み込み時に発生するLoadedイベントのハンドラを設定しました。
以下に設定した主なプロパティの一覧を示します。
コントロール名 | プロパティ | 概要 |
UserControl | Loadedイベント | ユーザーコントロール読み込み時に発生するイベントのハンドラ。WebサービスからXML形式の顧客リストを読み込む機能を実装する |
DataGrid | AutoGenerateColumns | 読み込んだデータに応じて列を自動的に生成するプロパティ |
ItemsSource | バインド情報を設定 | |
IsReadOnly | 読み取り専用の属性を設定 | |
Button | Clickイベント | ページ更新のハンドラ |
実際のXAMLコードは次のとおりです。
<UserControl xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data" x:Class="DataBindApplication1.Page" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="800" Height="600" Loaded="UserControl_Loaded" xmlns:DataBindApplication1="clr-namespace:DataBindApplication1" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid x:Name="LayoutRoot" Background="White"> <Grid.RowDefinitions> <RowDefinition Height="0.133*"/> <RowDefinition Height="0.867*"/> </Grid.RowDefinitions> <TextBlock HorizontalAlignment="Left" Margin="48,24,0,32" Width="Auto" Text="顧客リスト" TextWrapping="Wrap" FontSize="16"/> <data:DataGrid Margin="48,48,248,192" Grid.Row="1" x:Name="list1" AutoGenerateColumns="True" ItemsSource="{Binding}" IsReadOnly="False" /> <Button HorizontalAlignment="Right" Margin="0,0,248,154" VerticalAlignment="Bottom" Grid.Row="1" Content="更新" Click="Button_Click" RenderTransformOrigin="0.429,-1.182" Width="48"/> </Grid> </UserControl>
続いて、XMLの顧客リストの各要素をプロパティに持つCustomer
クラスを定義します。実際のデータバインドは、このCustomer
クラスのリストをバインド元オブジェクトにすることになります。ソリューションエクスプローラのクライアント側[DataBindApplication1]で右クリックし[追加]-[新しい項目]-[クラス]でCustomer.csを作成します。以下にコードを示します。
namespace DataBindApplication1 { public class Customer { public string ID { get; set; } public string Name { get; set; } public string Work { get; set; } public string Mail { get; set; } public bool Check { get; set; } public string Ref { get; set; } } }
ちなみに、プロパティの定義に利用したのはC# 3.0からの機能である自動プロパティです。これはプロパティの実体となる変数を定義することなくプロパティを使用できる便利機能です。
Customer
クラスは前述の顧客リストXMLのItem要素に対応し、Item要素以下の子要素に対応するプロパティを持ちます。後述するように、サーバから取得したXMLをLINQでこのCustomer
クラスに変換し、データソースとします。
最後にPage.xamlのビハインドコード、Page.xaml.csを作成します。
using System.Xml.Linq; //usingディレクティブを追加 ...中略... private void UserControl_Loaded(object sender, RoutedEventArgs e) { ReadContent(); //ユーザーコントロールがロードされた時にデータを読み込む } public void customer_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) { //Webサービスからのデータ取得が終わった時の処理 XDocument Xmllist = XDocument.Parse(e.Result); //取得した文字列をXML文書にして代入 var customers = from customer in Xmllist.Descendants("Item") select new Customer //LINQを使ってXMLの各要素を新しいCustomerオブジェクトとして出力 { ID = (string)customer.Element("ID"), Name = (string)customer.Element("Name"), Work = (string)customer.Element("Work"), Mail = (string)customer.Element("Mail"), Check = (bool)customer.Element("Check"), Ref = (string)customer.Element("Ref") }; this.DataContext = customers ; //ユーザーコントロール全体に適用されるDataContextを設定 } public void ReadContent() //ページロードおよび更新ボタン共通のイベント { WebClient customer = new WebClient(); //HTTPリクエストを行うクラス customer.DownloadStringCompleted += new DownloadStringCompletedEventHandler(customer_DownloadStringCompleted); //ダウンロード完了時のイベントハンドラを設定 customer.DownloadStringAsync(new Uri("http://localhost:8080/Default.aspx")); //非同期的にサーバ側に作成したサービスにアクセス } private void Button_Click(object sender, RoutedEventArgs e) { ReadContent(); //更新ボタンが押された際にもデータを読み込む }
まず、LINQを使うのでusingディレクティブに「System.Xml.Linq;」を追加します。LINQに関しては本論から離れるので詳述しませんが、
from (クエリの中でのみ有効な一時変数)in (データソース)select (出力形式)
という形式で記述しています。ここでは取得したXMLのItem要素を順にcustomer
という変数に取り出し、各要素をプロパティに変換しながらCustomer
クラスに変換し、Customer
クラスの集合をcustomers
変数に代入しています。LINQについては連載第4回も併せて参照してください。
他の各部の動作についてはコメントを参照いただくとして、ここではバインディングに関連する部分に注目してみます。
this.DataContext = customers;
この記述でユーザーコントロール全体のバインド元オブジェクトとして、customers
変数が設定されます。この結果XAMLファイル内で特にソースを明示せずデータバインディングを実行した場合、ここで設定したDataContextが継承されます。
では、ここまででとりあえず実行してみましょう。
サーバ上のXMLデータをダウンロードし、Customer
クラスのオブジェクトに変換したものを、DataGridにバインドして表示しています。boolean型の変数は自動的にCheckBoxで、それ以外の要素はTextBoxで表示されています。
試しにXMLファイルを開いて適当な要素を改変したうえで更新ボタンを押下してください。表示される値が変更されるのを確認できるでしょう。