DataGridにレコードを追加する機能を付加したサンプル

 

DataGridにレコードを追加する機能を付加したサンプル

 

このサンプルは、親ウィンドウから子ウィンドウを開いて、新規レコードを追加します。子ウィンドウから追加したレコードは、親ウィンドウのDataGridに表示されます。

 

新規レコードを追加するには、親ウィンドウに表示されているレコードの追加ボタンをクリックします。子ウィンドウが開いたら、テキストボックスに得意先名、担当者名、部署役職、電話番号を入力します。最後に、子ウィンドウから[追加]ボタンをクリックすると、得意先テーブルにレコードが追加されます。追加ボタンをクリックしても、子ウィンドウは開いた状態になっていますので、連続してレコードを追加することができます。[閉じる]のボタンをクリックすると、子ウィンドウを閉じます。子ウィンドウから追加したレコードは、親ウィンドウのDataGridに反映されます。親ウィンドウのDataGridには、得意先テーブルのレコードが得意先IDの降順に10件表示されます。

 

 

  プログラムPopupInsert.aspxのポイント

 

¶ポイント1 新規登録でDataGridに表示されていないカラムを入力するには

 

Web Matrixのテンプレートを使用すれば、DataGridにレコードを追加する機能を簡単に付加することができます。ところが、DataGridにレコードを追加する機能を組み込んだ場合、入力できるレコードのフィールドがDataGridに表示されているカラムに限定されるため、あまり実用的ではありません。このサンプルでは、レコードの追加処理を、子ウィンドウに分離することによりこの問題を解決しています。子ウィンドウからは、DataGridに表示されていないカラムを入力することができます。また、子ウィンドウと親ウィンドウを連動させていますので、子ウィンドウから追加したレコードが親ウィンドウのDataGridに反映されます。

 

子ウィンドウと親ウィンドウを連動させるには、Page.GetPostBackEventReference()メソッドを使用します。このメソッドを使用すると、子ウィンドウから親ウィンドウをポストバックさせてデータを渡すことができます。サンプルでは、この機能を応用して子ウィンドウから追加したレコードを親ウィンドウのDataGridに反映しています。

 

¶ポイント2 ページ間でDataTableオブジェクトを共有するには

 

このサンプルでは、親ウィンドウと子ウィンドウ間でDataTableを共有するために、Session変数にDataTableを保存しています。DataTableを共有することにより、子ウィンドウからレコードを追加する処理を高速化することができます。

 

¶ポイント3 子ウィンドウから親ウィンドウにデータを渡すには

 

このサンプルでは、子ウィンドウから親ウィンドウのTextBoxに処理の結果を示すメッセージを渡しています。子ウィンドウから親ウィンドウにデータを渡すには、JavaScriptを登録して実行させます。Webサーバ側からJavaScriptを登録するには、Page.RegisterClientScriptBlock()メソッドを使用します。子ウィンドウから親ウィンドウを参照するには、JavaScriptwindow.openerを使用します。

 

Dim sbScript As New StringBuilder()

With sbScript

  .Append("<script language='javascript'> ")

  .Append("window.opener.frmMain.txtMessage.value = 'message';")

  .Append("</" & "script>")

End With

RegisterClientScriptBlock("insert", sbScript.ToString)

 

 

¶ポイント4 Webサーバ側からポップアップウィンドウにメッセージを表示するには

 

このサンプルでは、Webサーバ側でエラーを検出したときエラーメッセージをポップアップウィンドウに表示させています。クライアント側にポップウィンドウを表示するには、JavaScripを登録して実行させます。Webサーバ側からJavaScriptを登録するには、Page.RegisterClientScriptBlock()メソッドを使用します。ポップアップウィンドウにメッセージを表示するには、JavaScriptwindow.alert()メソッドを使用します。

 

Dim sbScript As New StringBuilder()

With sbScript

  .Append("<script language='javascript'> ")

  .Append("alert('error message'); ")

  .Append("</" & "script>")

End With

RegisterClientScriptBlock("alertScript", sbScript.ToString)

 

 

¶ポイント5 アプリケーション独自のカーソルを表示するには

 

このサンプルでは、TextBoxにクライアント側で動作するonFocusonBlurイベントを登録して背景色を切り替えています。onFocusイベントでフォーカスを取得したときは、TextBoxの背景色をLightGreenに変えます。onBlurイベントでフォーカスを喪失したときは、背景色をAliceBlueに戻します。これで、アプリケーション独自のカーソルが表示されます。

 

TextBoxにクライアント側で動作するイベントを登録するには、AttributesコレクションのAdd()メソッドを使用します。

 

txtCompanyName.Attributes.Add("onFocus", "this.style.backgroundColor='LightGreen'")

txtCompanyName.Attributes.Add("onBlur", "this.style.backgroundColor='AliceBlue'")

 

 

  メインプログラムDataGridInsert.aspxの解説(HTML編)

 

親ウィンドウのWebフォームには、ImageButtonDataGridを作成しています。ImageButtonでは、レコードの追加ボタンを表示します。このボタンをクリックすると、子ウィンドウが開きます。DataGridには、得意先テーブルのレコードを得意先IDの降順に10件表示します。つまり、新規登録された順番に表示します。

 

151-157では、ImageButtonを定義しています。行153では、OnCommandイベントを登録しています。このイベントでは、子ウィンドウを開きます。行154では、ImageUrlプロパティにイメージのurlを設定しています。

 

151:     <asp:ImageButton id="ibtnInsert" runat="server"
152:       CommandName="insert"
153:       OnCommand="ibtnInsert_Command"
154:       ImageUrl="../img/insert.gif"
155:       Title="Add new record"
156:       CssClass="imageButton"
157:       ImageAlign="Middle" />

158-164では、LabelTextBoxを定義してDataGridの件数を表示しています。TextBoxReadOnlyプロパティには、Trueを設定して読み込み専用にしています。TextBoxには、ランタイム時にレコード件数を設定します。

 

158:     <asp:Label id="lblRows" runat="server"
159:       Text="
件数" Font-Name="Tahoma" Font-Size="9pt"
160:       CssClass="rowNumber" />
161:     <asp:TextBox id="txtRows" runat="server"
162:       CssClass="rowNumber"
163:       Columns="3"
164:       ReadOnly="True" />

177-229では、DataGridを定義しています。このDataGridでは、AutoGenerateColumnsプロパティにFalseを設定してカラムの自動生成機能を抑止しています。行191-228<Columns>…</Columns>では、TemplateColumnBoundColumnを定義しています。TemplateColumnItemTemplateでは、LinkButtonを定義しています。LinkButtonは、レコードセレクターとして使用します。BoundColumnでは、得意先テーブルの得意先ID、得意先名、担当者名、役職、電話番号、都道府県をバインドしています。

 

191:     <Columns>
192:       <asp:TemplateColumn
193:         HeaderText="<div class='dgrdHeaderBox'>1</div>">
194:         <ItemTemplate>
195:           <asp:LinkButton id="lbtnSelect" runat="server"
196:             CommandName="Select"
197:             Text="<div class='dgrdItemArrow'>4</div>" Width="10"
198:             Visible="True" />
199:         </ItemTemplate>
202:       </asp:TemplateColumn>
203:       <asp:BoundColumn ItemStyle-Width="20"
204:         HeaderText="<div class='dgrdHeader'>ID</div>"
205:         DataField="CustomerID">
207:       </asp:BoundColumn>
          
・・・

228:     </Columns>

238-243では、TextBoxを定義しています。TextBoxReadOnlyプロパティがTrueになっていることに注意してください。このTextBoxは、メッセージを表示するのとは別に、Webページをポストバックさせるために重要な役割をします。TextBoxの役割については、コード編にて解説します。

 

238: <asp:TextBox id="txtMessage" runat="server"
239:   Text=""
240:   Style="background-color:SkyBlue"
241:   Columns="107"
242:   Visible="True"
243:   ReadOnly="True" />

248-251では、Buttonを定義しています。このButtonWebページをポストバックさせるのに重要な役割をします。ButtonVisibleプロパティには、Falseを設定しています。Buttonが非可視状態なのに、OnClickイベントを登録していますので不思議に思うかもしれません。実は、このイベントは、ランタイム時にプログラムから起動させます。

 

248: <asp:Button id="btnRefresh" runat="server"
249:   Text="Hidden"
250:   Visible="False"
251:   OnClick="btnRefresh_Click" />

 

リスト DataGridInsert.aspxのソースコード(HTML編)

132: <html>
137:
138: <body scroll="no">
146:
147: <form id="frmMain" runat="server">
148: <table cellpadding="3" width="100%">
149: <tr>
150:   <td align="left">
151:     <asp:ImageButton id="ibtnInsert" runat="server"
152:       CommandName="insert"
153:       OnCommand="ibtnInsert_Command"
154:       ImageUrl="../img/insert.gif"
155:       Title="Add new record"
156:       CssClass="imageButton"
157:       ImageAlign="Middle" />
158:     <asp:Label id="lblRows" runat="server"
159:       Text="
件数" Font-Name="Tahoma" Font-Size="9pt"
160:       CssClass="rowNumber" />
161:     <asp:TextBox id="txtRows" runat="server"
162:       CssClass="rowNumber"
163:       Columns="3"
164:       ReadOnly="True" />
165:   </td>
166: </tr>
167: </table>
168:
169: <table border="0" cellPadding="0" cellSpacing="0" >
174:
175: <tr>
176: <td valign="top" style="width:590">
177:   <asp:DataGrid id="dgrdCustomers" runat="server"
178:     AutoGenerateColumns="False"
179:     OnItemCommand="dgrdCustomers_ItemCommand"
180:     OnItemDataBound="dgrdCustomers_ItemDataBound"
181:     OnItemCreated="dgrdCustomers_ItemCreated"
182:     BorderColor="gainsboro"
183:     GridLines="Vertical"
184:     CellPadding="0"
185:     CssClass="dgrdShadow"
186:     EnableViewState="True">
        
・・・

191:     <Columns>
192:       <asp:TemplateColumn
193:         HeaderText="<div class='dgrdHeaderBox'>1</div>">
194:         <ItemTemplate>
195:           <asp:LinkButton id="lbtnSelect" runat="server"
196:             CommandName="Select"
197:             Text="<div class='dgrdItemArrow'>4</div>" Width="10"
198:             Visible="True" />
199:         </ItemTemplate>
200:         <ItemStyle  CssClass="recSelector"
201:           HorizontalAlign="Center" />
202:       </asp:TemplateColumn>
203:       <asp:BoundColumn ItemStyle-Width="20"
204:         HeaderText="<div class='dgrdHeader'>ID</div>"
205:         DataField="CustomerID">
206:         <ItemStyle HorizontalAlign="right" />
207:       </asp:BoundColumn>
          
・・・

228:     </Columns>
229:   </asp:DataGrid>
230: </td>
231:
232: <td valign="top">
233: </td>
234: </tr>
235: <tr>
236: <td colspan="2">
238: <asp:TextBox id="txtMessage" runat="server"
239:   Text=""
240:   Style="background-color:SkyBlue"
241:   Columns="107"
242:   Visible="True"
243:   ReadOnly="True" />
244: </td>
245: </tr>
246: </table>
247: <hr>
248: <asp:Button id="btnRefresh" runat="server"
249:   Text="Hidden"
250:   Visible="False"
251:   OnClick="btnRefresh_Click" />
252: </form>
253: </body>
253: </html>

 

 

 

  メインプログラムDataGridInsert.aspxの解説(コード編)

 

DataGridInsert.aspxは、DataGrid上に得意先テーブルを表示します。レコードの追加ボタンをクリックすると、子ウィンドウを開きます。また、子ウィンドウと連携して、子ウィンドウから追加したレコードをDataGridに表示する処理も行っています。

 

Sub Page_Load()イベントの処理

 

このイベントは、DataGridInsert.aspxがロードされたときに実行されます。このイベントでは、クライアント側で動作するイベントの登録と、DataGridに得意先テーブルをバインドします。

 

9-10では、メッセージを表示するTextBoxにクライアント側で動作する、onPropertyChangeイベントを登録しています。Webコントロールに、クライアント側で動作するイベントを登録するには、AttributesコレクションのAdd()メソッドを使用します。Add()メソッドの引数には、イベント名とイベントの処理を記述します。Page.GetPostBackEventReference()メソッドは、WebページをポストバックさせるためのJavaScriptを生成します。このメソッドの引数には、Webページがポストバックされたときに実行されるWebコントロールのIDを指定します。ここでは、リフレッシュボタンのID(btnRefresh)を指定しています。

 

  9:   txtMessage.Attributes.Add("OnPropertyChange", _
 10:     GetPostBackEventReference(btnRefresh))

Attributes.Add()メソッドが実行されると、以下のようなHTMLタグが生成されます。

 

<input name="txtMessage" type="text" size="107"

  readonly="readonly" id="txtMessage"

  OnPropertyChange="__doPostBack('btnRefresh','')"

  style="background-color:SkyBlue" />

 

GetPostBackEventReference()メソッドを使用すると、本来ポストバックしないWebコントロールをポストバックさせることができます。このサンプルでは、クライアント側からTextBoxTextプロパティを書き換えることによりWebページをポストバックさせてbtnRefreshのイベントを起動させています。

 

11-18If…Else…End Ifでは、DataGridに得意先テーブルをバインドしています。ページが最初にロードされたときは、BindDataGrid()を呼び出してDataGridに得意先テーブルをバインドします。ページがポストバックされたときは、Session変数に格納されている得意先テーブルのDataTableオブジェクトを取得して変数に保存します。Session変数にDataTableが保存されていないときは、BindDataGrid()を呼び出します。

 

  8: Sub Page_Load()
  9:   txtMessage.Attributes.Add("OnPropertyChange", _
 10:     GetPostBackEventReference(btnRefresh))
 11:   If Not IsPostBack Then
 12:     BindDataGrid()
 13:   Else
 14:     mdt = CType(Session("Customers"), DataTable)
 15:     If mdt Is Nothing Then
 16:       BindDataGrid()
 17:     End If
 18:   End If
 19: End Sub

 

 

Sub dgrdCustomers_ItemDataBound()イベントの処理

 

このイベントは、DataGridDataBind()メソッドが実行されたときに発生します。このイベントでは、DataGridのアイテム(DataGridItem)にクライアント側で動作するOnClickイベントを登録しています。これにより、任意のセルをクリックして行を選択できるようになります。

 

35: Sub dgrdCustomers_ItemDataBound(s As Object, _
 36:   e As DataGridItemEventArgs)
 37:   Dim lit As ListItemType = e.Item.ItemType
 40:   If lit = ListItemType.Item OrElse _
 41:     lit = ListItemType.AlternatingItem OrElse _
 42:     lit = ListItemType.SelectedItem  Then
 43:     Dim lbtn As LinkButton = _
 44:       CType(e.Item.FindControl("lbtnSelect"), LinkButton)
 45:     e.Item.Attributes("onClick") = GetPostBackClientHyperlink(lbtn, "")
 46:     e.Item.Style("cursor") = "hand"
 47:   End If
 48: End Sub

 

 

Sub ibtnInsert_Command()イベントの処理

 

このイベントは、Webページからレコードの追加ボタンをクリックしたときに発生します。このイベントでは、InsertScriptBlock()を呼び出して、新規ウィンドウを表示します。

 

57: Sub ibtnInsert_Command(s As Object, e As CommandEventArgs)
 58:   InsertScriptBlock()
 59: End Sub

 

 

Sub btnRefresh_Click()イベントの処理

 

このイベントは、クライアント側からメッセージを表示するTextBoxを書き換えたときに発生します。このサンプルでは、子ウィンドウから親ウィンドウのTextBoxにメッセージを設定して書き換えます。つまり、子ウィンドウから親ウィンドウをポストバックさせています。btnRefresh_Clickイベントでは、DataGridに得意先テーブルをバインドしてリフレッシュします。

 

22-27With…End Withでは、DataGridに得意先テーブルが格納されているDataTableをバインドしています。行28では、件数を表示するTextBoxにレコード件数を設定しています。レコード件数は、DataTableRowsコレクションのCountプロパティから取得します。

 

21: Sub btnRefresh_Click(s As Object, e As EventArgs)
 22:   With dgrdCustomers
 23:     .DataSource = mdt
 24:     .DataKeyField = "CustomerID"
 25:     .DataBind()
 26:     .SelectedIndex = -1
 27:   End With
 28:   txtRows.Text = mdt.Rows.Count.ToString()
 29: End Sub

 

 

Sub BindDataGrid()の処理

 

このサブプロシージャは、DataGridに得意先テーブルをバインドして表示します。BindDataGridは、Page_Loadイベントから呼ばれます。

 

62-63では、得意先テーブルからレコードを抽出するSQLを生成しています。このSQLでは、Order By句で「CustomerID Desc」を指定していますので、得意先IDの降順にレコードが並べ替えられます。また、Top 10のオプションを指定していますので、上位10件のレコードが抽出されます。

 

64では、CreateDataSet()関数を呼び出して得意先テーブルのDataSetを作成しています。CreateDataSet()の引数には、SQLを指定します。この関数からは、DataSetが返されます。

 

62:   Dim strSQL As String = "Select Top 10 * From Customers " & _
 63:     "Order by CustomerID Desc"
 64:   Dim ds AS DataSet = CreateDataSet(strSQL)

68では、DataSetTablesコレクションから得意先テーブルのDataTableを作成しています。

 

70-75With…End Withでは、DataGridに得意先テーブルのDataTableをバインドしています。行71では、DataGridDataSourceプロパティにDataTableを設定しています。行72では、DataKeyFieldプロパティに得意先テーブルの主キー(得意先ID)を設定しています。ここで設定した主キーは、DataGridから行を選択したときに参照します。行73では、DataBind()メソッドでDataTableをバインドしています。行74では、SelectedIndexプロパティに-1を設定して以前選択されていた行を解除しています。

 

76では、件数を表示するTextBoxTextプロパティに、レコード件数を設定しています。レコード件数は、DataTableRowsコレクションのCountプロパティから取得します。行77では、Session変数にDataTableを保存しています。Session変数に保存されたDataTableは、ページがポストバックされたときに再使用します。また、サブプログラムからも参照します。

 

61: Sub BindDataGrid()
 62:   Dim strSQL As String = "Select Top 10 * From Customers " & _
 63:     "Order by CustomerID Desc"
 64:   Dim ds AS DataSet = CreateDataSet(strSQL)
 65:   If ds Is Nothing Then
 66:     Exit Sub
 67:   End If
 68:   mdt = ds.Tables(0)
 69:
 70:   With dgrdCustomers
 71:     .DataSource = mdt
 72:     .DataKeyField = "CustomerID"
 73:     .DataBind()
 74:     .SelectedIndex = -1
 75:   End With
 76:   txtRows.Text = mdt.Rows.Count.ToString()
 77:   Session("Customers") = mdt
 78: End Sub

 

 

Sub InsertScriptBlock()の処理

 

このサブプロシージャでは、新規ウィンドウを開くJavaScriptを生成して登録します。InsertScriptBlockは、レコードの追加ボタンをクリックしたときに、追加ボタンのOnCommandイベントから呼ばれます。

 

81-83では、JavaScriptwindow.open()メソッドの引数に指定するオプションを生成しています。行85-90With…End Withでは、StringBuilder()Append()メソッドで以下のJavaScriptを生成しています。

 

<script language='javascript'>

window.open('PopupInsert.aspx','_blank','height=200,width=330,left=10,top=10,

location=no,menubar=no,resizable=yes,scrollbars=no,status=no,titlebar=yes,toolbar=no');

</script>

 

JavaScriptwindow.open()メソッドは、新規ウィンドウを開きます。Open()メソッドの引数には、urltargetfeaturesを指定します。Urlには、新規ウィンドウに表示するファイルPopupInsert.aspxを指定します。Targetには、_blankを指定して新規ウィンドウを開くようにします。Featuresには、ウィンドウのサイズなど各種オプションを指定します。

 

91では、Page.RegisterClientScriptBlock()メソッドでJavaScriptを登録します。ここで登録したJavaScriptは、Webページがロードされたときにクライアント側のブラウザで実行されます。

 

80: Sub InsertScriptBlock()
 81:   Dim strFeatures As String = "height=200,width=330,left=10,top=10," & _
 82:     "location=no,menubar=no,resizable=yes,scrollbars=no," & _
 83:     "status=no,titlebar=yes,toolbar=no"
 84:   Dim sbScript As New StringBuilder()
 85:   With sbScript
 86:     .Append("<script language='javascript'>" & vbCrLf)
 87:     .Append(vbTab & "window.open('PopupInsert.aspx','_blank','" & _
 88:       strFeatures & "');" & vbCrLf)
 89:     .Append("</" & "script>")
 90:   End With
 91:   RegisterClientScriptBlock("openWindow", sbScript.ToString)
 92: End Sub

 

 

Sub InsertAlertScript()の処理

 

このサブプロシージャでは、エラーメッセージをポップアップウィンドウに表示するJavaScriptを生成して登録します。InsertAlertScriptは、CreateDataSet()関数からエラーが発生したときに呼ばれます。

 

95では、引用符(')JavaScriptのエスケープシーケンス\'に置換しています。メッセージに引用符が含まれると、alert()メソッドでエラーとなるのを回避します。行97-102では、StringBuilderAppend()メソッドで以下のJavaScriptを生成しています。

 

<script language='javascript'>

  alert('Error Message');

</script>

 

JavaScriptalert()メソッドは、エラーメッセージをポップアップウィンドウに表示します。

 

103では、Page.RegisterClientScriptBlick()メソッドでJavaScriptを登録しています。ここで登録したJavaScriptは、Webページがロードされたときにクライアント側のブラウザで実行されます。

 

94: Sub InsertAlertScript(strMessage As String)
 95:   Dim strMsg As String = strMessage.Replace("'","\'")
 96:   Dim sbScript As New StringBuilder()
 97:   With sbScript
 98:     .Append("<script language='javascript'>" & vbCrLf)
 99:     .Append(vbTab & "alert('" & strMsg & "');" & vbCrLf)
101:     .Append("</" & "script>")
102:   End With             
103:   RegisterClientScriptBlock("alertScript", sbScript.ToString)
104: End Sub

 

 

Function CreateDataSet()関数の処理

 

この関数は、DataSetを作成して返します。CreateDataSetは、BindDataGrid()から呼ばれます。

 

117-118では、Connectionのインスタンスを生成しています。Connectionの引数には、Web.Configに登録されているデータベース接続文字列を指定しています。Web.Configに登録されている内容を取得するには、ConfigurationSettingsAppSettings()メソッドを使用します。AppSettings()メソッドの引数には、<add>タグのkeyを指定します。

 

117:   Dim con As New OleDbConnection( _
118:     ConfigurationSettings.AppSettings("
conStringAccNw"))

<appSettings>

  <add key="conStringAccNw"

   value="PROVIDER=Microsoft.Jet.OLEDB.4.0;DATA Source=C:\WebMatrix\webdb\Nwind.mdb" />                         

</appSettings>

 

119では、DataAdapterのインスタンスを生成しています。DataAdapterの引数には、SQLConnectionオブジェクトを指定しています。

 

121-126Try…Catch…End Tryブロックでは、DataAdapterFill()メソッドでSQLを実行して得意先テーブルをDataSetに取り込んでいます。行121-122Tryブロックでエラーが発生したときは、行123-125Catchブロックが実行されます。Catchブロックでは、InsertAlertScript()を呼び出してポップアップウィンドウにエラーメッセージを表示します。

 

121:   Try
122:     da.Fill(ds)
123:   Catch e As Exception
124:     InsertAlertScript(e.Message)
125:     Return Nothing
126:   End Try

127では、関数の戻り値としてDataSetを返します。

 

115: Function CreateDataSet(strSQL As String, _
116:   Optional strConnectionString As String = "conStringAccNw") As DataSet
117:   Dim con As New OleDbConnection( _
118:     ConfigurationSettings.AppSettings(strConnectionString))
119:   Dim da As New OleDbDataAdapter(strSQL, con)
120:   Dim ds As New DataSet()
121:   Try
122:     da.Fill(ds)
123:   Catch e As Exception
124:     InsertAlertScript(e.Message)
125:     Return Nothing
126:   End Try
127:   Return ds
128: End Function

 

 

リスト DataGridInser.aspxのソースコード(コード編)

  1: <%@ Page language="vb" SmartNavigation="false"  %>
  2: <%@ Import Namespace="System.Data" %>
  3: <%@ Import Namespace="System.Data.OleDb" %>
  4:
  5: <script language="vb" runat="server">
  6: Private mdt As DataTable

7:
  8: Sub Page_Load()
 19: End Sub
 20:
 21: Sub btnRefresh_Click(s As Object, e As EventArgs)
 29: End Sub
 34:
 35: Sub dgrdCustomers_ItemDataBound(s As Object, _
 36:   e As DataGridItemEventArgs)
 48: End Sub
 56:
 57: Sub ibtnInsert_Command(s As Object, e As CommandEventArgs)
 59: End Sub
 60:
 61: Sub BindDataGrid()
 78: End Sub
 79:
 80: Sub InsertScriptBlock()
 92: End Sub
 93:

 94: Sub InsertAlertScript(strMessage As String)

104: End Sub
114:
115: Function CreateDataSet(strSQL As String, _
116:   Optional strConnectionString As String = "conStringAccNw") As DataSet
128: End Function
130: </script>

 

 

  サブプログラムPopupInsert.aspxの解説(HTML編)

 

子ウィンドウのWebフォームには、TextBoxButtonを作成しています。TextBoxには、新規レコードを入力します。

 

85-162<fieldset>…</fieldset>では、角の丸みがかったボックスを表示しています。行86-90<legend>…</legend>では、ボックスの凡例を表示しています。

 

 

丸みがかったボックスと凡例を表示した例

 

92-104<tr>…</tr>では、得意先IDLabelTextBoxを定義しています。得意先IDは、自動採番されるのでTextBoxReadOnlyプロパティにTrueを設定して読み込み専用にしています。

 

106-120<tr>…</tr>では、得意先名のLabelTextBoxを定義しています。行116-118では、RequiredFieldValidatorで得意先名が入力されているかチェックしています。得意先名を入力しないで追加ボタンをクリックすると、TextBoxの右側に「*」が表示されます。

 

エラーメッセージの「*」が表示された例

 

後続する<tr>…</tr>では、担当者名、部署役職、電話番号のLabelTextBoxを定義しています。

 

165-205<table>…</table>には、ImageButtonLabelDropDownListButtonを定義しています。ImageButtonDropDownListEnabledプロパティには、Falseを設定して使用不可にしています。このサンプルでは、これらの機能はサポートしていません。行195-202では、「追加」と「閉じる」のボタンを定義しています。「閉じる」のボタンには、CausesValidationプロパティにFalseを設定してRequiredFieldValidatorを適用させないようにしています。

 

ImageButtonLabelDropDownListを使用不可の状態で表示した例

 

 

リスト PopupInsert.aspxのソースコード(HTML編)

76: <html>
 82: <body>
 83: <form id="frmPopupInsert" runat="server">
 85: <fieldset>
 86:   <legend>
 87:     <div style="font-family:Tahoma;font-size:9pt;">
 88:       [
得意先]
 89:     </div>
 90:   </legend>
 91: <table>
 92: <tr>
 93:   <td width="20%">
 94:     <asp:Label id="lblCustomerID" runat="server"
 95:       CssClass="label"
 96:       Text="ID" />
 97:   </td>
 98:   <td>
 99:     <asp:TextBox id="txtCustomerID" runat="server"
100:       CssClass="textBox"
101:       Text="auto"
102:       Columns="4" ReadOnly="True" />
103:   </td>
104: </tr>
106: <tr>
107:   <td>
108:     <asp:Label id="lblCompanyName" runat="server"
109:       CssClass="label"
110:       Text="
得意先名" />
111:   </td>
112:   <td>
113:     <asp:TextBox id="txtCompanyName" runat="server"
114:       CssClass="textBox"
115:       Columns="40" />
116:     <asp:RequiredFieldValidator runat="server"
117:       ControlToValidate="txtCompanyName"
118:       ErrorMessage="*" />
119:   </td>
120: </tr>
    
・・・
161: </table>
162: </fieldset>
163:
164: <fieldset>
165: <table>
166: <tr>
167:   <td align="left">
168:     <asp:ImageButton id="ibtnPrev" runat="server"
169:       CausesValidation="False"
170:       CommandName="prev"
171:       ImageUrl="../img/prevoff.gif"
172:       Title="Prev"
173:       CssClass="imageButton"
174:       Enabled="False"
175:       ImageAlign="Middle" />
176:     <asp:ImageButton id="ibtnNext" runat="server"
177:       CausesValidation="False"
178:       CommandName="next"
179:       ImageUrl="../img/nextoff.gif"
180:       Title="Next"
181:       CssClass="imageButton"
182:       Enabled="False"
183:       ImageAlign="Middle" />
184:     <asp:Label id="lblEditor" runat="server"
185:       Text="
エディタ" Font-Name="Tahoma" Font-Size="9pt"
186:       CssClass="statusRow" />
187:     <asp:DropDownList id="dropEditor" runat="server"
188:       CssClass="statusRow"
189:       Enabled="False">
190:       <asp:ListItem Text="Text" />
191:       <asp:ListItem Text="HTML" />
192:     </asp:DropDownList>

193:   </td>
194:   <td align="right">             
195:     <asp:Button id="btnAdd" runat="server"
196:       Text="
追加"
197:       Style="vertical-align:middle"
198:       OnClick="btnAdd_Click" />
199:     <asp:Button id="btnClose" runat="server"
200:       CausesValidation="False"
201:       Text="
閉じる"
202:       Style="vertical-align:middle" />             
203:   </td>
204: </tr>
205: </table>
206: </fieldset>
208: </form>
209: </body>
209: </html>

 

 

  サブプログラムPopupInsert.aspxの解説(コード編)

 

PopupInsert.aspxは、Webフォームから入力した得意先データをDataTableに追加します。さらに、DataTableに追加したレコードをデータベースに反映します。追加したレコードをデータベースに反映したら、親ウィンドウをポストバックさせてDataGrid上に追加したレコードを表示します。

 

Sub Page_Load()イベントの処理

 

このイベントは、ページがロードされたときに発生します。Page_Loadでは、ページの初期化処理を行います。

 

9では、Session変数に保存されている得意先テーブルのDataTableを取得して変数に退避します。行10-13If…EndIfでは、ページが最初にロードされたか調べています。最初にロードされたときは、AddCursor()を呼び出してアプリケーション独自のカーソルを表示しています。さらに、「閉じる」ボタンにクライアント側で動作するonClickイベントを登録しています。このイベントでは、JavaScriptwindow.close()メソッドを実行して子ウィンドウを閉じます。

 

 8: Sub Page_Load()
  9:   mdt = CType(Session("Customers"), DataTable)
 10:   If Not IsPostBack Then
 11:     AddCursor()
 12:     btnClose.Attributes.Add("onclick", "window.close();")
 13:   End If
 14: End Sub

 

 

Sub btnAdd_Click()イベントの処理

 

このイベントは、追加ボタンをクリックしたときに発生します。このイベントでは、得意先テーブルに新規レコードを追加します。また、ここで追加したレコードを親ウィンドウのDataGridに反映させます。

 

17では、InsertRecord()関数を呼び出して得意先テーブルにレコードを追加します。この関数からは、処理の結果がメッセージで返されます。行19-24With…End Withでは、StringBuilderAppend()メソッドで以下のJavaScriptを生成しています。

 

<script language='javascript'>

  window.opener.frmMain.txtMessage.value = 'XXX';

</script>

 

JavaScriptwindow.opener.frmMain.txtMessage.value=は、親ウィンドウのtxtMessage.valueにメッセージを設定します。txtMessageには、クライアント側で動作するonProperyChangeイベントが登録されていますので、このイベントが実行されます。onPropertyChangeイベントには、WebページをポストバックさせるJavaScriptが記述されていますので、WebページがポストバックされてDataGridがリフレッシュされます。これで親ウィンドウのDataGridには、子ウィンドウから追加したレコードが表示されます。

 

25では、Page.RegisterClientScriptBlock()メソッドでJavaScriptを登録しています。ここで登録した、JavaScriptは、Webページがロードされたときクライアント側のブラウザから実行されます。

 

 

16: Sub btnAdd_Click(s As Object, e As EventArgs)
 17:   Dim strMessage As String = InsertRecord()
 18:   Dim sbScript As New StringBuilder()

19:   With sbScript
 20:     .Append("<script language='javascript'>" & vbCrLf)
 21:     .Append(vbTab & "window.opener.frmMain.txtMessage.value = '" & _
 22:       strMessage & "';" & vbCrLf)
 23:     .Append("</" & "script>")
 24:   End With
 25:   RegisterClientScriptBlock("insert", sbScript.ToString)
 26: End Sub

 

 

Sub AddCursor()の処理

 

このサブプロシージャでは、アプリケーション独自のカーソルを追加します。AddCursorは、Page_Loadイベントからページが最初にロードされたときに呼ばれます。

 

カーソルを追加するには、TextBoxにクライアント側で動作するonFocusonBlurイベントを登録します。onFocusイベントは、TextBoxがフォーカスを取得したときに発生します。onBlurは、フォーカスを喪失したときに発生します。これらのイベントで、TextBoxの背景色を書き換えることによりアプリケーション独自のカーソルを表示することができます。

 

TextBoxにクライアント側で動作するイベントを登録するには、AttributesコレクションのAdd()メソッドを使用します。Add()メソッドの引数には、イベント名とイベント処理を記述します。

 

onFocusイベントでは、TextBoxの背景色をLightGreenに書き換えます。onBlueイベントでは、TextBoxの背景色をAliceBlueに戻します。

 

 

28: Sub AddCursor()
 29:   txtCompanyName.Attributes.Add("onFocus","this.style.backgroundColor='LightGreen'")
 30:   txtCompanyName.Attributes.Add("onBlur","this.style.backgroundColor='AliceBlue'")
 31:
 32:   txtContactName.Attributes.Add("onFocus","this.style.backgroundColor='LightGreen'")
 33:   txtContactName.Attributes.Add("onBlur","this.style.backgroundColor='AliceBlue'")
 34:
 35:   txtContactTitle.Attributes.Add("onFocus","this.style.backgroundColor='LightGreen'")
 36:   txtContactTitle.Attributes.Add("onBlur","this.style.backgroundColor='AliceBlue'")
 37:
 38:   txtPhone.Attributes.Add("onFocus","this.style.backgroundColor='LightGreen'")
 39:   txtPhone.Attributes.Add("onBlur","this.style.backgroundColor='AliceBlue'")
 40: End Sub

 

 

Function InsertRecord()関数の処理

 

この関数では、Webフォームに入力したデータを得意先テーブルのDataTableに追加します。InsertRecordは、追加ボタンのOnClickイベントから呼ばれます。

 

43-46では、TextBoxから入力した得意先名、担当者名、部署各職、電話番号を取得します。行49-54では、DataTableに新規レコードを追加しています。行49では、DataTableNewRow()メソッドでDataRowを作成します。行50-53では、DataRowのカラムに得意先名、担当者名、部署各職、電話番号を設定しています。行54では、DataTableRowsコレクションのAdd()メソッドでDataRowを追加しています。ここで追加したレコードは、DataTableに追加されただけで、データベースには反映されていません。

 

56では、UpdateDataTable()関数を呼び出して、DataTableをデータベースに反映します。UpdateDataTable()からは、処理の結果を示すメッセージとして「正常終了!」、「エラー発生!」が返されます。

 

 

42: Function InsertRecord() As String
 43:   Dim strCompanyName As String = txtCompanyName.Text.Trim()
 44:   Dim strContactName As String = txtContactName.Text.Trim()
 45:   Dim strContactTitle As String = txtContactTitle.Text.Trim()
 46:   Dim strPhone As String = txtPhone.Text.Trim()
 47:   Dim strSQL As String = "Select CustomerID, CompanyName, ContactName,

ContactTitle, Phone From Customers"

48:
 49:   Dim dr As DataRow = mdt.NewRow
 50:   dr("CompanyName") = strCompanyName
 51:   dr("ContactName") = strContactName
 52:   dr("ContactTitle") = strContactTitle
 53:   dr("Phone") = strPhone
 54:   mdt.Rows.Add(dr)
 55:
 56:   Return UpdateDataTable(strSQL)
 57: End Function

 

 

Function UpdateDataTable()関数の処理

 

この関数では、DataTableに追加されたレコードをデータベースに反映します。UpdateDataTableは、InsertRecord()から呼ばれます。UpdateDataTable()の引数には、strSQLstrConnectionStringを指定します。strSQLには、得意先テーブルからレコードを抽出するSQLを指定します。strConnectionStringには、データベースの接続文字列を指定します。DataTableをデータベースに反映するには、DataAdapterUpdate()メソッドを使用します。Update()メソッドで使用するINSERTUPDATEDELETESQLは、CommandBuilderで自動生成します。

 

61-62では、Connectionのインスタンスを生成しています。Connectionの引数には、データベースの接続文字列を指定します。行63では、DataAdapterのインスタンスを生成しています。DataAdapterの引数には、SQLConnectionのオブジェクトを指定します。引数のSQLには、SELECTステートメントを指定します。行64では、CommandBuilderDataTableをデータベースに反映するためのSQLを自動生成します。CommandBuilderは、SELECTステートメントを元にINSERTUPDATEDELETESQLを生成します。

 

66-70Try…Catch…End Tryブロックでは、DataAdapterUpdate()メソッドでDataTableの変更された内容をデータベースに反映します。DataTableに新規レコードが追加されたときは、SQLINSERTステートメントを実行してDataTableのレコードをデータベースに追加します。DataTableのレコードが更新されたときは、UPDATEステートメントで、データベースのレコードを更新します。DataTableのレコードが削除されたときは、DELETEステートメントで、データベースからレコードを削除します。得意先テーブルのレコードを更新、削除するときは、他のユーザから変更されていないことを確認してから実行します。他のユーザから変更されているときは、同時実行違反のエラーになります。このサンプルでは、レコードの追加しか行っていませんので同時実行違反のエラーになることはありません。

 

Update()メソッドでエラーが発生したときは、行68-69Catchブロックが実行されます。

 

71では、Session変数に格納されているDataTableを解放します。Session変数に保存されているDataTableを解放すると、メインプログラムがポストバックされたときに、得意先テーブルをデータベースから読み込んでリフレッシュします。行72では、戻り値として処理の結果を示すメッセージを返します。

 

 

59: Function UpdateDataTable(strSQL As String, _
 60:   Optional strConnectionString As String = "conStringAccNw") As String
 61:   Dim con As New OleDbConnection( _
 62:     ConfigurationSettings.AppSettings(strConnectionString))
 63:   Dim da As New OleDbDataAdapter(strSQL, con)
 64:   Dim cb As New OleDbCommandBuilder(da)
 65:   Dim strMessage As String = "
正常終了!"
 66:   Try
 67:     da.Update(mdt)
 68:   Catch
 69:     strMessage = "
エラー発生 !"
 70:   End Try
 71:   Session("Customers") = Nothing
 72:   Return strMessage
 73: End Function

 

 

リスト PopupInsert.aspxのソースコード(コード編)

  1: <%@ Page language="vb" %>
  2: <%@ Import Namespace="System.Data" %>
  3: <%@ Import Namespace="System.Data.OleDb" %>
  4:
  5: <script language="vb" runat="server">
  6: Private mdt As DataTable
  7:
  8: Sub Page_Load()
 14: End Sub
 15:
 16: Sub btnAdd_Click(s As Object, e As EventArgs)
 26: End Sub
 27:
 28: Sub AddCursor()
 40: End Sub
 41:
 42: Function InsertRecord() As String
 57: End Function
 58:
 59: Function UpdateDataTable(strSQL As String, _
 73: End Function
 74: </script>

 

Note

CommandBuilder()を使用する場合の留意事項

 

CommandBuilderは、DataAdapterSelectCommandに格納されているSELECTステートメントを元にINSERTUPDATEDELETEステートメントを自動生成します。CommandBuilderで使用するSELECTステートメントには、以下の制約があります。これらの制約に違反するときは、CommandBuilderを使用しないでINSERTUPDATEDELETEステートメントを手動にて用意する必要があります。

 

  DataAdapterSelectCommandに格納されているSELECTステートメントでは、テーブルの主キーを選択する必要があります。

  SelectCommandに格納されているSELECTステートメントでは、JOINなどで複数のテーブルを結合することはできまません。

  SELECTステートメントに、計算式などを記述することはできません。テーブルのフィールド名のみ記述する必要があります。

 

 

Note

DataAdapterUpdate()メソッドで使用するINSERTステートメントを手動で用意するには

 

Update()メソッドで使用するINSERTステートメントを手動で用意するには、INSERTCommandオブジェクトを作成してDataAdapterInsertCommandに設定します。

 

.Add("@CompanyName", OleDbType.VarWChar, 40, "CompanyName")

.Add("@ContactName", OleDbType.VarWChar, 30, "ContactName")

.Add("@ContactTitle", OleDbType.VarWChar, 30, "ContactTitle")

.Add("@Phone", OleDbType.VarWChar, 24, "Phone")

 

INSERTステートメントのパラメータ@CompanyName@ContactName@ContactTitle@Phoneには、DataTableDataColumnが関連付けられていますので、自動的に値が代入されます。

 

Dim con = New OleDbConnection( _

  ConfigurationSettings.AppSettings("conStringAccNw"))

Dim da As New OleDbDataAdapter(strSQL, con)

 

da.InsertCommand = CreateInsertCommand()

 

Function CreateInsertCommand() As OleDbCommand

  Dim sbSQL As New StringBuilder()

 

  With sbSQL

    .Append("Insert Into Customers " & vbCrLf)

    .Append(" (CompanyName, ContactName, ContactTitle, Phone) " & vbCrLf)

    .Append(" Values(?, ?, ?, ?)")

  End With

  Dim cmd As New OleDbCommand(sbSQL.ToString, con)

  Dim pc As OleDbParameterCollection = cmd.Parameters

  With pc

    .Add("@CompanyName", OleDbType.VarWChar, 40, "CompanyName")

    .Add("@ContactName", OleDbType.VarWChar, 30, "ContactName")

    .Add("@ContactTitle", OleDbType.VarWChar, 30, "ContactTitle")

    .Add("@Phone", OleDbType.VarWChar, 24, "Phone")

  End With

  Return cmd

End Function

 

 

 

Tip

CommandBuilder()で生成されたINSERTUPDATEDELETEステートメントを表示するには

 

CommandBuilderで生成されたINSERTUPDATEDELETEステートメントを取得するには、CommandBuilderGetInsertCommandGetUpdateCommandGetDeleteCommandCommandTextを参照します。

 

Dim strSQL As String = "Select CustomerID, CompanyName, ContactName,

ContactTitle, Phone From Customers"

 

Dim con As New OleDbConnection( _

  ConfigurationSettings.AppSettings(strConnectionString))

Dim da As New OleDbDataAdapter(strSQL, con)

Dim cb As New OleDbCommandBuilder(da)

 

Response.Write(cb.GetInsertCommand.CommandText & "<br>")

Response.Write(cb.GetUpdateCommand.CommandText & "<br>")

Response.Write(cb.GetDeleteCommand.CommandText & "<br>")

 

 

SELECTステートメント:

SELECT CustomerID, CompanyName, ContactName, ContactTitle, Phone From Customers

 

 

INSERTステートメント:

INSERT INTO Customers( CompanyName , ContactName , ContactTitle , Phone )

  VALUES ( ? , ? , ? , ? )

 

 

UPDATEステートメント:

UPDATE Customers SET CompanyName = ? , ContactName = ? ,

  ContactTitle = ? , Phone = ?

WHERE ( (CustomerID = ?)

AND ((? IS NULL AND CompanyName IS NULL) OR (CompanyName = ?))

AND ((? IS NULL AND ContactName IS NULL) OR (ContactName = ?))

AND ((? IS NULL AND ContactTitle IS NULL) OR (ContactTitle = ?))

AND ((? IS NULL AND Phone IS NULL) OR (Phone = ?)) )

 

 

DELETEステートメント:

DELETE FROM Customers

WHERE ( (CustomerID = ?)

AND ((? IS NULL AND CompanyName IS NULL) OR (CompanyName = ?))

AND ((? IS NULL AND ContactName IS NULL) OR (ContactName = ?))

AND ((? IS NULL AND ContactTitle IS NULL) OR (ContactTitle = ?))

AND ((? IS NULL AND Phone IS NULL) OR (Phone = ?)) )

 

 

UPDATEDELETEステートメントのWHERE句では、レコードが他のユーザから変更されていないことを確認してから更新、削除していることが解ります。

 

 

 

Tip

追加ボタンの処理が完了するまで再度ボタンをクリックできないようにするには

 

子ウィンドウから追加ボタンをクリックしてレコードの追加処理中に、再度追加ボタンをクリックすると同じレコードが重複して追加されます。得意先テーブルのように主キー(得意先ID)がオートナンバー型の場合、システムが得意先IDを自動採番するため、重複エラーにならないで登録されてしまいます。この不都合を回避するには、追加ボタンをクリックしたときに、追加処理が完了するまで追加ボタンを使用不可の状態にします。

 

追加ボタンをクリックしたときに使用不可の状態にするには、Page_LoadイベントでDisableAddButton()を呼びます。DisableAddButton()では、以下のようなJavaScriptを生成してWebページに登録します。

 

<script language='javascript'>

function verifyStatus() {

  if (typeof(Page_ClientValidate) != 'function' ||  Page_ClientValidate()) {

    if (document.frmPopupInsert.btnAdd.disabled==false) {

      document.frmPopupInsert.btnAdd.disabled=true;

      __doPostBack('btnAdd','');

      return true;

    } else {

      return false;

    }

  } else {

    return false;

  }

}

</script>

 

DisableAddButton()で登録したJavaScriptverifyStatus()関数は、<span>…</span>タグのonClickイベントから呼びます。

 

<span onClick="return verifyStatus();">

  <asp:Button id="btnAdd" runat="server"

    Text="追加"

    OnClick="btnAdd_Click" />

</span>

 

Webページから追加ボタンをクリックすると、spanonClickイベントが発生してverifyStatus()関数を呼びます。verifyStatus()では、追加ボタンを使用不可の状態にしてからWebページをポストバックします。Webページがポストバックされると、追加ボタンのOnClickイベントが実行されます。

 

Sub Page_Load()

DisableAddButton()

End Sub

 

Sub DisableAddButton()

  Dim sbScript As New StringBuilder()

 

  With sbScript

    .Append("<script language='javascript'>" & vbCrLf)

    .Append("function verifyStatus() {" & vbCrLf)

    .Append("  if (typeof(Page_ClientValidate) != 'function' ||  Page_ClientValidate()) {" & vbCrLf)

    .Append("    if (document.frmPopupInsert.btnAdd.disabled==false) {" & vbCrLf)

    .Append("      document.frmPopupInsert.btnAdd.disabled=true;" & vbCrLf)

    .Append("      " & GetPostBackEventReference(btnAdd) & ";" & vbCrLf)

    .Append("      return true;" & vbCrLf)

    .Append("    } else {" & vbCrLf)

    .Append("      return false;" & vbCrLf)

    .Append("    }" & vbCrLf)

    .Append("  } else {" & vbCrLf)

    .Append("    return false;" & vbCrLf)

    .Append("  }" & vbCrLf)

    .Append("}" & vbCrLf)

    .Append("</" & "script>")

  End With

  RegisterClientScriptBlock("clientScript", sbScript.ToString)

End Sub

 

 

ASP.NET DataGrid2のホームへ戻る