特集:WPF/Silverlight時代のDataGrid速習講座(後編)

初めてのWPF/Silverlightデータグリッド開発

デジタルアドバンテージ 一色 政彦
2010/11/26
Page1 Page2

 前回は、基礎知識としてWPFやSilverlightのデータグリッド(=DataGridコントロール)の機能性を簡単に知るために、Windowsフォーム版およびASP.NET Webフォーム版と横並びにして比較した。今回は、それらの具体的な開発方法の説明に入っていこう。

連載:.NETグリッド・コントロール大研究 第4回 ドラッグ&ドロップで作るWindowsデータベース・アプリケーション Page2(Windowsフォーム版)
連載:VS 2005でいってみようDBプログラミング 第2回 Page2 データベースの内容をグリッド表示する(ASP.NET Webフォーム版)

 本稿の前半では「WPF」のデータグリッド、後半では「Silverlight」のデータグリッドを活用した開発の基本手順を解説する。「まずは何とか作れるようになる」ことを目的としているので、「取りあえず、簡単に開発を試したい」という方を読者ターゲットとしている。

 なお、本特集の前提条件として、すべてのサンプル・プログラムやスクリーン・キャプチャにVisual Studio 2010(以降、 VS 2010)を使用する。またSilverlightとその開発環境は、バージョン「4」を使用する。データベース・エンジンとしてSQL Server 2008 Express Editionを、データベースとして「AdventureWorks」を利用する(AdventureWorksのインストール/利用方法については、「.NET TIPS:サンプル用のデータベース・ファイル(.mdfファイル)を入手するには?」を参照されたい)。

WPFデータグリッド開発の基本手順

 WPF版のデータグリッドの使い方は、Windowsフォーム版やASP.NET Webフォーム版のそれとほぼ同じだ。なお以下では、データ・ソース(Data Source:データ元)としてデータセット(DataSet)を使用する場合の手順を説明する(LINQ to SQLやEntity Frameworkを使用する場合については、後述の「WPFデータグリッド開発の基礎知識」で紹介)。

データセットの作成

 具体的には、まず、データセットを作成する。今回は、(Webサービスなどの外部にデータセットを持つのではなく)WPFアプリケーション内部に直接、データセットを持つようにする。

 [ソリューション エクスプローラー]でWPFアプリケーションのプロジェクト項目を右クリックして、表示されるコンテキスト・メニュー(以降、右クリック・メニュー)から[追加]−[新しい項目]をクリック。これにより[新しい項目の追加]ダイアログが表示されるので、次の画面のように、左側のツリーから「データ」を選択し、右側のリストから「データセット」テンプレートを選択し、任意の[名前]を入力して、[追加]ボタンをクリックする。

データセットの作成([新しい項目の追加]ダイアログ)

 これにより、データセット・ファイル(.xsdファイル)が生成され、それがデータセット・デザイナ(=中央のエディタ/デザイナ部分)で開かれる。

データセットへのテーブルの追加

 次に[サーバー エクスプローラー](または、VS 2010 Expressでは[データベース エクスプローラー]。いずれもメニューバーにある[表示]メニューの下位メニューから選択できる)で、[データ接続]項目の右クリック・メニューから[接続の追加]をクリックして、SQL Serverデータベースへの接続を追加する。そして、次の画面のように、[データ接続]項目の下位階層を開いていき、[<追加した接続名>]−[テーブル]の直下にあるテーブル群から、使用したいテーブル項目を、データセット・デザイナのデザイン・サーフェイス上にドラッグ&ドロップする。

データセットへのテーブルの追加(データセット・デザイナ)

 これにより、データセット・デザイナに「データセットのデータテーブル*1 +テーブルアダプタ*2」の図が表示される。今回は、ここでは何も変更せずに初期状態のまま利用する。

*1 データテーブルとは、データセットに含まれる表形式データのこと。データベースにテーブルが含まれているように、データセットにはデータテーブルが含まれている。詳しくは「連載:Visual Studio 2005によるWindowsデータベース・プログラミング 第2回 データセットとデータテーブル」を参照されたい。
*2 テーブルアダプタとは、データテーブルとデータベースの橋渡し役となるコンポーネントである。詳しくは「連載:Visual Studio 2005によるWindowsデータベース・プログラミング 第3回 テーブルアダプタの基礎」を参照されたい。

[データ ソース]ウィンドウの表示

 WPFでは、このようにして作成したデータセットは、データ・ソースとして利用できる。そこで、[データ ソース]ウィンドウを表示しよう。

 これには、データセット・デザイナを開いたままの状態で、メニューバーから[データ]−[データ ソースの表示]を実行すればよい。

[データ ソース]ウィンドウに表示されたデータセットの内容

 [データ ソース]ウィンドウには、プロジェクト内に作成されている、すべてのデータセットの内容(本稿の例では「DataSet1」のみ)が、[<データセット名>]−[<テーブル名>]−[<列(=カラム)名>]という階層構造のツリー形式で表示される。列項目などを編集したい場合には、先ほどのデータセット・デザイナを開いて、データセット側を編集する必要がある。

[データ ソース]ウィンドウでの各列項目に使用するコントロールの選択

 次に、XAMLコードをWPF版のXAMLデザイナで開く。具体的には、[ソリューション エクスプローラー]にある該当のファイル項目(本稿の例では「MainWindow.xaml」)をダブルクリックする。

 これにより、[データ ソース]ウィンドウの表示が少し変わり、テーブル内の各列項目を選択すると右端に[▼]ボタンが表示されるようになる。この[▼]ボタンをクリックすると、次の画面のようにWPFコントロールの選択リスト([TextBox][ComboBox][Label][TextBlock][[なし]][カスタマイズ])が表示されるので、適宜、使用目的に応じて選択する。

[データ ソース]ウィンドウでの各列項目に使用するWPFコントロールの選択

 なお、[[なし]]を指定すると、その列はデータグリッドに表示されない。

 また、選択リストから[カスタマイズ]をクリックすると、次の画面のような[コントロールのバインドのカスタマイズ]ダイアログが表示される。

選択リストへのコントロールの追加([コントロールのバインドのカスタマイズ]ダイアログ)

 このダイアログでは、[データ型]に結び付けるコントロール群を、[関連付けられたコントロール]リストの各チェックボックスにチェックを入れることで指定できる。

 ちなみに、[関連付けられたコントロール]リストには、独自に作成したコントロールなども表示できる。その具体的な方法は、「MSDN:方法: [データ ソース] ウィンドウにカスタム コントロールを追加する」の「データ型に関連付けられたコントロールの一覧へのコントロールの追加」の説明をご参照いただきたい。

 例えば、列のデータ型が「Integer」のときに、選択リストの項目として[Button]を表示し、これによりボタン(=Buttonコントロール)を選択できるようにしたい場合は、[Button]項目のチェックボックスにチェックを入れればよい。

 こうやって[データ型]に結び付けたコントロール群は、[データ ソース]ウィンドウの各列項目のデータ型に応じて選択リストに表示されるようになる。例えば次の画面の例では、Integer型の列項目「CustomerID」のコントロール選択リストに、[Button]が表示されている。

追加したコントロールの選択リストの表示例([データ ソース]ウィンドウ)

[データ ソース]ウィンドウを利用したWPFデータグリッドの追加

 後は、いつもどおり、[データ ソース]ウィンドウからテーブル項目(=「データ・バインド・コントロール」の一種。詳細後述)を、(XAMLデザイナのデザイン・サーフェイス上に配置された)ウィンドウ(=<Window>要素)やパネルの上にドラッグ&ドロップすればよい。本稿では、Gridパネル(=<Grid>要素)の上にドラッグ&ドロップした。その結果が次の画面だ。

[データ ソース]ウィンドウを利用したデータグリッドの追加(WPFのXAMLデザイナ)

 XAMLコード内にDataGridコントロール(=<DataGrid>要素)が追加される。<Window.Resources>要素により、データセット(本稿の例では「DataSet1」)と(データセットの表示とデータ移動を管理する)CollectionViewSourceオブジェクトがリソースとして追加されており、そのリソースが<DataGrid>要素にデータ・バインディングされている。詳しい説明は割愛するが、出力されたコードは以下のとおり。

<Window
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 xmlns:my="clr-namespace:DataGridSampleWPF"
    x:Class="DataGridSampleWPF.MainWindow" Title="MainWindow"
    Height="300" Width="400" Loaded="Window_Loaded">
  <Window.Resources>
    <my:DataSet1 x:Key="dataSet1" />
    <CollectionViewSource x:Key="customerViewSource" Source=
      "{Binding Path=Customer, Source={StaticResource dataSet1}}"
      />
  </Window.Resources>
  <Grid DataContext="{StaticResource customerViewSource}">
    <DataGrid
        AutoGenerateColumns="False"
        EnableRowVirtualization="True"
        Height="200"
        HorizontalAlignment="Left"
        ItemsSource="{Binding}"
        Margin="64,52,0,0"
        Name="customerDataGrid"
        RowDetailsVisibilityMode="VisibleWhenSelected"
        VerticalAlignment="Top" Width="400">
      <DataGrid.Columns>
        <DataGridTextColumn x:Name="customerIDColumn"
            Binding="{Binding Path=CustomerID}"
            Header="Customer ID" IsReadOnly="True"
            Width="SizeToHeader" />
        <DataGridCheckBoxColumn x:Name="nameStyleColumn"
            Binding="{Binding Path=NameStyle}"
            Header="Name Style" Width="SizeToHeader" />
        <DataGridTextColumn x:Name="titleColumn"
            Binding="{Binding Path=Title}"
            Header="Title" Width="SizeToHeader" />
        <DataGridTextColumn x:Name="firstNameColumn"
            Binding="{Binding Path=FirstName}"
            Header="First Name" Width="SizeToHeader" />
        ……同じような出力のため、省略……
        <DataGridTemplateColumn x:Name="modifiedDateColumn"
            Header="Modified Date" Width="SizeToHeader">
          <DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
              <DatePicker SelectedDate="{Binding Path=ModifiedDate, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" />
            </DataTemplate>
          </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
      </DataGrid.Columns>
    </DataGrid>
  </Grid>
</Window>
データグリッドを追加した後のXAMLコード例

 DataGridコントロールの列項目として、<DataGridTextColumn>要素や<DataGridCheckBoxColumn>要素や<DataGridTemplateColumn>要素が追加されているのが分かる。前回も説明したが、WPFのデータグリッドでは、標準の列フィールド用のコントロールとして、

  • テキストボックス(=<DataGridTextColumn>要素)
  • チェックボックス(=<DataGridCheckBoxColumn>要素)
  • ハイパーリンク(=<DataGridHyperlinkColumn>要素)
  • コンボボックス(=<DataGridComboBoxColumn>要素)

が用意されている。これら以外のコントロールを使う場合は、

  • カスタムの列フィールド(=<DataGridTemplateColumn>要素)

を用いる必要がある。前述のように、[データ ソース]ウィンドウの[コントロールのバインドのカスタマイズ]ダイアログで、[データ型]に結び付けるコントロールとしてボタンを追加した場合も、同様に<DataGridTemplateColumn>要素のコントロールとして自動生成される。

 また、コードビハインド・ファイル(MainWindow.xaml.cs/MainWindow.xaml.vb)には、下記のようなコードが自動生成される。

using System.Windows;
using System.Windows.Data;

namespace DataGridSampleWPF
{
  public partial class MainWindow : Window
  {
    public MainWindow()
    {
      InitializeComponent();
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
      DataSet1 dataSet1 =
        ((DataSet1)(this.FindResource("dataSet1")));
      // テーブル Customer にデータを読み込みます。
      // 必要に応じてこのコードを変更できます。
      DataSet1TableAdapters.CustomerTableAdapter
        dataSet1CustomerTableAdapter =
          new DataSet1TableAdapters.CustomerTableAdapter();
      dataSet1CustomerTableAdapter.Fill(dataSet1.Customer);
      CollectionViewSource customerViewSource =
        ((CollectionViewSource)(
          this.FindResource("customerViewSource")));
      customerViewSource.View.MoveCurrentToFirst();
    }
  }
}
Class MainWindow

  Private Sub Window_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded

    Dim DataSet1 As DataSet1 = _
      CType(Me.FindResource("DataSet1"), DataSet1)
    ' テーブル Customer にデータを読み込みます。
    ' 必要に応じてこのコードを変更できます。
    Dim DataSet1CustomerTableAdapter _
      As DataSet1TableAdapters.CustomerTableAdapter = _
      New DataSet1TableAdapters.CustomerTableAdapter()
    DataSet1CustomerTableAdapter.Fill(DataSet1.Customer)
    Dim CustomerViewSource As CollectionViewSource = _
      CType(Me.FindResource("CustomerViewSource"), CollectionViewSource)
    CustomerViewSource.View.MoveCurrentToFirst()
  End Sub
End Class
データグリッドにデータセット側のデータを反映させるコード(上:C#、下:VB)

WPFデータグリッドの位置調整とWPFアプリケーションの実行

 最後に、データグリッドをGridパネルいっぱい、つまりウィンドウいっぱいまで広げよう。これには、XAMLデザイナでDataGridコントロールを選択した状態で、[プロパティ]ウィンドウの[レイアウト]グループにある[Width][Height][Margin]プロパティに指定されている値を、それぞれ削除して空にする。これにより、Gridパネル全体にDataGridコントロールが広がる。

 それでは、WPFアプリケーションを実行してみよう。次の画面はその実行例だ。

WPFのデータグリッドの実行例

WPFデータグリッド開発の基礎知識

(データグリッドではなく)リストや詳細の追加

 ここまでは、データグリッドの追加手順を説明した。しかし実際には、デフォルトのデータグリッド以外にも、「リスト」(=ListViewコントロール)や「詳細」(=Gridパネル内に並べられたLabelコントロール+TextBoxコントロールなど)を、[データ ソース]ウィンドウからのドラッグ&ドロップで追加することが可能だ(なお、これらをまとめて「データ・バインド・コントロール」と呼ぶ)。

 リストやグリッドを追加するには、[データ ソース]ウィンドウのテーブル項目を選択する。これにより、右端に[▼]ボタンが表示されるのでこれをクリックする。すると、次の画面のようにWPFデータ・バインド・コントロールの選択リスト([データグリッド][リスト][詳細][[なし]][カスタマイズ])が表示されるので、適宜、目的に応じて選択すればよい。

[データ ソース]ウィンドウでの各テーブルに使用するWPFデータ・バインド・コントロールの選択

 なお、[[なし]]を指定すると、そのテーブルはWPF XAMLデザイナのデザイン・サーフェイス上へドラッグ&ドロップできなくなる。

 また、選択リストから[カスタマイズ]をクリックすると、[コントロールのバインドのカスタマイズ]ダイアログが表示される。このダイアログの使い方は、前述したとおりなので、説明を割愛する。独自にデータ・バインド・コントロールを作成したい場合も、前に示したMSDNの解説を参照していただきたい。

[ツールボックス]を利用したデータグリッドの追加

 今回は[データ ソース]ウィンドウを利用してデータグリッドを追加する手順を示した。この手順以外にも、[ツールボックス]の[コモン WPF コントロール]タブ内にある[DataGrid]項目(次の画面を参照)を、WPF XAMLデザイナのデザイン・サーフェイス上にドラッグ&ドロップすることでも、データグリッドを追加できる。

[ツールボックス]を利用したデータグリッドの追加

 しかしこの手法の場合、当然ながら、データ・ソース部分の設定を手動で行わなければならない。この作業の手間の分、[データ ソース]ウィンドウを利用する手法の方が、開発が手軽である。特に理由がなければ、本稿で示した手順によりデータグリッドを追加することをお勧めする。

Entity FrameworkのEDMをデータ・ソースとする場合について

連載:ADO.NET Entity Framework入門

 データ・ソースとして、データセットではなくEntity FrameworkのEDM(=エンティティ・データ・モデル)を使う場合は、[新しい項目の追加]ダイアログの「データ」カテゴリから「ADO.NET Entity Data Model」テンプレートを選択してEDMファイル(.edmxファイル)を作成する。その作成時に[Entity Data Model ウィザード]が立ち上がるので、そこでSQL Serverデータベースのテーブルを選択する。

 EDMの作成が完了した状態で、[データ ソース]ウィンドウにテーブル項目が表示されるようになる。後は、データセットの場合と同じように、[データ ソース]ウィンドウからドラッグ&ドロップするだけでデータグリッドを追加できる。

LINQ to SQLをデータ・ソースとする場合について

特集:VBプログラマーのためのLINQ超入門(後編) LINQによるデータベース・アクセスとO/Rマッピング Page2
特集:C#プログラマーのためのLINQ超入門(後編) LINQによるデータベース・アクセスとO/Rマッピング Page2

 またLINQ to SQLを使う場合は、[新しい項目の追加]ダイアログの「データ」カテゴリから「LINQ to SQL クラス」テンプレートを選択して、データベース・マークアップ言語ファイル(.dbmlファイル)を作成する。作成後、O/Rデザイナ(=オブジェクト/リレーショナル・デザイナ)が表示されるので、[サーバー エクスプローラー](もしくは[データベース エクスプローラー])にあるSQL Serverデータベースのテーブル項目(本稿の例では「Customer」)を、そのデザイン・サーフェイス上にドラッグ&ドロップする。これにより、テーブルとマッピングされたエンティティ・クラス(本稿の例では「Customer」)が自動作成される。

 しかしこの状態では、[データ ソース]ウィンドウを表示しても、LINQ to SQLに追加したテーブルのエンティティ(=エンティティ・クラスのオブジェクト)は表示されない。そこで、テーブル・エンティティを「オブジェクト」のデータ・ソースとして、[データ ソース]ウィンドウに追加する。その一連の操作手順を、スクリーン・キャプチャ画像で示しておこう。

[新しいデータ ソースの追加]ボタンをクリック
「オブジェクト」を選択
先ほど自動作成されたエンティティ・クラスを選択
[データ ソース]ウィンドウへのLINQ to SQLエンティティの追加
[データ ソース]ウィンドウの上部左端にある[新しいデータ ソースの追加]ボタンをクリックして[データ ソース構成ウィザード]を起動する。そこで、データ・ソースの種類として「オブジェクト」を選択し、データ・バインディングする(データ・ソース側の)オブジェクトとして、先ほど自動作成されたエンティティ・クラス(本稿の例では「Customer」)を選択する。[完了]ボタンをクリックして、[データ ソース構成ウィザード]を閉じると、LINQ to SQLのテーブル・エンティティが[データ ソース]ウィンドウに表示される。

 後は、データセットやEntity Frameworkの場合と同じだ。[データ ソース]ウィンドウからドラッグ&ドロップするだけでデータグリッドを追加できる。

【コラム】XBAPの場合の注意点

 WPFのXAMLコードとほぼ同等の内容を、Webブラウザに表示できるXBAP(=WPF XAMLブラウザ・アプリケーション)という機能が提供されている。そこでデータグリッドを使う場合、上記のWPFの手順と同様に行えばよい。ただし、開発方法は同じでも、運用環境が異なるので、注意が必要だ。

 XBAPはWebブラウザ上で実行されるという性質上、サンドボックス(=セキュリティ制限がかかった環境)内でプログラムが動作する。このため、(インターネット・ゾーンやイントラネット・ゾーンで)アクセス許可(Permission)が得られていないコード、例えば今回の例のようにSQL Serverデータベースにアクセスしようとすると、「SqlClientPermission例外(System.Data.SqlClient名前空間)」が発生してしまうという問題がある。

 データベース・アクセスの問題を回避するには、データ・アクセス処理をWCF Webサービスなどでサーバ側に分離するか、XBAP自体のアクセス許可を適切に設定するか(=部分信頼:Partial Trust)、もしくは完全信頼(Full Trust)権限を付与する必要がある。最も手軽に済ませたい場合は、完全信頼を採用するとよい。特に、セキュリティ上の問題が少ない社内ネットワークであれば、完全信頼がお勧めだ。

 実際にXBAPを完全信頼モードに設定するには、次の画面のように、プロジェクト・プロパティの[セキュリティ]タブを開き、[ClickOnce セキュリティ設定を有効にする]チェックボックスにチェックを入れて、[これは完全に信頼するアプリケーションです]ラジオボタンを選択して、設定を保存すればよい。

XBAPに完全信頼権限を付与する設定(プロジェクト・プロパティ)

 続いて、Silverlight版のデータグリッドについて説明する。


 INDEX
  特集:WPF/Silverlight時代のDataGrid速習講座(前編)
  WPF/Silverlightデータグリッド・コントロールの基礎と比較
    1.各UI技術のデータグリッドの比較:エンド・ユーザー視点
    2.各UI技術のデータグリッドの比較:開発者視点
 
  特集:WPF/Silverlight時代のDataGrid速習講座(後編)
  初めてのWPF/Silverlightデータグリッド開発
  1.WPFデータグリッド開発の基本手順
    2.Silverlightデータグリッド開発の基本手順


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)
- PR -

イベントカレンダー

PickUpイベント

- PR -

アクセスランキング

もっと見る

注目のテーマ

業務アプリInsider 記事ランキング

本日 月間
ソリューションFLASH