![]() ![]() ![]() ![]() オブジェクトバインディングに関するヒントとテクニックこの記事のURLhttp://japan.internet.com/developer/20060516/25.html
著者:Deborah Kurata
海外internet.com発の記事
はじめに筆者は、Visual Basic 2.0以来、データバインディングの概念を嫌ってきた多くの開発者の1人でした。データバインディングの仕組みは拡張性が低く、有益なプログラミング手法を活用していないし、期待通りに動作しないこともしょっちゅうでした。しかし、今はオブジェクトバインディングの愛好者であることを認めざるを得ません。 本稿では、まず、オブジェクトバインディングの基本について説明します。次に、オブジェクトバインディングをよりよく活用するためのヒントとテクニックを示します。オブジェクトバインディングで実行できることをすべて理解したならば、読者もこれが気に入ることでしょう。 オブジェクトバインディングの基本 Windows Formsにおけるオブジェクトバインディングの大前提は、 例えば、顧客情報を表示するフォームと、 データベースへのバインディングでは、あらかじめ生成されている大量のコードにバインドする必要がありますが、それに対してオブジェクトバインディングでは、自分で記述したコードにバインドします。そのため、自分で多くを管理することが可能であり、アプリケーションのメンテナンスが非常に簡単です。 オブジェクトバインディングを試すために、新しいWindows Formsプロジェクトを作成し、クラスを1つ追加してみましょう(実際のアプリケーションでは、このクラスを別のプロジェクトに含める場合もあります。このサンプルでは、話を簡単にするために、すべてのクラスをWindows Formsプロジェクトに追加します)。次に、そのクラスにさまざまなプロパティを持たせます。例えば、 VBの場合
Private _LastName As String Public Property LastName() As String Get Return _LastName End Get Set(ByVal value As String) _LastName = value End Set End Property C#の場合
private string _LastName; public string LastName { get { return _LastName;} set { _LastName = value;} } プロパティプロシージャを作成するには、Propertyスニペットを使用するのが最も簡単です。VBコードウィンドウで「property」と入力し、[Tab]キーを押して、VB Propertyプロシージャを作成します。C#コードウィンドウでは、「prop」と入力し、[Tab]キーを2回押してプロパティを作成します。スニペットの使用または独自のスニペットの作成の詳細については、『CoDe Magazine』2006年1月/2月号の「Having Fun with Code Snippets」を参照してください。 ビジネスオブジェクト上で目的のプロパティを定義したら、プロジェクトをビルドします。ビルドプロセスによって、[Data Sources]ウィンドウからビジネスオブジェクトにアクセスできるようになります。ビジネスオブジェクトにプロパティを追加する場合はいつでも、[Data Sources]ウィンドウにプロパティが表示される前に、プロジェクトをリビルドする必要があります。 次に、データソースをビルドします。[Data Sources]ウィンドウが表示されていない場合は、[Data]ウィンドウの[Show Data Sources]を選択して表示し、[Add New Data Source]をクリックします。データソース構成ウィザードが起動します。 オブジェクトバインディングデータソースを作成するには、ウィザードの先頭のページで[Object]を選択し、2番目のページで目的のビジネスオブジェクトを選択します。[Finish]ボタンをクリックすると、[Data Sources]ウィンドウに新しいオブジェクトデータソースが表示されます。オブジェクトの各プロパティが、ウィンドウ内のオブジェクト名の下に表示されることに注意してください。 さて、これからが本番です。プロジェクトを作成するときに作成された既定のフォームを開きます。[Data Sources]ウィンドウ内のビジネスオブジェクトに関連するコンボボックスをドロップダウンし、[DataGridView]を選択して、すべてのビジネスオブジェクトをグリッドで表示するか、[Details]を選択して、個々のビジネスオブジェクトプロパティをフォーム上の個別のコントロールとして表示します。最後に、[Data Sources]ウィンドウからフォームへ、ビジネスオブジェクトの名前をドラッグします。図1は、[Details]セクションを使った場合の結果を示しています。[Data Sources]ウィンドウによるフォーム作成の詳細については、『CoDe Magazine』2004年9月/10月号の「Drag-Once Databinding」を参照してください。 図1 既定では、ビジネスオブジェクトをフォームにドラッグすると、BindingNavigator(ビデオデッキのボタンに似たコントロールツールバー)もフォームに追加される。これが不要な場合は削除する。 ![]() オブジェクトバインディングデータソースは、フォームのコンポーネントトレイに自動的に追加され、ビジネスオブジェクトの名前にちなんだ名前が付けられます。この例の場合は、「CustomerBindingSource」です。生成されるコントロールは、このバインディングソースに自動的にバインドされます。 Visual Studio IDEは、プロパティの名前を使ってコントロールのラベルを作成しますが、アンダースコアや英字の大文字/小文字に基づいて単語間に空白を追加したりできます。これは、アプリケーションのユーザーインターフェイスの開始点として、非常に優れています。 ビジネスオブジェクトに値を割り当てるこの時点でアプリケーションを実行しても、何も表示されません。コントロールはプロパティにバインドされていますが、プロパティに値がないのです。そこで、ビジネスオブジェクトに値を割り当てることが、オブジェクトバインディングの次の大きなステップになります。 データを取得してビジネスオブジェクトに割り当てるには、さまざまな方法があります。例えば、DataSetまたはDataTableを使用する方法や、Webサービスを使って必要なデータを取得する方法があります。また、TableAdaptersを使って、プロパティをデータベースフィールドにバインドする方法もあります。 話を簡単にするために、ビジネスオブジェクトのプライベートな リスト1 テスト用の一時的な^^Retrieve^^メソッド(VB)
Private Function Retrieve(ByVal CustomerID As Int32) As DataRow Dim dt As New DataTable ’ Define the columns dt.Columns.Add("CustomerID") dt.Columns.Add("LastName") dt.Columns.Add("FirstName") Select Case CustomerID Case 1 dt.Rows.Add(1, "Einstein", "Albert") Case 2 dt.Rows.Add(2, "Curie", "Marie") Case 3 dt.Rows.Add(3, "Brahe", "Tycho") Case 4 dt.Rows.Add(4, "Faraday", "Michael") End Select Return dt.Rows(0) End Function リスト2 テスト用の一時的な^^Retrieve^^メソッド(C#)
private DataRow Retrieve(Int32 CustomerID) { DataTable dt = new DataTable(); // Define the columns dt.Columns.Add("CustomerID"); dt.Columns.Add("LastName"); dt.Columns.Add("FirstName"); switch (CustomerID) { case 1: dt.Rows.Add(1, "Einstein", "Albert"); break; case 2: dt.Rows.Add(2, "Curie", "Marie"); break; case 3: dt.Rows.Add(3, "Brahe", "Tycho"); break; case 4: dt.Rows.Add(4, "Faraday", "Michael"); break; } return dt.Rows[0]; } ベストプラクティスでは、Factoryパターンを使ってビジネスオブジェクトを作成し、これに取得データを割り当てます。Factoryパターンを実装するには、さまざまな方法があります。今回の例では、次に示すように、Factoryパターンの実装によってコンストラクタをプライベートにし(これで他のコードはオブジェクトを作成できなくなります)、インスタンスの作成と値の割り当てを行う静的な(共有の) VBの場合
Private Sub New() ’ Don’t allow creation of this object End Sub Public Shared Function Create(ByVal CustomerID _ As Int32) As Customer ’ Create the customer Dim oCustomer As New Customer ’ Retrieve the data for this customer Dim dr As DataRow dr = oCustomer.Retrieve(CustomerID) ’ Populate the business object oCustomer.Populate(dr) Return oCustomer End Function C#の場合
private Customer() { // Don’t allow creation of this object } public static Customer Create(Int32 CustomerID) { // Create the customer Customer oCustomer = new Customer(); // Retrieve the data for this customer DataRow dr =oCustomer.Retrieve(CustomerID); // Populate the business object oCustomer.Populate(dr); return oCustomer; } 実際にビジネスオブジェクトへの値の割り当てを行うメソッドは、次のようになります。 VBの場合
Private Sub Populate(ByVal CustomerDataRow As _ DataRow) With CustomerDataRow Me.LastName = .Item("LastName").ToString Me.FirstName = .Item("FirstName").ToString Me.CustomerID = .Item("CustomerID").ToString End With End Sub C#の場合
private void Populate(DataRow CustomerDataRow) { this.LastName = CustomerDataRow["LastName"].ToString(); this.FirstName = CustomerDataRow["FirstName"].ToString(); this.CustomerID = Convert.ToInt32(CustomerDataRow["CustomerID"]); } ビジネスオブジェクトにプロパティを追加するたびに、 オブジェクトバインディングを完成させるには、フォームの VBの場合
Private Sub CustomerWin_Load(ByVal sender As _ Object, ByVal e As System.EventArgs) _ Handles Me.Load Dim CustomerInstance As Customer CustomerInstance = Customer.Create(1) CustomerBindingSource.DataSource = CustomerInstance End Sub C#の場合
private void CustomerWin_Load(object sender, EventArgs e) { Customer CustomerInstance = Customer.Create(1); customerBindingSource.DataSource = CustomerInstance; } この時点で、アプリケーションを実行できます。問題がなければ、フォームが表示され、そのフォーム上のコントロールにプロパティ値がテキストとして表示されます。 データ管理フォーム上の値の更新をユーザーに許可する場合は、その値を検証する必要が生じます。すべての値が有効なときは、変更を保存するオプションを提供するようにします。オブジェクトバインディングは、検証およびデータ管理プロセスを支援するいくつかの機能を備えています。 オブジェクトバインディングを使って検証を実装するには、最初に、ErrorProviderコントロールをフォームに追加し、そのバインディングソースを、本稿で作成したCustomerBindingSourceに設定します。これにより、ErrorProviderはビジネスオブジェクトからのエラーを認識できるようになります。 ErrorProviderを設定したら、ビジネスオブジェクトのプロパティに直接、フィールドレベルの検証ルールを実装します。プロパティが無効な場合は、例外をスローします。ユーザーが入力した値が無効の場合は、ErrorProviderアイコンに例外のテキストが自動的に表示されます。 簡単な例として、Customerビジネスオブジェクトに、ユーザーに姓の入力を求めるビジネスルールがあるものとします。これは、次のように実装できます。 VBの場合
Public Property LastName() As String Get Return _LastName End Get Set(ByVal value As String) If String.IsNullOrEmpty(value) Then Throw New Exception( _ "The Last Name cannot be empty") End If _LastName = value End Set End Property C#の場合
public string LastName { get { return _LastName;} set { if (String.IsNullOrEmpty(value)) { throw new Exception( "The Last Name cannot be empty"); } _LastName = value; } } 注意
プロパティプロシージャ内のコード、またはプロパティプロシージャによって呼び出されるコードが原因で生じる予期せぬ例外は、オブジェクトバインディングによってキャッチされ、ErrorProviderに表示されます。このため、例えばキャストエラーがあっても、このエラーを目にすることはありません。オブジェクトバインディングコードがこのエラーをキャッチして、ErrorProviderアイコンに表示します。
適切な検証コードをビジネスオブジェクトプロパティに直接追加することができ、必要であれば例外をスローできます。もっと柔軟で再利用性に優れた検証処理が必要な場合は、独立した ユーザーの入力値を検証したら、ビジネスオブジェクトは、値の変更を追跡する必要があります。これによって、何らかの変更があった場合のみ、終了時に変更を保存するかどうかをユーザーに確認するなどの機能を実装できるようになります。また、オブジェクトの更新、作成、または削除を追跡し、元のデータソースにさかのぼって適切な処理を実行することができます。 このデータ管理では、次の4つの基本ステップが必要です。
この4ステップを実装するにあたり、最も直接的なのは、必要なコードの大部分をすべてのビジネスオブジェクトクラスで繰り返すという方法です。もっと洗練された実装にするには、4ステップのコードを実装した基本のビジネスオブジェクトクラスを作成し、この基本クラスをすべてのビジネスオブジェクトクラスで継承するという方法もあります。 ここでは、例を簡単にするために、上記の4ステップをCustomerビジネスオブジェクトクラスに直接実装することにします。 ステップ1:データ状態を表す定数を定義します。 VBの場合
Public Enum EntityStateEnum Unchanged Added Deleted Modified End Enum C#の場合
public enum EntityStateEnum { Unchanged, Added, Deleted, Modified, } ステップ2:状態を保持するプロパティを定義します。 VBの場合
Private _EntityState As EntityStateEnum Public Property EntityState() As EntityStateEnum Get Return _EntityState End Get Private Set(ByVal value As EntityStateEnum) _EntityState = value End Set End Property C#の場合
private EntityStateEnum _EntityState; public EntityStateEnum EntityState { get { return _EntityState; } private set { _EntityState = value; } } setアクセサの実装はPrivateであることに注意してください。これによって、他のコードによる状態の変更が回避されます。 ステップ3: VBの場合
Public Class Customer Implements INotifyPropertyChanged Public Event PropertyChanged(ByVal sender As _ Object, ByVal e As PropertyChangedEventArgs) _ Implements INotifyPropertyChanged.PropertyChanged C#の場合
class Customer : INotifyPropertyChanged public event PropertyChangedEventHandler PropertyChanged; ステップ4: VBの場合
Private Sub DataStateChanged(ByVal dataState As _ EntityStateEnum, ByVal propertyName As String) ’ Raise the event If Not String.IsNullOrEmpty(propertyName) Then RaiseEvent PropertyChanged(Me, _ New PropertyChangedEventArgs(propertyName)) End If ’ If the state is deleted, mark it as deleted If dataState = EntityStateEnum.Deleted Then Me.EntityState = dataState End If If Me.EntityState = EntityStateEnum.Unchanged Then Me.EntityState = dataState End If End Sub C#の場合
private void DataStateChanged(EntityStateEnum dataState, string propertyName) { // Raise the event if (PropertyChanged != null && propertyName != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } // If the state is deleted, mark it as deleted if (dataState == EntityStateEnum.Deleted) { this.EntityState = dataState; } if (this.EntityState == EntityStateEnum.Unchanged) { this.EntityState = dataState; } } この VBの場合
Public Property LastName() As String Get Return _LastName End Get Set (ByVal value as String) If String.IsNullOrEmpty(value) Then Throw New Exception( _ "The Last Name cannot be empty") End If If value <> _LastName Then Me.DataStateChanged( _ EntityStateEnum.Modified, _ "LastName") End If _LastName = value End Set End Property C#の場合
public string LastName { get { return _LastName;} set { if (String.IsNullOrEmpty(value)) { throw new Exception( "The Last Name cannot be empty"); } if (value != _LastName) { this.DataStateChanged( EntityStateEnum.Modified, "LastName"); } _LastName = value; } } 基本のデータ管理コードを実装した後で、必要に応じて、追加の機能を実装することができます。例えば、次のような単純な読み取り専用の VBの場合
Public ReadOnly Property IsDirty() As Boolean Get Return Me.EntityState <> _ EntityStateEnum.Unchanged End Get End Property C#の場合
public Boolean IsDirty { get{ return this.EntityState!=EntityStateEnum.Unchanged;} } この 前述の通り、この一連のデータ管理コード(最後の リストの管理アプリケーションのユーザーインターフェイスに、項目をリストしなければならないことはよくあります。例えば、すべての顧客をコンボボックスに表示して、その中から編集する顧客を選択する場合が考えられます。顧客の種類、状態、支払い予定のリストを表示することもあるでしょう。顧客が購入したすべての製品のリストをグリッドで表示する場合もあるかもしれません。 最初に、適度なサイズの項目リストを実装する方法について見ていきましょう。このリストでは、項目のいくつかのプロパティを表示し、場合によっては編集する必要があります。ここでは、顧客が購入した項目のリストをグリッドで表示することにします。 まずプロジェクトに プロジェクトに VBの場合
Public Class PurchasedItemCollection Inherits BindingList(Of PurchasedItem) C#の場合
class PurchasedItemCollection :
BindingList<PurchasedItem>
Factoryパターンに従い、コレクションエントリを作成する VBの場合
Public Shared Function Create(ByVal CustomerID _ As Int32) As PurchasedItemCollection Dim oCollection As New PurchasedItemCollection Dim dt As DataTable ’ Perform the appropriate retrieve dt = oCollection.Retrieve(CustomerID) ’ For each row, create an object in the list For Each dr As DataRow In dt.Rows Dim oItem As PurchasedItem oItem = PurchasedItem.Create(dr) oCollection.Add(oItem) Next Return oCollection End Function C#の場合
public static PurchasedItemCollection Create( Int32 CustomerID) { PurchasedItemCollection oCollection = new PurchasedItemCollection(); // Perform the appropriate retrieve DataTable dt = oCollection.Retrieve(CustomerID); // For each row, create an object in the list foreach (DataRow dr in dt.Rows) { PurchasedItem oItem = PurchasedItem.Create(dr); oCollection.Add(oItem); } return oCollection; } 両クラスの実装が完成したら、プロジェクトをビルドして、[Data Sources]ウィンドウから新しいクラスにアクセスできるようにします。次に、 フォームの VBの場合
Private Sub CustomerWin_Load(ByVal sender As _ Object, ByVal e As System.EventArgs) _ Handles Me.Load Dim CustomerInstance As Customer CustomerInstance = Customer.Create(1) CustomerBindingSource.DataSource = _ CustomerInstance Dim ItemCollection As PurchasedItemCollection ItemCollection = _ PurchasedItemCollection.Create(1) PurchasedItemCollectionBindingSource. _ DataSource = ItemCollection End Sub C#の場合
private void CustomerWin_Load(object sender, EventArgs e) { Customer CustomerInstance = Customer.Create(1); customerBindingSource.DataSource = CustomerInstance; PurchasedItemCollection ItemCollection = PurchasedItemCollection.Create(1); purchasedItemCollectionBindingSource. DataSource = ItemCollection; } 例えば編集対象の顧客を選択するための顧客名リストのように、大量の読み取り専用のキー値が必要な場合には、値ごとにインスタンスを作成するのは非効率的に感じられます。この場合は、キー値のDataTableに直接バインドしたいと思うかもしれません。しかし、この場合でも、ちょっとしたテクニックによって、一種のオブジェクトバインディングを引き続き使用することができます。 そのためには、 リスト3 オブジェクトバインディングを利用してDataTableとのバインドを実現するクラス(VB)
Public Class CustomerList Public ReadOnly Property FullName() As String Get Return "" End Get End Property Public ReadOnly Property CustomerID() As Int32 Get Return 0 End Get End Property Public ReadOnly Property CustomerDataTable() As DataTable Get Return Retrieve() End Get End Property Private Function Retrieve() As DataTable Dim dt As New DataTable dt.Columns.Add("FullName") dt.Columns.Add("CustomerID") dt.Rows.Add("Einstein, Albert", 1) dt.Rows.Add("Curie, Marie", 2) dt.Rows.Add("Brahe, Tycho", 3) dt.Rows.Add("Faraday, Michael", 4) Return dt End Function End Class リスト4 オブジェクトバインディングを利用してDataTableとのバインドを実現するクラス(C#)
class CustomerList { public string FullName { get { return "";} } public Int32 CustomerID { get { return 0;} } public DataTable CustomerDataTable { get { return Retrieve();} } private DataTable Retrieve() { DataTable dt = new DataTable(); dt.Columns.Add("FullName"); dt.Columns.Add("CustomerID"); dt.Rows.Add("Einstein, Albert", 1); dt.Rows.Add("Curie, Marie", 2); dt.Rows.Add("Brahe, Tycho", 3); dt.Rows.Add("Faraday, Michael", 4); return dt; } } プロジェクトをビルドし、 図2 コンボボックスを使って、より複雑なデータバインディングを実現する。 ![]() コンボボックスのスマートタグをクリックして、コンボボックスのプロパティを設定します。 最後に、ユーザーインターフェイスを修正して、コンボボックスに値を読み込むためのコードと、ユーザーがコンボボックスから顧客を選択したときに他のコントロールの内容を更新するためのコードを追加します(以前に作成した VBの場合
Private Sub CustomerWin_Load(ByVal sender As _ Object, ByVal e As System.EventArgs) _ Handles Me.Load ’ Bind the list Dim oList As New CustomerList CustomerListBindingSource.DataSource = _ oList.CustomerDataTable End Sub Private Sub _ FullNameComboBox_SelectionChangeCommitted( _ ByVal sender As Object, _ ByVal e As System.EventArgs) _ Handles FullNameComboBox.SelectionChangeCommitted Dim oCustomer As Customer oCustomer = Customer.Create( FullNameComboBox.SelectedValue) CustomerBindingSource.DataSource = oCustomer Dim oCollection As PurchasedItemCollection oCollection = PurchasedItemCollection.Create( _ FullNameComboBox.SelectedValue) PurchasedItemCollectionBindingSource. _ DataSource = oCollection End Sub C#の場合
private void CustomerWin_Load(object sender, EventArgs e) { CustomerList oList = new CustomerList(); customerListBindingSource.DataSource = oList.CustomerDataTable; } private void fullNameComboBox_SelectionChangeCommitted( object sender, EventArgs e) { Int32 selectedID = Convert.ToInt32( fullNameComboBox.SelectedValue); Customer oCustomer = Customer.Create(selectedID); customerBindingSource.DataSource = oCustomer; PurchasedItemCollection oCollection = PurchasedItemCollection.Create(selectedID); purchasedItemCollectionBindingSource. DataSource = oCollection; } これは基本的に見せかけのオブジェクトバインディングで、オブジェクトにバインドしていると思わせていますが、実際のバインド先はDataTableです。この方法は、クラスのインスタンスは不要だが、どのデータソースでもオブジェクトバインディングを使用するように統一したい場合に、非常に効果的な方法です(データソースの混在を気にしない場合は、ここに示す「見せかけの」オブジェクトバインディングではなく、データベースバインディングを使ってTableAdapterに直接バインドすることもできます)。 この例の場合、顧客が多数に及ぶ可能性があるため、DataTableへのバインドには意味があります。また、ワークフローの観点からは、ユーザーが一度に編集する顧客数はわずかであることが予想されます。従って、数十万もの個別のインスタンスを作成し、それぞれのインスタンスにバインドするのは無駄が多すぎます。 この「見せかけのオブジェクトバインディング」の手法は、顧客の種類、状態、支払い予定などのリストが必要なときにも使えます。このようなケースでは、リストは常に読み取り専用であり、インスタンスを本当に作成して管理する必要はありません。 例として、 このようなリストを使用する場合は、コンボボックスの3つのプロパティを操作する必要があります。このプロパティはすべて、コンボボックスのスマートタグからアクセスできます。
このように、すべての型コードに対してクラスとインスタンスを作成しなくても、完全な機能を備えたオブジェクトバンディングを実現できます。 ユーザーインターフェイスに関する注意オブジェクトバインディングに関連して、ユーザーインターフェイスにはいくつか注意を要することがあります。例えば、ラジオボタンにバインドしたり、親プロパティを子データのグリッドに追加する簡単な方法はありません。最後に、この点に触れておきたいと思います。 ラジオボタンにバインドするには、「RadioButtonList」というようなコントロールを使用するのが最も簡単です。しかし、Windows Formsにはこのようなコントロールがありません。一連のラジオボタンにバインドするには、ラジオボタンごとに個々のビジネスオブジェクトプロパティを作成しなければなりません。 例えば、顧客が請求書を受け取る方法(電子メール、FAX、郵送のいずれか)を定義する一連のラジオボタンがあるものとします。これらにバインドするには、3つの個別のブール型のビジネスオブジェクトプロパティ(E-mail、FAX、Postal)を作成し、各プロパティを個々のラジオボタンにバインドする必要があります。各プロパティのプロパティプロシージャでは、このプロパティがtrueの場合は他のプロパティ値をfalseに設定するコードを追加します(この実装については、ダウンロードサンプルを参照してください)。 ユーザーインターフェイスに関する2番目の注意事項は、親情報を子データのグリッドに簡単に表示できないということです。例えば、すべての請求書をリストするユーザーインターフェイスを作成するときに、図2のCustomerフォームと同様のグリッドを配置する一方で、他の詳細情報はフォームにいっさい表示しないというデザインにしたとします。このグリッドをユーザーが実用的に使うためには、関連するCustomerインスタンスからCustomerの名前を表示する必要があります。 そのためには、PurchasedItemビジネスオブジェクトから親オブジェクトCustomerを参照して、Customerインスタンスを作成するのが一番分かりやすいでしょう。この参照は可能であり、[Data Sources]ウィンドウにもCustomerインスタンスが表示されていますが、グリッドからそのCustomerインスタンスにアクセスすることはできません。 これに対処するには、PurchasedItemビジネスオブジェクトに オブジェクトバインディングは、ユーザーインターフェイス上のコントロールをビジネスオブジェクトプロパティに結び付ける、非常に論理的なメカニズムを提供します。ここで紹介したようなヒントとテクニックを実装することによって、オブジェクトバインディングを大いに活用できます。 オブジェクトバインディングは完全ではありませんが、この世に完全なものなどないのですから、どんどん使ってみることをお勧めします。 著者紹介Deborah Kurata(Deborah Kurata)
ビジネスの構想をMicrosoft .NETテクノロジで実現することに力を注ぐコンサルティング会社InStep Technologies Inc.の共同設立者。優れた.NETアプリケーションの設計、デザイン、開発に15年以上従事。『Doing Objects in Visual Basic 6.0』(SAMS)や『Doing Web Development: Client-Side Techniques』(APress)など複数の著作がある。INETA Speaker’s Bureauのメンバーであり、数多くの講演を行っている。
|