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 CategoryPackage AS

  TYPE rcurCategories IS REF CURSOR;

  PROCEDURE GetCategories(

    orcurCategories OUT rcurCategories);

END CategoryPackage;

 

パッケージ本体部(CategoryPackageBody.sql)

CREATE OR REPLACE PACKAGE BODY CategoryPackage AS

  PROCEDURE GetCategories(

    orcurCategories OUT rcurCategories) IS

  BEGIN

    OPEN orcurCategories FOR

       SELECT * FROM Categories

       ORDER BY CategoryID;

  END GetCategories;

END CategoryPackage;

 

このサンプルでは、以下のノウハウを習得することができます。

 

DataGridの編集行にDropDownListを表示する方法

▼連結列をテンプレート列に変換する方法

▼テンプレート列の編集からItemTemplateLabelを作成する方法

▼テンプレート列の編集からEditItemTemplateDropDownListを作成する方法

DropDownListCategories表をバインドする方法

DataGridの編集時、DropDownListにデフォルトのアイテムを表示する方法

DataGridの編集行からDropDownListで選択したアイテムを取得する方法

DropDownListItemsコレクションのFindByValueFindByTextメソッドの使い方

@PageディレクティブのsmartNavigationプロパティの使い方

 

 

1. 連結列をテンプレート列に変換

 

DataGrid1の右クリックから[プロパティビルダ]を選択します。「DataGrid1プロパティ」が表示されたら、左側から[]を選択します。「選択された列」から[商品区分]を選択します。画面最下位の[この列をテンプレート列に変換する]をクリックして連結列をテンプレート列に変換します。「選択された列」の[商品区分]が連結列からテンプレート列に変わります。[OK]をクリックして「プロパティビルダ」を閉じます。

 

fig6-2-3

プロパティビルダの[]から連結列をテンプレート列に変換する

 

2. テンプレートの編集

 

DataGrid1の右クリックから[テンプレートの編集][Columns[2] – 商品区分]を選択します。「DataGrid1 – Columns[2] – 商品区分」のテンプレート編集が表示されたら、ItemTemplateLabel1をクリックして選択します。Label1のプロパティウィンドウから「(DataBindings)」プロパティを選択してiconEllipsis(iconEllipsis.gif)をクリックします。「Label1データ連結」が表示されたら、「Textの連結」から[カスタム連結式]を選択して、テキストボックスに以下の連結式を入力します。

 

GetCategoryName(Container.DataItem("CategoryID"))

 

[OK]をクリックして「Label1データ連結」を閉じます。

 

fig6-2-4

Label1Textプロパティにカスタム連結式入力

 

EditItemTemplateTextBoxの右クリックから[削除]を選択して、TextBoxを削除します。ツールボックスの[Webフォーム]からDropDownListをドラッグして、EditItemTemplateにドロップします。

 

fig6-2-5

EditItemTemplateDropDownListをドラッグ&ドロップ

 

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

 

fig6-2-6

DropDownListDataSourceプロパティにカスタム連結式入力

 

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

 

fig6-2-7

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 GetCategoriesFunction 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]を右クリックしてブラウザに表示します。DataGridProducts表が表示されたら[編集]をクリックします。「商品」がテキストボックス、「商品区分」がドロップダウンリストに表示されます。[更新]をクリックすると、ドロップダウンリストから選択した商品区分がProducts表に保存されます。

 

fig6-2-8

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の右クリックから[テンプレートの編集]を選択して、ItemTemplateLabel1Textプロパティにカスタム連結式を記述します。

 

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

 

EditItemTemplateTextBoxを削除して、ツールボックスから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_LoadDataGrid1_EditCommandの順にイベントが発生します。Page_Loadイベントでは、IsPostBackプロパティを調べて初期ロードのときBindGridメソッドを実行します。

 

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs)

cccHandles 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」を設定してDataViewCategoryID順に並べ替えます。

 

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メソッドを実行すると、DataGridProducts表がバインドされて、DataGrid1_ItemDataBoundイベントが発生します。

 

Private Sub DataGrid1_EditCommand(ByVal source As Object,

cccByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs)

cccHandles 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,

cccByVal e As System.Web.UI.WebControls.DataGridItemEventArgs)

cccHandles 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を取得して変数に保存します。TextBoxのオブジェクトは、DataGridItemCellsコレクションのControlsコレクションから取得します。DropDownListのオブジェクトは、DataGridItemFindControlメソッドを実行して取得します。FindControlメソッドの引数には、DropDownListIDを指定します。

 

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]を選択します。

 

fig6-2-9

smartNavigationプロパティから[True]を選択