SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

japan.internet.com翻訳記事

オブジェクトバインディングに関するヒントとテクニック

.NET Framework 2.0で強化されたデータバインディング機能

データ管理

 フォーム上の値の更新をユーザーに許可する場合は、その値を検証する必要が生じます。すべての値が有効なときは、変更を保存するオプションを提供するようにします。オブジェクトバインディングは、検証およびデータ管理プロセスを支援するいくつかの機能を備えています。

 オブジェクトバインディングを使って検証を実装するには、最初に、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アイコンに表示します。

 適切な検証コードをビジネスオブジェクトプロパティに直接追加することができ、必要であれば例外をスローできます。もっと柔軟で再利用性に優れた検証処理が必要な場合は、独立したValidationクラスを作成し、このクラスで必須フィールドのチェック、文字列長のチェック、数値チェック、日付範囲のチェックなど、さまざまな種類の検証を行うことができます。Validationクラスは、例外をスローする代わりに、検証エラーのコレクションを保持できます。その場合、ビジネスオブジェクトはIDataErrorInfoインターフェイスを実装して、このコレクションをErrorProviderに公開する必要があります。この方法の詳細については割愛しますが、興味を抱く読者が多いようであれば、このトピックに関する記事を書くつもりです。

 ユーザーの入力値を検証したら、ビジネスオブジェクトは、値の変更を追跡する必要があります。これによって、何らかの変更があった場合のみ、終了時に変更を保存するかどうかをユーザーに確認するなどの機能を実装できるようになります。また、オブジェクトの更新、作成、または削除を追跡し、元のデータソースにさかのぼって適切な処理を実行することができます。

 このデータ管理では、次の4つの基本ステップが必要です。

  1. データ状態を表す定数を定義します。
  2. ビジネスオブジェクトにプロパティを追加して、状態を保持します。
  3. INotifyPropertyChangedインターフェイス(System.ComponentModel.INotifyPropertyChanged)を実装します。
  4. PropertyChangedイベントを生成します。

 この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:INotifyPropertyChangedインターフェイスを実装します。このインターフェイスを実装し、プロパティ値が変更されたときにPropertyChangedイベントを起動することによって、オブジェクトバインディングは変更を自動的に検出します。プロパティに加えられた変更は、ユーザーインターフェイスの中で確実に更新されます。

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:PropertyChangedイベントを起動します。

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;
   }
}

 このDataStateChangedメソッドは、PropertyChangedイベントを起動し、適切なデータ状態を設定します。DataStateChangedメソッドは、次に示すように、ビジネスオブジェクト内の各プロパティのプロパティプロシージャで呼び出されます。

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;
   }
}

 基本のデータ管理コードを実装した後で、必要に応じて、追加の機能を実装することができます。例えば、次のような単純な読み取り専用のIsDirtyプロパティを追加できます。

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;}
}

 このIsDirtyプロパティをユーザーインターフェイスのClosingイベントの中で呼び出せば、ユーザーに変更の保存確認を求めるべきどうかを判別できます。

 前述の通り、この一連のデータ管理コード(最後のIsDirtyプロパティも含む)を1つの基本クラスに追加し、この基本クラスをすべてのビジネスオブジェクトに継承させるという実装方法も考えられます。そうすれば、すべてのビジネスオブジェクトにかかわる一連の基本機能を1つのコードセットで提供することができます。

次のページ
リストの管理

この記事は参考になりましたか?

japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

Deborah Kurata(Deborah Kurata)

ビジネスの構想をMicrosoft .NETテクノロジで実現することに力を注ぐコンサルティング会社InStep Technologies Inc.の共同設立者。優れた.NETアプリケーションの設計、デザイン、開発に15年以上従事。『Doing Objects in Visual Basic 6.0』...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/383 2006/08/22 15:46

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー