●DataGridの編集時、商品区分をDropDownListから選択 (ch62DataGrid2.aspx)
DataGridの編集時、商品区分をテキストボックスに直接入力する代わりにドロップダウンリストから選択できるように操作性を改善します。
ドロップダウンリストに商品区分を表示するには、パッケージ(CategoryPackage)に登録されているストアドプロシージャ(GetCategories)を使用します。
iSQL*PlusまたはSQL*Plusを起動して、事前にパッケージ仕様部(C:\vbora\sql\CategoryPackage.sql)とパッケージ本体部(C:\vbora\sql\CategoryBody.sql)を作成してください。
パッケージ仕様部(CategoryPackage.sql)
CREATE OR REPLACE PACKAGE
TYPE rcurCategories IS REF CURSOR;
PROCEDURE GetCategories(
orcurCategories OUT rcurCategories);
END CategoryPackage;
パッケージ本体部(CategoryPackageBody.sql)
CREATE OR REPLACE PACKAGE BODY
PROCEDURE GetCategories(
orcurCategories OUT rcurCategories) IS
BEGIN
OPEN orcurCategories FOR
SELECT * FROM Categories
ORDER BY CategoryID;
END GetCategories;
END CategoryPackage;
このサンプルでは、以下のノウハウを習得することができます。
▼DataGridの編集行にDropDownListを表示する方法
▼連結列をテンプレート列に変換する方法
▼テンプレート列の編集からItemTemplateにLabelを作成する方法
▼テンプレート列の編集からEditItemTemplateにDropDownListを作成する方法
▼DropDownListにCategories表をバインドする方法
▼DataGridの編集時、DropDownListにデフォルトのアイテムを表示する方法
▼DataGridの編集行からDropDownListで選択したアイテムを取得する方法
▼DropDownListのItemsコレクションのFindByValue、FindByTextメソッドの使い方
▼@PageディレクティブのsmartNavigationプロパティの使い方
1. 連結列をテンプレート列に変換
DataGrid1の右クリックから[プロパティビルダ]を選択します。「DataGrid1プロパティ」が表示されたら、左側から[列]を選択します。「選択された列」から[商品区分]を選択します。画面最下位の[この列をテンプレート列に変換する]をクリックして連結列をテンプレート列に変換します。「選択された列」の[商品区分]が連結列からテンプレート列に変わります。[OK]をクリックして「プロパティビルダ」を閉じます。

図 プロパティビルダの[列]から連結列をテンプレート列に変換する
2. テンプレートの編集
DataGrid1の右クリックから[テンプレートの編集]→[Columns[2] – 商品区分]を選択します。「DataGrid1 –
Columns[2] – 商品区分」のテンプレート編集が表示されたら、ItemTemplateのLabel1をクリックして選択します。
(iconEllipsis.gif)をクリックします。「Label1データ連結」が表示されたら、「Textの連結」から[カスタム連結式]を選択して、テキストボックスに以下の連結式を入力します。
GetCategoryName(Container.DataItem("CategoryID"))
[OK]をクリックして「Label1データ連結」を閉じます。

図 Label1のTextプロパティにカスタム連結式入力
EditItemTemplateのTextBoxの右クリックから[削除]を選択して、TextBoxを削除します。ツールボックスの[Webフォーム]からDropDownListをドラッグして、EditItemTemplateにドロップします。

図 EditItemTemplateにDropDownListをドラッグ&ドロップ
プロパティウィンドウから[DropDownList1]を選択したら、「(DataBindings)」プロパティを選択して
(iconEllipsis.gif)をクリックします。「DropDownList1データ連結」が表示されたら、「DataSourceの連結」から[カスタム連結式]を選択して、テキストボックスにメソッド名「GetCategories()」を入力します。[OK]をクリックして「DropDownList1データ連結」を閉じます。

図 DropDownListのDataSourceプロパティにカスタム連結式入力
DropDownList1のプロパティウィンドウから「DataTextField」プロパティに「CategoryName」を入力します。「DataValueField」プロパティには、「CategoryID」を入力します。「テンプレート編集」の右クリックから[テンプレート編集の終了]を選択して終了します。

図 DropDownList1のプロパティ設定
3. コードビューに切り替え
メニューバーから[表示]→[コード]を選択してコードビューに切り替えます。Page_Loadイベントの直前に、以下の変数を宣言します。
Private mdvCategories As DataView
Sub BindGridを以下のように書き換えます。
Private Sub BindGrid()
Dim con As New OracleConnection(ConfigurationSettings.AppSettings("conStringOraNw"))
Dim cmd As OracleCommand
Dim da As New OracleDataAdapter
Dim ds As New DataSet
con.Open()
cmd = New OracleCommand("ProductPackage.GetProducts", con)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.Add("1", OracleDbType.RefCursor, ParameterDirection.Output)
da.SelectCommand = cmd
da.Fill(ds, "Products")
cmd = New OracleCommand("CategoryPackage.GetCategories", con)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.Add("1", OracleDbType.RefCursor, ParameterDirection.Output)
da.SelectCommand = cmd
da.Fill(ds, "Categories")
con.Close()
mdvCategories = ds.Tables("Categories").DefaultView
mdvCategories.Sort = "CategoryID"
With DataGrid1
.DataSource = ds
.DataMember = "Products"
.DataKeyField = "ProductID"
.DataBind()
End With
End Sub
クラスモジュールの最後に、Function GetCategoriesとFunction GetCategoryNameを追加します。
Public Function GetCategories() As DataView
Return mdvCategories
End Function
Public Function GetCategoryName(ByVal oCategoryID As Object) As String
Dim intCategoryID As Integer = CType(oCategoryID, Integer)
Dim intRowIndex As Integer = mdvCategories.Find(intCategoryID)
Return mdvCategories(intRowIndex)("CategoryName")
End Function
4. ItemDataBoundイベント作成
コードビュー左上の「クラス名」のドロップダウンリストから[DataGrid1]、右上の「メソッド名」のドロップダウンリストから[ItemDataBound]を選択します。DataGrid1_ItemDataBoundイベントが生成されたら、以下のコードを追加します。
Private Sub DataGrid1_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DataGridItemEventArgs) Handles DataGrid1.ItemDataBound
If e.Item.ItemType = ListItemType.EditItem Then
Dim ddl As DropDownList = CType(e.Item.FindControl("DropDownList1"), DropDownList)
Dim drv As DataRowView = CType(e.Item.DataItem, DataRowView)
Dim strCategoryID As String = drv("CategoryID").ToString
ddl.Items.FindByValue(strCategoryID).Selected = True
End If
End Sub
5. UpdateCommandイベントの書き換え
DataGrid1_UpdateCommandイベントを以下のように書き換えます。
Private Sub DataGrid1_UpdateCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs) Handles DataGrid1.UpdateCommand
Dim ddl As DropDownList = CType(e.Item.FindControl("DropDownList1"), DropDownList)
Dim strProductName As String = CType(e.Item.Cells(1).Controls(0), TextBox).Text
Dim intCategoryID As Integer = Int32.Parse(ddl.SelectedItem.Value)
Dim intProductID As Integer = DataGrid1.DataKeys(e.Item.ItemIndex)
UpdateRecord(strProductName, intCategoryID, intProductID)
DataGrid1.EditItemIndex = -1
BindGrid()
End Sub
6. ブラウザに表示
ソリューションエクスプローラから[ch62DataGrid1.aspx]を右クリックしてブラウザに表示します。DataGridにProducts表が表示されたら[編集]をクリックします。「商品」がテキストボックス、「商品区分」がドロップダウンリストに表示されます。[更新]をクリックすると、ドロップダウンリストから選択した商品区分がProducts表に保存されます。

図 DropDownListから商品区分を選択する
■解説
DataGridの編集時に「商品区分」をDropDownListから選択できるようにするには、連結列をテンプレート列に変換します。連結列をテンプレート列に変換するには、DataGrid1の右クリックから[プロパティビルダ]を選択します。「DataGrid1プロパティ」が表示されたら、左側から[列]を選択します。「選択された列」から[商品区分]を選択したら、画面最下位から[この列をテンプレート列に変換する]をクリックします。[OK]をクリックすると、以下のようなテンプレート列が生成されます。
<asp:DataGrid id="DataGrid1" runat="server"
AutoGenerateColumns="False">
<Columns>
・・・
<asp:TemplateColumn HeaderText="商品区分">
<ItemTemplate>
<asp:Label runat="server"
Text='<%# DataBinder.Eval(Container, "DataItem.CategoryID") %>'>
</asp:Label>
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox runat="server"
Text='<%# DataBinder.Eval(Container, "DataItem.CategoryID") %>'>
</asp:TextBox>
</EditItemTemplate>
</asp:TemplateColumn>
・・・
</Columns>
</asp:DataGrid>
連結列をテンプレート列に変換したら、DataGrid1の右クリックから[テンプレートの編集]を選択して、ItemTemplateのLabel1のTextプロパティにカスタム連結式を記述します。
GetCategoryNameメソッドの引数には、商品区分ID(CategoryID)を指定します。GetCategoryNameメソッドは、Categories表のDataViewから商品区分IDを検索して商品区分名を返します。
<ItemTemplate>
<asp:Label id=Label1 runat="server"
Text='<%#
GetCategoryName(Container.DataItem("CategoryID")) %>'>
</asp:Label>
</ItemTemplate>
Public Function GetCategoryName(ByVal oCategoryID As Object) As String
Dim intCategoryID As Integer = CType(oCategoryID, Integer)
Dim intRowIndex As Integer = mdvCategories.Find(intCategoryID)
Return mdvCategories(intRowIndex)("CategoryName")
End Function
EditItemTemplateのTextBoxを削除して、ツールボックスからDropDownListをドラッグ&ドロップしたら、DataSourceプロパティにカスタム連結式を記述してCategories表をバインドします。GetCategoriesメソッドは、Categories表のDataViewオブジェクトを返します。
<EditItemTemplate>
<asp:DropDownList id=DropDownList1
runat="server"
DataValueField="CategoryID"
DataTextField="CategoryName"
DataSource="<%# GetCategories()
%>">
</asp:DropDownList>
</EditItemTemplate>
Public Function GetCategories() As DataView
Return mdvCategories
End Function
DataGridから[編集]をクリックすると、WebページがポストバックされてPage_Load→DataGrid1_EditCommandの順にイベントが発生します。Page_Loadイベントでは、IsPostBackプロパティを調べて初期ロードのときBindGridメソッドを実行します。
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles MyBase.Load
If Not IsPostBack Then
BindGrid()
End If
End Sub
BindGridメソッドは、パッケージ(ProductPackage)に登録されているストアドプロシージャ(GetProducts)を実行してProducts表をDataSetに取り込みます。次に、パッケージ(CategoryPackage)に登録されているストアドプロシージャ(GetCategories)を実行してCategories表をDataSetに取り込みます。
DataSetオブジェクトのTablesコレクションからCategories表のDataViewオブジェクトを作成して変数に保存します。DataViewオブジェクトのSortプロパティに「CategoryID」を設定してDataViewをCategoryID順に並べ替えます。
DataGridオブジェクトのDataSourceプロパティにDataSetオブジェクトを設定したら、DataBindメソッドを実行してProducts表をバインドして表示します。DataSetに複数のDataTableが格納されているときは、DataGridオブジェクトのDataMemberプロパティにDataTable名を設定します。
Private Sub BindGrid()
Dim con As New OracleConnection(ConfigurationSettings.AppSettings("conStringOraNw"))
Dim cmd As OracleCommand
Dim da As New OracleDataAdapter
Dim ds As New DataSet
con.Open()
cmd = New OracleCommand("ProductPackage.GetProducts", con)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.Add("1", OracleDbType.RefCursor, ParameterDirection.Output)
da.SelectCommand = cmd
da.Fill(ds, "Products")
cmd = New OracleCommand("CategoryPackage.GetCategories", con)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.Add("1", OracleDbType.RefCursor, ParameterDirection.Output)
da.SelectCommand = cmd
da.Fill(ds, "Categories")
con.Close()
mdvCategories = ds.Tables("Categories").DefaultView
mdvCategories.Sort = "CategoryID"
With DataGrid1
.DataSource = ds
.DataMember = "Products"
.DataKeyField = "ProductID"
.DataBind()
End With
End Sub
DataGrid1_EditCommandイベントでは、DataGridオブジェクトのEditItemIndexプロパティにカレントのアイテム番号を設定して、BindGridメソッドを実行します。BindGridメソッドを実行すると、DataGridにProducts表がバインドされて、DataGrid1_ItemDataBoundイベントが発生します。
Private Sub DataGrid1_EditCommand(ByVal source As Object,
ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs)
Handles DataGrid1.EditCommand
DataGrid1.EditItemIndex = e.Item.ItemIndex
BindGrid()
End Sub
DataGrid1_ItemDataBoundイベントでは、カレントのアイテムが編集行(EditItem)か調べます。編集行のときは、DropDownListオブジェクトのListItemオブジェクトのSelectedプロパティにTrueを設定してデフォルトのアイテムを選択します。つまり、編集行にDropDownListを表示するとき、現在の商品区分をデフォルトとして表示します。DropDownListからデフォルトの商品区分を検索するには、ItemsコレクションのFindByValueメソッドを使用します。FindByValueメソッドの引数には、商品区分ID(CategoryID)を指定します。FindByValueメソッドの戻り値として、ListItemオブジェクトが返されます。
Private Sub DataGrid1_ItemDataBound(ByVal sender As Object,
ByVal e As System.Web.UI.WebControls.DataGridItemEventArgs)
Handles DataGrid1.ItemDataBound
If e.Item.ItemType = ListItemType.EditItem Then
Dim ddl As DropDownList = CType(e.Item.FindControl("DropDownList1"), DropDownList)
Dim drv As DataRowView = CType(e.Item.DataItem, DataRowView)
Dim strCategoryID As String = drv("CategoryID").ToString
ddl.Items.FindByValue(strCategoryID).Selected = True
End If
End Sub
DropDownListから商品区分を選択して[更新]をクリックすると、DataGrid1_UpdateCommandイベントが発生します。DataGrid1_UpdateCommandイベントでは、編集行のTextBoxから商品名、DropDownListから商品区分IDを取得して変数に保存します。
UpdateRecordメソッドを実行して、編集データをProducts表に反映します。DataGridオブジェクトのEditItemIndexプロパティに「-1」を設定して、BindGridメソッドを実行すると、編集行が通常行として表示されます。
Private Sub DataGrid1_UpdateCommand(ByVal source As Object,
ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs)
Handles DataGrid1.UpdateCommand
Dim ddl As DropDownList = CType(e.Item.FindControl("DropDownList1"), DropDownList)
Dim strProductName As String = CType(e.Item.Cells(1).Controls(0), TextBox).Text
Dim intCategoryID As Integer = Int32.Parse(ddl.SelectedItem.Value)
Dim intProductID As Integer = DataGrid1.DataKeys(e.Item.ItemIndex)
UpdateRecord(strProductName, intCategoryID, intProductID)
DataGrid1.EditItemIndex = -1
BindGrid()
End Sub
Tip
|
ポストバックしたときにDataGridの位置を保持するには DataGridの商品がブラウザの画面に収まらないとき、画面をスクロールした状態で[編集]をクリックするとWebページがポストバックされてDataGridが再表示されます。ところが、ブラウザの画面にはDataGridの先頭行が表示されますので、画面をスクロールして編集行を探す必要があります。DataGridの[編集]をクリックしたときにカレントの位置を保持させるには、プロパティウィンドウから[DOCUMENT]を選択して、「smartNavigation」プロパティから[True]を選択します。
図 smartNavigationプロパティから[True]を選択 |