はじめに
Visual Studio 2005では、WindowsアプリケーションとSmart Clientアプリケーションを短期間で構築できるように、さまざまな点がすばらしく向上しています。[Data Sources]パネルを使えば、各種コントロールをフォームに配置し、それらをBindingSourceコンポーネントでバインドするという操作が自動で行えます。BindingNavigatorコンポーネントには非常に大きな可能性が隠されており、ほんの少しの拡張を加えるだけで、ナビゲーション機能とデータアクセスに関するCRUD(Create、Read、Update、Delete=作成、更新、取得、削除)機能をほぼ自動的に実装することができます。本稿では、BindingNavigatorコンポーネントの機能を拡張するユーザーコントロールの作成方法を示します。
以前の記事では、Visual Studio 2005のRAD機能に焦点を当て、ビジネス層とデータアクセス層を自動生成することですばやくN階層のWindowsアプリケーションを作成する方法を説明しました。本稿では、以前の記事で取り上げた概念に基づいて、より迅速なアプリケーション開発を実現するコードテンプレートとユーザーコントロールのシンプルなアーキテクチャを紹介します。
今回のアーキテクチャでは、ユーザーコントロール内のBindingNavigatorコンポーネントを拡張して、編集済みデータの保存機能を自動生成するようにしています。そのためには、Bining Sourceコントロールを拡張し、インターフェイステンプレートをデータアクセスロジックに追加する必要があります。
Visal Studio 2005のBindingNavigatorコンポーネント
新しくVisual Studio 2005のRADツールに加わったこの機能を理解するために、実際に使ってみることにしましょう。新しいアプリケーションを作成し、Northwindデータベースの「Customer」テーブルと「Order」テーブルを使用して、新しいデータソース(DataSet)を追加します(詳しい手順は、筆者の前の記事を参照してください)。
[Data Sources]パネルの[Typded Dataset]からテーブルやフィールドをドラッグしてフォームにドロップすると、すぐに使えるバインド済みのデータアクセスロジックが作成されます。先ほど作成した新しいデータソースの「Customer」テーブルをフォームにドラッグしてください。すると、ウィザードによってそのデータセットのインスタンスが作成され、さらに、そのデータセット内のテーブルにリンクされるBindingSourceコンポーネントと、このバインディングソースにリンクされるBindingNavigatorコンポーネントが作成されます。データセットがプロジェクトにとってローカルである場合は、さらにテーブルアダプタのインスタンス化が行われ、Fill
メソッドの呼び出しが追加されます(ただし、オブジェクトデータソースを使っている場合は、このコードを手作業で追加する必要があります)。
BindingNavigatorコンポーネントによって、ユーザーがレコード間をナビゲートするための一連のツールがフォームの最上部に配置されます。最初のレコード、前のレコード、次のレコード、最後のレコードに移動するためのボタンと、インデックス番号を指定して特定のレコードに直接移動するためのフィールドがあります。
レコードの追加と削除、そして編集結果の保存を行うためのボタンも追加されます。保存用のボタン(フロッピーディスクのアイコン)は、標準的なナビゲーションバーの一部ではなく、データソースウィザードによって特別に追加されます。本稿を執筆するきっかけとなったのは、この保存ボタンです。
データセットがプロジェクトにローカルである場合は、保存ボタンがナビゲーションバーに追加されるときに、適切なコードが生成されます(オブジェクトデータソースを使用する場合は、この限りではありません)。「Customer」テーブル用には、次のメソッドが追加されます。
Private Sub CustomersBindingNavigatorSaveItem_Click( _ ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles CustomersBindingNavigatorSaveItem.Click Me.Validate() Me.CustomersBindingSource.EndEdit() Me.CustomersTableAdapter.Update(Me.NorthwindDataSet.Customers) End Sub
Validate
コマンドは、コントロールの編集を終わらせます。バインディングソースのEndEdit
メソッドは、コントロール内の編集済みデータをすべてデータセットのレコードに書き戻します。テーブルアダプタのUpdate
コマンドは、更新済みレコードをデータベースに反映させます。
この新しいコントロールは大幅な拡張であり、通常はこれで、データバウンドフォームに関するナビゲーションとCRUDのニーズの大部分を満たすことができます。しかし、データバウンドフォームのニーズすべてに対処する完全なツールを作るには、いくつか足りない点があります。克服しなければならない問題としては、次のようなものがあります。
- オブジェクトデータソースを使う場合は、データテーブルへのデータ読み込みおよびデータテーブルの更新を行うためのコードがウィザードによって自動生成されません。このコードは手作業で追加する必要があります。
- データを編集したときは、ユーザーが忘れずに保存ボタンをクリックしなければなりません。データが変更されても、
IsDataDirty
フラグはセットされません、そのため、ユーザーがレコードを変更し、保存しないままでいても警告メッセージは表示されません。 - レコードを削除する場合も、警告または確認メッセージは表示されません。
- ナビゲーションバーには、特定レコードをルックアップする手段も必要です。
汎用的なテーブル更新インターフェイス
1番目の問題に対処するには、データテーブルのデータ読み込み(Fill
)と更新(Update
)を実行する、汎用的なコードを作成する必要があります。筆者の以前の記事のパート3では、データアクセスロジックをビジネス層にラップしてしまうコードを紹介しました。その後、この構造に少し手を加え、データテーブルのサブクラスを利用してメソッドの一貫性を高めるように書き換えました。この一貫性を実現するには、個々のテーブルクラスがラッパー内で実装するインターフェイスを作成する必要があります。
- ソリューションエクスプローラでプロジェクトを右クリックし、[Add]-[New Item]を選択します(多層アプリケーションの場合は、これはビジネス層で行うべき処理ですが、話を簡単にするために、ここではまずWindowsプロジェクトに格納して、後から移動することにします)。
- [Choose a Class]を選び、「_Interface」と名前を付けます(先頭にアンダーバーを付けることで、ソート時にこのクラスが一番上に来るようにしています)。このクラスを、汎用的なメソッドを持ち、プログラム全体を通じてアクセスできるユーティリティ的なクラスにします。
_Interface
クラス内に、Fill
メソッドとUpdate
メソッドを要求する「ITableUpdate」という名前のインターフェイスを作成します。
Public Class _Interface ''' <summary> ''' Interface for Data table in a dataset ''' to standardize fill and update methods ''' </summary> Public Interface ITableUpdate Sub Fill() Sub Update() End Interface End Class
データセットの背後にあるパーシャルクラス(データセットを右クリックして[View Code]をクリックすると表示されます)内で、データセット内の更新可能なテーブル1つ1つに対して次のテンプレートコードを作成します。この例では、「NorthwindDataSet」テーブルに関するCustomer
クラスを実装しています。
Partial Class NorthwindDataSet Shared taCustomer As New _ NorthwindDataSetTableAdapters.CustomersTableAdapter Partial Class CustomersDataTable Implements _Interface.ITableUpdate Public Sub Fill() Implements _Interface.ITableUpdate.Fill taCustomer.Fill(Me) End Sub Public Sub Update() Implements _Interface.ITableUpdate.Update taCustomer.Update(Me) End Sub End Class End Class
このインターフェイスを実装することにより、どのテーブルでも汎用的なUI呼び出しが使えるようになります。つまり、Save
メソッドは、「Customer」テーブル用の更新メソッドを呼び出す代わりに、汎用的なコードを使って更新を呼び出せるようになります。保存ルーチンを一度書いておけば、個々のテーブル用にいちいちコードを書き直さなくても、同じコードを再利用できるというわけです。