挿入、更新、削除に関連付けられているイベントを調べる (VB)
このチュートリアルでは、ASP.NET データ Web コントロールの挿入、更新、または削除操作の前後、および操作中に発生するイベントの使用について説明します。 また、製品フィールドのサブセットの更新のみを行うように編集インターフェイスをカスタマイズする方法についても説明します。
はじめに
GridView、DetailsView、または FormView コントロールの組み込みの挿入、編集、または削除機能を使用する場合、エンド ユーザーが新しいレコードの追加または既存のレコードの更新または削除のプロセスを完了すると、さまざまな手順が発生します。 前のチュートリアルで説明したように、GridView で行を編集すると、[編集] ボタンが [更新] ボタンと [キャンセル] ボタンに置き換わり、BoundField が TextBox に変わります。 エンド ユーザーがデータを更新し、[更新] をクリックすると、ポストバック時に次の手順が実行されます。
- GridView は ObjectDataSource の
UpdateParameters
に、編集されたレコードの一意の識別フィールド (DataKeyNames
プロパティを使用) とユーザーが入力した値を設定します - GridView は ObjectDataSource の
Update()
メソッドを呼び出し、基になるオブジェクト (前のチュートリアルのProductsDAL.UpdateProduct
) の適切なメソッドを呼び出します - 更新された変更を含む基になるデータは、GridView に再バインドされます
この一連の手順の間に多数のイベントが発生し、必要に応じてイベント ハンドラーを作成してカスタム ロジックを追加できます。 たとえば、手順 1 より前では、GridView の RowUpdating
イベントが発生します。 検証エラーが発生した場合は、この時点で更新要求を取り消すことができます。 Update()
メソッドが呼び出されると、ObjectDataSource の Updating
イベントが発生し、UpdateParameters
のいずれかの値を追加またはカスタマイズする機会が提供されます。 ObjectDataSource の基になるオブジェクトのメソッド実行が完了すると、ObjectDataSource の Updated
イベントが発生します。 Updated
イベントのイベント ハンドラーは、影響を受けた行の数や例外が発生したかどうかなど、更新操作に関する詳細を調べることができます。 最後に、手順 2 の後に GridView の RowUpdated
イベントが発生します。このイベントのイベント ハンドラーは、先ほど実行した更新操作に関する追加情報を調べることができます。
図 1 は、GridView を更新するときのこの一連のイベントと手順を示しています。 図 1 のイベント パターンは、GridView での更新に固有のものではありません。 GridView、DetailsView、または FormView からデータを挿入、更新、または削除すると、データ Web コントロールと ObjectDataSource の両方に対して、同じ一連の事前および事後レベルのイベントが生成されます。
図 1: GridView でデータを更新するときに発生する一連の事前および事後イベント (クリックするとフルサイズの画像が表示されます)
このチュートリアルでは、これらのイベントを使用した、ASP.NET データ Web コントロールの組み込みの挿入、更新、および削除機能の拡張について説明します。 また、製品フィールドのサブセットの更新のみを行うように編集インターフェイスをカスタマイズする方法についても説明します。
手順 1: 製品の ProductName
および UnitPrice
フィールドを更新する
前のチュートリアルの編集インターフェイスでは、読み取り専用ではない "すべての" 製品フィールドを含める必要がありました。 データを更新するときに GridView からフィールドを削除する場合 ( QuantityPerUnit
など)、データ Web コントロールは ObjectDataSource の QuantityPerUnit
UpdateParameters
値を設定しません。 この場合、ObjectDataSource は UpdateProduct
ビジネス ロジック レイヤー (BLL) メソッドに Nothing
の値を渡します。これにより、編集されたデータベース レコードの QuantityPerUnit
列が NULL
値に変更されます。 同様に、編集インターフェイスから必須フィールド (ProductName
など) が削除された場合、"列 'ProductName' に nulls を使用することはできません" 例外で更新が失敗します。 この動作の理由は、ObjectDataSource が ProductsBLL
クラスの UpdateProduct
メソッドを呼び出すように構成されており、各製品フィールドの入力パラメーターが必要だったためです。 そのため、ObjectDataSource の UpdateParameters
コレクションには、このメソッドの各入力パラメーターのパラメーターが含まれていました。
エンド ユーザーにフィールドのサブセットの更新のみを許可するデータ Web コントロールを提供する場合は、ObjectDataSource の Updating
イベント ハンドラーで UpdateParameters
の欠損値をプログラムによって設定するか、フィールドのサブセットのみを受け取る BLL メソッドを作成して呼び出す必要があります。 この後者のアプローチを見てみましょう。
具体的には、編集可能な GridView の ProductName
および UnitPrice
フィールドだけを表示するページを作成しましょう。 この GridView の編集インターフェイスでは、ProductName
と UnitPrice
の 2 つの表示フィールドの更新のみがユーザーに許可されます。 この編集インターフェイスでは製品のフィールドのサブセットのみが表示されるため、既存の BLL の UpdateProduct
メソッドを使用し、不足している製品フィールド値が Updating
イベント ハンドラーでプログラムによって設定される ObjectDataSource を作成するか、GridView で定義されているフィールドのサブセットのみを受け入れる新しい BLL メソッドを作成する必要があります。 このチュートリアルでは後者のオプションを使用し、3 つの入力パラメーター productName
、unitPrice
、productID
のみを受け取る UpdateProduct
メソッドのオーバーロードを作成します。
<System.ComponentModel.DataObjectMethodAttribute _
(System.ComponentModel.DataObjectMethodType.Update, False)> _
Public Function UpdateProduct(productName As String, _
unitPrice As Nullable(Of Decimal), productID As Integer) _
As Boolean
Dim products As Northwind.ProductsDataTable = _
Adapter.GetProductByProductID(productID)
If products.Count = 0 Then
Return False
End If
Dim product As Northwind.ProductsRow = products(0)
product.ProductName = productName
If Not unitPrice.HasValue Then
product.SetUnitPriceNull()
Else
product.UnitPrice = unitPrice.Value
End If
Dim rowsAffected As Integer = Adapter.Update(product)
Return rowsAffected = 1
End Function
元の UpdateProduct
メソッドと同様に、このオーバーロードは、指定した ProductID
を持つ製品がデータベース内に存在するかどうかを確認することから始めます。 ない場合は False
が返されます。これは、製品情報の更新要求が失敗したことを示します。 それ以外の場合は、既存の製品レコードの ProductName
および UnitPrice
フィールドを適宜更新し、TableAdapter の Update()
メソッドを呼び出し、ProductsRow
インスタンスを渡して更新をコミットします。
ProductsBLL
クラスへの追加によって、簡略化された GridView インターフェイスを作成する準備ができました。 EditInsertDelete
フォルダーの DataModificationEvents.aspx
を開き、ページに GridView を追加します。 新しい ObjectDataSource を作成し、ProductsBLL
クラスで、その Select()
メソッドを GetProducts
にマッピングし、その Update()
メソッドを、productName
、unitPrice
、productID
入力パラメーターのみを受け取る UpdateProduct
オーバーロードにマッピングして使用されるように構成します。 図 2 は、ObjectDataSource の Update()
メソッドを ProductsBLL
クラスの新しい UpdateProduct
メソッド オーバーロードにマッピングするときのデータ ソースの作成ウィザードを示しています。
図 2: ObjectDataSource の Update()
メソッドを新しい UpdateProduct
オーバーロードにマップします (クリックするとフルサイズの画像が表示されます)
この例では、最初はデータの編集機能のみが必要で、レコードの挿入や削除は必要ないため、[INSERT] タブと [DELETE] タブに移動し、ドロップダウン リストから [(None)] を選択して、ObjectDataSource の Insert()
および Delete()
メソッドを ProductsBLL
クラスのメソッドにマップしないことを明示的に示します。
図 3: [INSERT] タブと [DELETE] タブのドロップダウン リストから [(None)] を選択します (クリックするとフルサイズの画像が表示されます)
このウィザードを完了したら、GridView のスマート タグから [編集チェックを有効にする] チェック ボックスをオンにします。
データ ソースの作成ウィザードが完了し、GridView にバインドされたので、Visual Studio によって両方のコントロールの宣言構文が作成されました。 次に示すように、ObjectDataSource の宣言型マークアップを調べるには、ソース ビューに移動します。
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
OldValuesParameterFormatString="original_{0}" SelectMethod="GetProducts"
TypeName="ProductsBLL" UpdateMethod="UpdateProduct">
<UpdateParameters>
<asp:Parameter Name="productName" Type="String" />
<asp:Parameter Name="unitPrice" Type="Decimal" />
<asp:Parameter Name="productID" Type="Int32" />
</UpdateParameters>
</asp:ObjectDataSource>
ObjectDataSource の Insert()
および Delete()
メソッドのマッピングがないため、InsertParameters
または DeleteParameters
セクションはありません。 さらに、Update()
メソッドは 3 つの入力パラメーターのみを受け取る UpdateProduct
メソッド オーバーロードにマップされるため、UpdateParameters
セクションには 3 つの Parameter
インスタンスしかありません。
ObjectDataSource の OldValuesParameterFormatString
プロパティが original_{0}
に設定されていることに注意してください。 このプロパティは、データ ソースの構成ウィザードを使用すると、Visual Studio によって自動的に設定されます。 ただし、BLL メソッドでは元の ProductID
値が渡されることを想定していないため、ObjectDataSource の宣言構文からこのプロパティの割り当てを完全に削除してください。
Note
デザイン ビューのプロパティ ウィンドウから OldValuesParameterFormatString
プロパティ値をクリアすると、プロパティは宣言構文にはありますが、空の文字列に設定されます。 宣言構文からプロパティを完全に削除するか、プロパティ ウィンドウから値を既定値の {0}
に設定します。
ObjectDataSource には、製品の名前、価格、ID の UpdateParameters
しかありませんが、Visual Studio では、製品の各フィールドに対して GridView で BoundField または CheckBoxField が追加されています。
図 4: GridView には製品の各フィールドに対して BoundField または CheckBoxField が含まれています (クリックするとフルサイズの画像が表示されます)
エンド ユーザーが製品を編集し、[更新] ボタンをクリックすると、読み取り専用ではないフィールドが GridView によって列挙されます。 次に、ObjectDataSource の UpdateParameters
コレクション内の対応するパラメーターの値が、ユーザーが入力した値に設定されます。 対応するパラメーターがない場合、GridView によってコレクションに追加されます。 そのため、GridView で製品のすべてのフィールドに対して BoundField と CheckBoxField が含まれている場合、ObjectDataSource は、ObjectDataSource の宣言型マークアップで 3 つの入力パラメーターのみが指定されるという事実にもかかわらず、これらのパラメーターをすべて受け取る UpdateProduct
オーバーロードを呼び出します (図 5 を参照)。 同様に、GridView に、UpdateProduct
オーバーロードの入力パラメーターに対応しない読み取り専用ではない製品フィールドの組み合わせがある場合、更新しようとすると例外が発生します。
図 5: GridView は ObjectDataSource の UpdateParameters
コレクションにパラメーターを追加します (クリックするとフルサイズの画像が表示されます)
ObjectDataSource が、製品の名前、価格、ID のみを受け取る UpdateProduct
オーバーロードを呼び出すようにするには、ProductName
および UnitPrice
の編集可能なフィールドのみを持つよう GridView を制限する必要があります。 これを実行するには、他の BoundField と CheckBoxField を削除します。これには、それらの他のフィールドの ReadOnly
プロパティを True
に設定するか、2 つの何らかの組み合わせを設定します。 このチュートリアルでは、ProductName
および UnitPrice
BoundField を除くすべての GridView フィールドを削除します。その後、GridView の宣言型マークアップは次のようになります。
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataKeyNames="ProductID" DataSourceID="ObjectDataSource1">
<Columns>
<asp:CommandField ShowEditButton="True" />
<asp:BoundField DataField="ProductName"
HeaderText="ProductName" SortExpression="ProductName" />
<asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice"
SortExpression="UnitPrice" />
</Columns>
</asp:GridView>
UpdateProduct
オーバーロードでは 3 つの入力パラメーターを受け取りますが、GridView には BoundField が 2 つだけあります。 これは、productID
入力パラメーターが主キー値であり、編集された行の DataKeyNames
プロパティの値を介して渡されるためです。
GridView と UpdateProduct
オーバーロードにより、ユーザーは他の製品フィールドを失うことなく、製品の名前と価格のみを編集できます。
図 6: インターフェイスでは、製品の名前と価格のみを編集できます (クリックするとフルサイズの画像が表示されます)
Note
前のチュートリアルで説明したように、GridView のビュー状態を有効にすることが非常に重要です (既定の動作)。 GridView の EnableViewState
プロパティを false
に設定すると、同時実行ユーザーが意図せずにレコードを削除または編集するリスクが発生します。
UnitPrice
の書式設定の改善
図 6 に示す GridView の例は機能しますが、UnitPrice
フィールドの書式設定がまったく行われず、通貨記号なしの小数点以下 4 桁の価格表示になります。 編集できない行に通貨書式を適用するには、UnitPrice
BoundField の DataFormatString
プロパティを {0:c}
に、その HtmlEncode
プロパティを False
に設定します。
図 7: UnitPrice
の DataFormatString
および HtmlEncode
プロパティを適宜設定します (クリックするとフルサイズの画像が表示されます)
この変更により、編集できない行は価格が通貨として書式設定されます。ただし、編集された行には、通貨記号なしの小数点以下 4 桁の値が表示されます。
図 8: 編集できない行が通貨値として書式設定されました (クリックするとフルサイズの画像が表示されます)
DataFormatString
プロパティで指定された書式設定命令は、BoundField の ApplyFormatInEditMode
プロパティを True
に設定することで (既定値は False
)、編集インターフェイスに適用できます。 このプロパティを True
に設定します。
図 9: UnitPrice
BoundField の ApplyFormatInEditMode
プロパティを True
に設定します (クリックするとフルサイズの画像が表示されます)
この変更により、編集された行に表示される UnitPrice
の値も通貨として書式設定されます。
図 10: 編集された行の UnitPrice
値が通貨として書式設定されるようになりました (クリックするとフルサイズの画像が表示されます)
ただし、$19.00 など、テキスト ボックスの通貨記号を使用して製品を更新すると、FormatException
がスローされます。 GridView がユーザー指定の値を ObjectDataSource のUpdateParameters
コレクションに割り当てようとすると、UnitPrice
文字列 "$19.00" をパラメーターで必要な Decimal
に変換することができません (図 11 を参照)。 これを解決するために、GridView の RowUpdating
イベントのイベント ハンドラーを作成し、ユーザーが指定した UnitPrice
を通貨書式の Decimal
として解析させます。
GridView の RowUpdating
イベントは、2 番目のパラメーターとして型 GridViewUpdateEventArgs のオブジェクトを受け取ります。これには、ObjectDataSource の UpdateParameters
コレクションに割り当てられる準備ができているユーザー指定の値を保持するプロパティの 1 つとして NewValues
ディクショナリが含まれます。 RowUpdating
イベント ハンドラー内の次のコード行で通貨書式を使用して解析された 10 進値を使用して NewValues
コレクション内の既存の UnitPrice
値を上書きできます。
Protected Sub GridView1_RowUpdating(sender As Object, e As GridViewUpdateEventArgs) _
Handles GridView1.RowUpdating
If e.NewValues("UnitPrice") IsNot Nothing Then
e.NewValues("UnitPrice") = _
Decimal.Parse(e.NewValues("UnitPrice").ToString(), _
System.Globalization.NumberStyles.Currency)
End If
End Sub
ユーザーが UnitPrice
値 ("$19.00" など) を指定した場合、この値は Decimal.Parse によって計算された 10 進値で上書きされ、値が通貨として解析されます。 これにより、通貨記号、コンマ、小数点などの場合に小数点が正しく解析され、System.Globalization 名前空間の NumberStyles 列挙型が使用されます。
図 11 は、ユーザー指定の UnitPrice
の通貨記号によって発生する問題と、GridView の RowUpdating
イベント ハンドラーを使用してこのような入力を正しく解析する方法の両方を示しています。
図 11: 編集された行の UnitPrice
値が通貨として書式設定されるようになりました (クリックするとフルサイズの画像が表示されます)
手順 2: NULL UnitPrices
を禁止する
Products
テーブルのUnitPrice
列のNULL
値を許可するようにデータベースが構成されていますが、この特定のページにアクセスするユーザーがNULL
UnitPrice
値を指定できないようにすることができます。 つまり、ユーザーが製品行の編集時に UnitPrice
値の入力に失敗した場合、結果をデータベースに保存するのではなく、このページを通じて、編集された製品に価格が指定されている必要があることをユーザーに通知するメッセージを表示します。
GridView の RowUpdating
イベント ハンドラーに渡される GridViewUpdateEventArgs
オブジェクトには、True
に設定した場合、更新プロセスを終了する Cancel
プロパティが含まれています。 RowUpdating
イベント ハンドラーを拡張して e.Cancel
を True
に設定し、NewValues
コレクション内の UnitPrice
値が Nothing
の値である理由を説明するメッセージを表示してみましょう。
まず、Label Web コントロールを MustProvideUnitPriceMessage
という名前の付いたページに追加します。 ユーザーが製品の更新時に UnitPrice
値の指定に失敗した場合、この Label コントロールが表示されます。 Label の Text
プロパティを "You must provide a price for the product." (製品の価格を指定する必要があります) に設定します。また、次の定義を持つ Warning
という名前の Styles.css
に新しい CSS クラスを作成しました。
.Warning
{
color: Red;
font-style: italic;
font-weight: bold;
font-size: x-large;
}
最後に、Label の CssClass
プロパティを Warning
に設定します。 この時点で、図 12 に示すように、デザイナーは GridView の上に赤、太字、斜体、特に大きなフォント サイズで警告メッセージを表示する必要があります。
図 12: GridView の上に Label が追加されました (クリックするとフルサイズの画像が表示されます)
既定では、この Label は非表示になっているため、Page_Load
イベント ハンドラーで Visible
プロパティを False
に設定します。
Protected Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load
MustProvideUnitPriceMessage.Visible = False
End Sub
ユーザーが UnitPrice
を指定せずに製品を更新しようとすると、更新が取り消されて警告ラベルが表示されることがあります。 GridView の RowUpdating
イベント ハンドラーを次のように拡張します。
Protected Sub GridView1_RowUpdating(sender As Object, e As GridViewUpdateEventArgs) _
Handles GridView1.RowUpdating
If e.NewValues("UnitPrice") IsNot Nothing Then
e.NewValues("UnitPrice") = _
Decimal.Parse(e.NewValues("UnitPrice").ToString(), _
System.Globalization.NumberStyles.Currency)
Else
MustProvideUnitPriceMessage.Visible = True
e.Cancel = True
End If
End Sub
ユーザーが価格を指定せずに製品を保存しようとすると、更新は取り消され、役に立つメッセージが表示されます。 データベース (およびビジネス ロジック) では NULL
UnitPrice
が可能ですが、この特定の ASP.NET ページでは使用できません。
図 13: ユーザーは UnitPrice
を空白のままにすることはできません (クリックするとフルサイズの画像が表示されます)
ここまでは、GridView の RowUpdating
イベントを使用して、ObjectDataSource の UpdateParameters
コレクションに割り当てられているパラメーター値をプログラムによって変更する方法と、更新プロセスを完全に取り消す方法について説明しました。 これらの概念は DetailsView および FormView コントロールに引き継がれ、挿入と削除にも適用されます。
これらのタスクは、ObjectDataSource レベルで、そのInserting
、Updating
、Deleting
イベントのイベント ハンドラーを使用して実行することもできます。 これらのイベントは、基になるオブジェクトの関連付けられたメソッドが呼び出される前に発生し、入力パラメーター コレクションを変更したり、操作を完全に取り消したりする最後の機会を提供します。 これら 3 つのイベントのイベント ハンドラーには、対象となる次の 2 つのプロパティを持つ ObjectDataSourceMethodEventArgs 型のオブジェクトが渡されます。
- Cancel。
True
に設定すると、実行中の操作が取り消されます。 - InputParameters。
InsertParameters
、UpdateParameters
、またはDeleteParameters
のコレクション (イベント ハンドラーがInserting
か、Updating
か、またはDeleting
イベント用かどうかに応じる)
ObjectDataSource レベルでパラメーター値を操作する方法を説明するために、ユーザーが新しい製品を追加できるようにする DetailsView をページに含めましょう。 この DetailsView は、データベースに新しい製品をすばやく追加するためのインターフェイスを提供するために使用されます。 新しい製品を追加するときに一貫したユーザー インターフェイスを維持するために、ユーザーが ProductName
および UnitPrice
フィールドの値のみを入力できるようにしましょう。 既定では、DetailsView の挿入インターフェイスで指定されていない値は、データベース値に NULL
が設定されます。 ただし、ObjectDataSource の Inserting
イベントを使用して異なる既定値を挿入することもできます。これについては、後で説明します。
手順 3: 新しい製品を追加するためのインターフェイスを提供する
ツールボックスから GridView の上にあるデザイナーに DetailsView をドラッグし、その Height
および Width
プロパティをクリアして、ページに既に存在する ObjectDataSource にバインドします。 これにより、製品の各フィールドの BoundField または CheckBoxField が追加されます。 この DetailsView を使用して新しい製品を追加するため、スマート タグから [挿入を有効にする] オプションをオンにする必要があります。ただし、ObjectDataSource の Insert()
メソッドは ProductsBLL
クラスのメソッドにマップされていないため、このようなオプションはありません (データ ソースを構成するときに、このマッピングを [(None)] に設定したことを思い出してください。図 3 を参照)。
ObjectDataSource を構成するには、スマート タグから [データ ソースの構成] リンクを選択し、ウィザードを起動します。 最初の画面では、ObjectDataSource がバインドされている基になるオブジェクトを変更できます。ProductsBLL
に設定したままにしておきます。 次の画面では、ObjectDataSource のメソッドから基になるオブジェクトへのマッピングが一覧表示されます。 Insert()
および Delete()
メソッドをどのメソッドにもマップしないことを明示的に示しましたが、[INSERT] タブと [DELETE] タブに移動すると、マッピングが存在することがわかります。 これは、ProductsBLL
の AddProduct
と DeleteProduct
メソッドが DataObjectMethodAttribute
属性を使用して、それらがそれぞれ Insert()
と Delete()
の既定のメソッドであることを示しているためです。 そのため、他の値が明示的に指定されていない限り、ウィザードを実行するたびに ObjectDataSource ウィザードによってこれらが選択されます。
Insert()
メソッドは AddProduct
メソッドを指したままにしますが、[DELETE] タブのドロップダウン リストは [(None)] に設定します。
図 14: INSERT タブのドロップダウン リストを AddProduct
メソッドに設定します (クリックするとフルサイズの画像が表示されます)
図 15: [DELETE] タブでドロップダウン リストを [(None)] に設定します (クリックするとフルサイズの画像が表示されます)
これらの変更を行うと、次に示すように、ObjectDataSource の宣言構文が展開され、InsertParameters
コレクションが含められます。
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
SelectMethod="GetProducts" TypeName="ProductsBLL"
UpdateMethod="UpdateProduct" OnUpdating="ObjectDataSource1_Updating"
InsertMethod="AddProduct" OldValuesParameterFormatString="original_{0}">
<UpdateParameters>
<asp:Parameter Name="productName" Type="String" />
<asp:Parameter Name="unitPrice" Type="Decimal" />
<asp:Parameter Name="productID" Type="Int32" />
</UpdateParameters>
<InsertParameters>
<asp:Parameter Name="productName" Type="String" />
<asp:Parameter Name="supplierID" Type="Int32" />
<asp:Parameter Name="categoryID" Type="Int32" />
<asp:Parameter Name="quantityPerUnit" Type="String" />
<asp:Parameter Name="unitPrice" Type="Decimal" />
<asp:Parameter Name="unitsInStock" Type="Int16" />
<asp:Parameter Name="unitsOnOrder" Type="Int16" />
<asp:Parameter Name="reorderLevel" Type="Int16" />
<asp:Parameter Name="discontinued" Type="Boolean" />
</InsertParameters>
</asp:ObjectDataSource>
ウィザードを再実行することで、OldValuesParameterFormatString
プロパティが追加されました。 このプロパティを既定値 ({0}
) に設定するか、宣言構文から完全に削除して、このプロパティをクリアします。
挿入機能を提供する ObjectDataSource では、DetailsView のスマート タグに [挿入を有効にする] チェックボックスが含まれるようになりました。デザイナーに戻り、このオプションをオンにします。 次に、DetailsView が BoundField - ProductName
と UnitPrice
- CommandField の 2 つだけになるようにします。 この時点で、DetailsView の宣言構文は次のようになります。
<asp:DetailsView ID="DetailsView1" runat="server" AutoGenerateRows="False"
DataKeyNames="ProductID" DataSourceID="ObjectDataSource1">
<Fields>
<asp:BoundField DataField="ProductName"
HeaderText="ProductName" SortExpression="ProductName" />
<asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice"
SortExpression="UnitPrice" />
<asp:CommandField ShowInsertButton="True" />
</Fields>
</asp:DetailsView>
図 16 は、この時点でブラウザーで表示された場合のこのページを示しています。 ご覧のように、DetailsView には最初の製品 (Chai) の名前と価格が一覧表示されます。 ただし、ユーザーが新しい製品をすばやくデータベースに追加するための手段を提供する挿入インターフェイスが必要です。
図 16: DetailsView は現在読み取り専用モードでレンダリングされています (クリックするとフルサイズの画像が表示されます)
DetailsView を挿入モードで表示するには、DefaultMode
プロパティを Inserting
に設定する必要があります。 これにより、最初にアクセスしたときに DetailsView が挿入モードでレンダリングされ、新しいレコードを挿入した後もそこに保持されます。 図 17 に示すように、このような DetailsView には、新しいレコードを追加するためのクイック インターフェイスが用意されています。
図 17: DetailsView によって、新しい製品をすばやく追加するためのインターフェイスが提供されます (クリックするとフルサイズの画像が表示されます)
ユーザーが製品名と価格 (図 17 のように "Acme Water" や 1.99 など) を入力して [挿入] をクリックすると、ポストバックが続き、挿入ワークフローが開始され、新しい製品レコードがデータベースに追加されます。 DetailsView には挿入インターフェイスが維持され、図 18 に示すように、新しい製品を含めるために GridView がデータ ソースに自動的に再バインドされます。
図 18: 製品 "Acme Water" がデータベースに追加されました
図 18 の GridView には表示されませんが、DetailsView インターフェイスには製品フィールドがなく、CategoryID
、SupplierID
、QuantityPerUnit
などにはデータベース値 NULL
が割り当てられています。 これを確認するには、次の手順を実行します。
- Visual Studio のサーバー エクスプローラーに移動する
NORTHWND.MDF
データベース ノードを展開するProducts
データベース テーブル ノードを右クリックする- [テーブル データの表示] を選択する
これにより、Products
テーブル内のすべてのレコードが一覧表示されます。 図 19 に示すように、ProductID
、ProductName
、UnitPrice
以外の新しい製品のすべての列に、NULL
値が設定されます。
図 19: DetailsView で指定されていない製品フィールドに NULL
値が割り当てられています (クリックするとフルサイズの画像が表示されます)
NULL
が最適な既定のオプションではない、またはデータベース列自体で NULL
が許可されていないため、これらの列の 1 つ以上の値に NULL
以外の既定値を指定することをお勧めします。 これを実現するために、DetailsView の InputParameters
のコレクションのパラメーターの値をプログラムによって設定できます。 この割り当ては、DetailsView の ItemInserting
イベントまたは ObjectDataSource の Inserting
イベントのイベント ハンドラーのいずれかで実行できます。 データ Web コントロール レベルでの事前および事後レベルのイベントの使用を既に確認したので、今度は ObjectDataSource のイベントを使用して調べてみましょう。
手順 4: 値を CategoryID
および SupplierID
パラメーターに割り当てる
このチュートリアルで、このインターフェイスを介して新しい製品を追加するときに、アプリケーションに CategoryID
と SupplierID
値の 1 を割り当てる必要があるとします。 前に説明したように、ObjectDataSource には、データ変更プロセス中に発生する事前および事後レベルのイベントのペアがあります。 その Insert()
メソッドが呼び出されると、ObjectDataSource は最初にその Inserting
イベントを発生させ、次にその Insert()
メソッドのマップ先メソッドを呼び出し、最後に Inserted
イベントを発生させます。 Inserting
イベント ハンドラーは、入力パラメーターを調整したり、操作を完全に取り消したりする最後の機会を提供します。
Note
実際のアプリケーションでは、ユーザーがカテゴリとサプライヤーを指定できるようにするか、何らかの条件またはビジネス ロジックに基づいてこの値を選択する必要があります (盲目的に ID 1 を選択するのではなく)。 この例では、ObjectDataSource の事前レベル イベントから入力パラメーターの値をプログラムによって設定する方法を示しています。
ObjectDataSource の Inserting
イベントのイベント ハンドラーを作成します。 イベント ハンドラーの 2 番目の入力パラメーターは型 ObjectDataSourceMethodEventArgs
のオブジェクトであり、パラメーター コレクション (InputParameters
) にアクセスするプロパティと、操作を取り消すプロパティ (Cancel
) があります。
Protected Sub ObjectDataSource1_Inserting _
(sender As Object, e As ObjectDataSourceMethodEventArgs) _
Handles ObjectDataSource1.Inserting
End Sub
この時点で、InputParameters
プロパティには、DetailsView から割り当てられた値を持つ ObjectDataSource の InsertParameters
コレクションが含まれます。 これらのいずれかのパラメーターの値を変更するには、e.InputParameters("paramName") = value
を使用します。 そのため、CategoryID
と SupplierID
を値 1 に設定するには、Inserting
イベント ハンドラーを次のように調整します。
Protected Sub ObjectDataSource1_Inserting _
(sender As Object, e As ObjectDataSourceMethodEventArgs) _
Handles ObjectDataSource1.Inserting
e.InputParameters("CategoryID") = 1
e.InputParameters("SupplierID") = 1
End Sub
今回は新しい製品 (Acme Soda など) を追加するときに、新製品の CategoryID
および SupplierID
列が 1 に設定されます (図 20 を参照)。
図 20: 新製品の値 CategoryID
と SupplierID
が 1 に設定されました (クリックするとフルサイズの画像が表示されます)
まとめ
編集、挿入、および削除のプロセス中に、データ Web コントロールと ObjectDataSource の両方で、多くの事前および事後レベルのイベントが処理されます。 このチュートリアルでは、事前レベルのイベントを調べ、これらを使用して入力パラメーターをカスタマイズしたり、データ Web コントロールと ObjectDataSource のイベントの両方からデータ変更操作を完全に取り消す方法を確認しました。 次のチュートリアルでは、事後レベル イベントのイベント ハンドラーの作成と使用について説明します。
プログラミングに満足!
著者について
7 冊の ASP/ASP.NET 書籍の著者であり、4GuysFromRolla.com の創設者である Scott Mitchell は、1998 年から Microsoft Web テクノロジに取り組んでいます。 Scott は、独立したコンサルタント、トレーナー、ライターとして働いています。 彼の最新の本は サムズは24時間で2.0 ASP.NET 自分自身を教えています。 にアクセスするか、ブログを使用して にアクセスmitchell@4GuysFromRolla.comできます。これは でhttp://ScottOnWriting.NET見つけることができます。
特別な感謝
このチュートリアル シリーズは、多くの役に立つ校閲者によってレビューされました。 このチュートリアルのリード レビュー担当者は、Jackie Goor と Liz Shulok でした。 今後の MSDN の記事を確認することに関心がありますか? その場合は、 にmitchell@4GuysFromRolla.com行をドロップしてください。