●得意先別受注情報を階層化して表示 (ch66NestedControl1.aspx)
DataList1にDataList2をネストさせて得意先別の受注情報を表示します。さらに、DataList2にDataGrid1をネストさせて受注明細を表示します。DataList1にCustomers表(得意先)を表示するには、パッケージ(CustomerPackage)に登録されているストアドプロシージャ(GetCustomers)を使用します。このストアドプロシージャは、Customers表からすべての行(レコード)を抽出します。
DataList2に得意先の受注情報を表示するには、パッケージ(OrderPackage)に登録されているストアドプロシージャ(GetOrdersByCustomerID)を使用します。このストアドプロシージャは、パラメータに指定した得意先のすべての受注情報を抽出します。
DataGrid1に受注明細を表示するには、パッケージ(OrderDetailPackage)に登録されているストアドプロシージャ(GetOrderDetailsByOrderID)を使用します。このストアドプロシージャは、パラメータに指定した受注IDの受注明細を抽出します。
iSQL*PlusまたはSQL*Plusを起動して、事前にパッケージ仕様部とパッケージ本体部を作成してください。
パッケージ仕様部
CustomerPackage.sql
CREATE OR REPLACE PACKAGE
TYPE rcurCustomers IS REF CURSOR;
PROCEDURE GetCustomers(
orcurCustomers OUT rcurCustomers);
END CustomerPackage;
OrderPackage.sql
CREATE OR REPLACE PACKAGE
TYPE rcurOrders IS REF CURSOR;
PROCEDURE GetOrdersByCustomerID(
orcurOrders OUT rcurOrders,
iCustomerID IN NUMBER);
END OrderPackage;
OrderDetailPackage.sql
CREATE OR REPLACE PACKAGE
TYPE rcurOrderDetails IS REF CURSOR;
PROCEDURE GetOrderDetailsByOrderID(
orcurOrderDetails OUT rcurOrderDetails,
iOrderID IN NUMBER);
END OrderDetailPackage;
パッケージ本体部
CustomerPackageBody.sql
CREATE OR REPLACE PACKAGE BODY
PROCEDURE GetCustomers(
orcurCustomers OUT rcurCustomers) IS
BEGIN
OPEN orcurCustomers FOR
SELECT *
FROM Customers
ORDER BY CustomerID;
END GetCustomers;
END CustomerPackage;
OrderPackageBody.sql
CREATE OR REPLACE PACKAGE BODY
PROCEDURE GetOrdersByCustomerID(
orcurOrders OUT rcurOrders,
iCustomerID IN NUMBER) IS
BEGIN
OPEN orcurOrders FOR
SELECT *
FROM Orders
WHERE CustomerID = iCustomerID
ORDER BY OrderID;
END GetOrdersByCustomerID;
END OrderPackage;
OrderDetailPackageBody.sql
CREATE OR REPLACE PACKAGE BODY
PROCEDURE GetOrderDetailsByOrderID(
orcurOrderDetails OUT rcurOrderDetails,
iOrderID IN NUMBER) IS
BEGIN
OPEN orcurOrderDetails FOR
SELECT OrderDetails.*, Products.ProductName
FROM Products
INNER JOIN OrderDetails
ON Products.ProductID = OrderDetails.ProductID
WHERE OrderDetails.OrderID = iOrderID
ORDER BY OrderDetails.ProductID;
END GetOrderDetailsByOrderID;
END OrderDetailPackage;
このサンプルでは、以下のノウハウを習得することができます。
▼DataListにDataListをネストさせる方法
▼DataListにDataGridをネストさせる方法
▼DataListにItemTemplateを追加する方法
▼DataListのSelectedIndexCangedイベントの使い方
1. 新規フォルダ作成
ソリューションエクスプローラから[ch6]を右クリックして、新規フォルダ[img]を作成します。本書サンプルのフォルダ(ch6\img)からすべてイメージファイルをコピー&ペーストします。

図 新規フォルダ(img)にイメージファイルをコピー&ペーストする
2. Webフォーム追加
ソリューションエクスプローラからフォルダ[ch6]を右クリックして、新規Webフォーム「ch66NestedControl1.aspx」を追加します。
3. DataList1作成
ツールボックスの[Webフォーム]からDataListをドラッグ&ドロップします。デザイナにDataList1のオブジェクトが作成されます。

図 デザイナにDataList1作成
4. DataList1にItemTemplate追加
デザイナの最下位に表示されている[HTML]タブをクリックして、HTMLビューに切り替えます。<asp:DataList>...</asp:DataList>の間に、次の<ItemTemplate>...</ItemTemplate>を追加します。ここで追加するItemTemplateは、後述する「DataList1のテンプレート作成」にて作成したものをコピー&ペーストします。
<asp:DataList id="DataList1" runat="server">
<ItemTemplate>
<TABLE id="Table1" border="0">
<TR>
<TD>
<asp:ImageButton id="ImageButton1" runat="server"
commandname="Select" ImageUrl="img/bookclose2.gif">
</asp:ImageButton>
</TD>
<TD>
<asp:Label id=lblCompanyName runat="server"
Text='<%# Container.DataItem("CompanyName") %>'>
</asp:Label>
</TD>
</TR>
<TR>
<TD></TD>
<TD>
<asp:DataList id="DataList2" Runat="server"
OnSelectedIndexChanged="DataList2_SelectedIndexChanged"
Visible="False">
</asp:DataList>
</TD>
</TR>
</TABLE>
</ItemTemplate>
</asp:DataList>
5. DataList2にテンプレート追加
DataList2の<asp:DataList>...</asp:DataList>の間に、次のHeaderTemplate、ItemTemplate、FooterTemplateを追加します。ここで追加するテンプレートは、後述する「DataList2のテンプレート作成」にて作成したものをコピー&ペーストします。
<asp:DataList id="DataList2" Runat="server"
OnSelectedIndexChanged="DataList2_SelectedIndexChanged"
Visible="False">
<HeaderTemplate>
<table id="Table2" border="0">
<tr>
<th></th>
<th>受注ID</th>
<th>受注日</th>
<th>出荷日</th>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td>
<asp:ImageButton ID="ImageButton2" Runat="server"
CommandName="Select" ImageUrl="img/bookclose.gif">
</asp:ImageButton>
</td>
<td>
<asp:Label ID=lblOrderID Runat=server
text='<%# Container.DataItem("OrderID") %>'>
</asp:Label>
</td>
<td>
<asp:Label ID="lblOrderDate" Runat=server
text='<%# DataBinder.Eval(Container.DataItem, "OrderDate", "{0:d}") %>'>
</asp:Label>
</td>
<td>
<asp:Label ID="lblShippedDate" Runat=server
text='<%# DataBinder.Eval(Container.DataItem, "ShippedDate","{0:d}") %>'>
</asp:Label>
</td>
</tr>
<tr>
<td></td>
<td colspan="3">
<asp:DataGrid ID="DataGrid1" Runat="server"
AutoGenerateColumns="False" Visible="False" BorderColor="#CCCCCC"
BorderStyle="None" BorderWidth="1px" BackColor="White"
CellPadding="4" GridLines="Horizontal"
ForeColor="Black" Width="220px">
<SelectedItemStyle Font-Bold="True" ForeColor="White"
BackColor="#CC3333">
</SelectedItemStyle>
<HeaderStyle Font-Bold="True" HorizontalAlign="Center"
ForeColor="White" BackColor="#333333">
</HeaderStyle>
<FooterStyle ForeColor="Black" BackColor="#CCCC99">
</FooterStyle>
<Columns>
<asp:BoundColumn DataField="ProductName"
HeaderText="受注商品">
</asp:BoundColumn>
<asp:BoundColumn DataField="Quantity"
HeaderText="数量" DataFormatString="{0:n0}">
<HeaderStyle HorizontalAlign="Right"></HeaderStyle>
<ItemStyle HorizontalAlign="Right"></ItemStyle>
</asp:BoundColumn>
</Columns>
<PagerStyle HorizontalAlign="Right"
ForeColor="Black" BackColor="White">
</PagerStyle>
</asp:DataGrid>
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:DataList>
6. デザインビューで確認
HTMLビューの最下位から[デザイン]タブをクリックして、デザインビューに切り替えます。

図 デザインビューで確認
7. コードビューに切り替え
メニューバーから[表示]→[コード]を選択してコードビューに切り替えます。クラスモジュールの先頭に、以下のImportsステートメントを追加します。
Imports System.Data
Imports Oracle.DataAccess.Client
Imports Oracle.DataAccess.Types
「Webフォームデザイナで生成されたコード」の左側の+をクリックして展開します。Protected WithEvents DataList1...の直後に、以下のコードを追加します。
Protected WithEvents DataList1 As System.Web.UI.WebControls.DataList
Protected WithEvents DataList2 As System.Web.UI.WebControls.DataList

図 Protected WithEvents DataList2...を追加
Page_Loadイベントに、以下のコードを追加します。
Private Sub Page_Load(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles MyBase.Load
If Not IsPostBack Then
BindCustomersList()
End If
End Sub
クラスモジュールの最後に、Sub BindCustomerList、Function CreateCustomersDataView、Function CreateOrdersDataView、Function CreateOrderDetailsDataViewを追加します。
Private Sub BindCustomersList()
With DataList1
.DataSource = CreateCustomersDataView()
.DataKeyField = "CustomerID"
.DataBind()
End With
End Sub
Private Function CreateCustomersDataView() As DataView
Dim con As New OracleConnection(ConfigurationSettings.AppSettings("conStringOraNw"))
Dim da As New OracleDataAdapter
Dim cmd As New OracleCommand("CustomerPackage.GetCustomers", con)
Dim ds As New DataSet
With cmd
.CommandType = CommandType.StoredProcedure
.Parameters.Add("1", OracleDbType.RefCursor, ParameterDirection.Output)
End With
da.SelectCommand = cmd
da.Fill(ds)
Return ds.Tables(0).DefaultView
End Function
Private Function CreateOrdersDataView(ByVal intCustomerID As Integer) As DataView
Dim con As New OracleConnection(ConfigurationSettings.AppSettings("conStringOraNw"))
Dim da As New OracleDataAdapter
Dim cmd As New OracleCommand("OrderPackage.GetOrdersByCustomerID", con)
Dim ds As New DataSet
With cmd
.CommandType = CommandType.StoredProcedure
.BindByName = True
.Parameters.Add("orcurOrders", OracleDbType.RefCursor, ParameterDirection.Output)
.Parameters.Add("iCustomerID", OracleDbType.Int32).Value = intCustomerID
End With
da.SelectCommand = cmd
da.Fill(ds)
Return ds.Tables(0).DefaultView
End Function
Private Function CreateOrderDetailsDataView(ByVal intOrderID As Integer) As DataView
Dim con As New OracleConnection(ConfigurationSettings.AppSettings("conStringOraNw"))
Dim da As New OracleDataAdapter
Dim cmd As New OracleCommand("OrderDetailPackage.GetOrderDetailsByOrderID", con)
Dim ds As New DataSet
With cmd
.CommandType = CommandType.StoredProcedure
.BindByName = True
.Parameters.Add("orcurOrderDetails", OracleDbType.RefCursor, ParameterDirection.Output)
.Parameters.Add("iOrderID", OracleDbType.Int32).Value = intOrderID
End With
da.SelectCommand = cmd
da.Fill(ds)
Return ds.Tables(0).DefaultView
End Function
コードビュー左上の「クラス名」のドロップダウンリストから[DataList1]、右上の「メソッド名」のドロップダウンリストから[SelectedIndexChanged]を選択します。DataList1_SelectedIndexChangedイベントが生成されたら、以下のコードを追加します。
Private Sub DataList1_SelectedIndexChanged(ByVal sender As Object,
ByVal e As System.EventArgs)
Handles DataList1.SelectedIndexChanged
Dim ibtn As ImageButton = CType(DataList1.SelectedItem.FindControl("ImageButton1"), ImageButton)
Dim dl As DataList = CType(DataList1.SelectedItem.FindControl("DataList2"), DataList)
Dim intCustomerID As Integer = DataList1.DataKeys(DataList1.SelectedIndex)
If dl.Visible Then
dl.Visible = False
ibtn.ImageUrl = "img/bookclose2.gif"
Else
dl.Visible = True
dl.DataSource = CreateOrdersDataView(intCustomerID)
dl.DataKeyField = "OrderID"
dl.DataBind()
ibtn.ImageUrl = "img/bookopen2.gif"
End If
End Sub
コードビュー左上の「クラス名」のドロップダウンリストから[DataList2]、右上の「メソッド名」のドロップダウンリストから[SelectedIndexChanged]を選択します。DataList2_SelectedIndexChangedイベントが生成されたら、以下のコードを追加します。それから、Private Sub DataList2をPublic Sub DataList2に書き換えます。
Public Sub DataList2_SelectedIndexChanged(ByVal sender As Object,
ByVal e As System.EventArgs)
Handles DataList2.SelectedIndexChanged
Dim dl As DataList = CType(sender, DataList)
Dim ibtn As ImageButton = CType(dl.SelectedItem.FindControl("ImageButton2"), ImageButton)
Dim dg As DataGrid = CType(dl.SelectedItem.FindControl("DataGrid1"), DataGrid)
Dim intOrderID As Integer = dl.DataKeys(dl.SelectedIndex)
If dg.Visible Then
dg.Visible = False
ibtn.ImageUrl = "img/bookclose.gif"
Else
dg.Visible = True
dg.DataSource = CreateOrderDetailsDataView(intOrderID)
dg.DataBind()
ibtn.ImageUrl = "img/bookopen.gif"
End If
End Sub
8. ブラウザに表示
ソリューションエクスプローラから[ch66NestedControl1.aspx]を右クリックしてブラウザに表示します。DataList1にCustomers表が表示されます。得意先の左側のアイコンをクリックすると、DataList2にOrders表が表示されます。受注IDの左側のアイコンをクリックすると、DataGrid1にOrderDetails表が表示されます。

図 DataList/DataGridがネストされて表示される
■ 解説
このサンプルは、DataList/DataGridが3階層にネストしています。DataList1のItemTemplateには、DataList2がネストします。さらに、DataList2のItemTemplateには、DataGrid1がネストします。
DataList1には、OracleデータベースのCustomers表から得意先を表示します。DataList2には、Orders表から得意先の受注情報を表示します。DataGrid1には、OrderDetails表から受注明細を表示します。
<asp:DataList id="DataList1" runat="server">
<ItemTemplate>
<asp:DataList id="DataList2" Runat="server"
OnSelectedIndexChanged="DataList2_SelectedIndexChanged"
Visible="False">
<HeaderTemplate>...</HeaderTemplate>
<ItemTemplate>
<asp:DataGrid ID="DataGrid1" Runat="server"
AutoGenerateColumns="False" Visible="False">
<Columns>
<asp:BoundColumn DataField="ProductName"
HeaderText="受注商品">
</asp:BoundColumn>
<asp:BoundColumn DataField="Quantity"
HeaderText="数量" DataFormatString="{0:n0}">
</asp:BoundColumn>
</Columns>
</asp:DataGrid>
</ItemTemplate>
<FooterTemplate>...</FooterTemplate>
</asp:DataList>
</ItemTemplate>
</asp:DataList>
DataList1の得意先の左側からアイコン
をクリックすると、WebページがポストバックされてPage_Load→DataList1_SelectedIndexChangedの順番にイベントが発生します。
DataList1_SelectedIndexChangedイベントでは、DataList1オブジェクトのSelectedItemプロパティから、選択したアイテムのDataListItemオブジェクトを取得します。DataListItemオブジェクトのFindControlメソッドを実行して、DataList2のオブジェクトを検索して取得します。
DataList2が可視(Visible=True)のときは、VisibleプロパティにFalseを設定します。ImageButtonオブジェクトのImageUrlプロパティに「bookclose2.gif」
のURLを設定します。
DataList2が不可視(Visible=False)のときは、VisibleプロパティにTrueを設定します。さらに、DataSourceプロパティにOrders表のDataViewオブジェクトを設定して、DataBindメソッドでバインドします。ImageButtonオブジェクトのImageUrlプロパティに「bookopen2.gif」
のURLを設定します。
Private Sub DataList1_SelectedIndexChanged(ByVal sender As Object,
ByVal e As System.EventArgs)
Handles DataList1.SelectedIndexChanged
Dim ibtn As ImageButton = CType(DataList1.SelectedItem.FindControl("ImageButton1"), ImageButton)
Dim dl As DataList = CType(DataList1.SelectedItem.FindControl("DataList2"), DataList)
Dim intCustomerID As Integer = DataList1.DataKeys(DataList1.SelectedIndex)
If dl.Visible Then
dl.Visible = False
ibtn.ImageUrl = "img/bookclose2.gif"
Else
dl.Visible = True
dl.DataSource = CreateOrdersDataView(intCustomerID)
dl.DataKeyField = "OrderID"
dl.DataBind()
ibtn.ImageUrl = "img/bookopen2.gif"
End If
End Sub
DataList2の受注IDの左側からアイコン
をクリックすると、WebページがポストバックされてPage_Load→DataList2_SelectedIndexChangedの順番にイベントが発生します。
DataList2_SelectedIndexChangedイベントでは、DataList2オブジェクトのSelectedItemプロパティから、選択したアイテムのDataListItemオブジェクトを取得します。DataListItemオブジェクトのFindControlメソッドを実行して、DataGrid1のオブジェクトを検索して取得します。
DataGrid1が可視(Visible=True)のときは、VisibleプロパティにFalseを設定します。ImageButtonオブジェクトのImageUrlプロパティに「bookclose.gif」
のURLを設定します。
DataGrid1が不可視(Visible=False)のときは、VisibleプロパティにTrueを設定します。さらに、DataSourceプロパティにOrderDetails表のDataViewオブジェクトを設定して、DataBindメソッドでバインドします。ImageButtonオブジェクトのImageUrlプロパティに「bookopen.gif」
のURLを設定します。
Public Sub DataList2_SelectedIndexChanged(ByVal sender As Object,
ByVal e As System.EventArgs)
Handles DataList2.SelectedIndexChanged
Dim dl As DataList = CType(sender, DataList)
Dim ibtn As ImageButton = CType(dl.SelectedItem.FindControl("ImageButton2"), ImageButton)
Dim dg As DataGrid = CType(dl.SelectedItem.FindControl("DataGrid1"), DataGrid)
Dim intOrderID As Integer = dl.DataKeys(dl.SelectedIndex)
If dg.Visible Then
dg.Visible = False
ibtn.ImageUrl = "img/bookclose.gif"
Else
dg.Visible = True
dg.DataSource = CreateOrderDetailsDataView(intOrderID)
dg.DataBind()
ibtn.ImageUrl = "img/bookopen.gif"
End If
End Sub