- PR -

「DataGridコントロールのヘッダーを複数行にするには?」で先頭行のドロップダウンが初期化される?

1
投稿者投稿内容
まう
会議室デビュー日: 2004/01/09
投稿数: 2
お住まい・勤務地: 神奈川県
投稿日時: 2004-01-09 09:14
 はじめまして。こちらの.NET TIPSをいつも参考にさせていただいています。

 「DataGridコントロールのヘッダーを複数行にするには?」で、うまく動かないパターンがあります。
 環境は、Windows2000Pro + IIS + VS.NET 2003 + .NET Framework v1.1です。
 以下がその現象です。

------------------------------------------------------------

 Webフォームにデータグリッドを1つ置きます。

 グリッドには、ボタン、テキストボックス、ドロップダウンリストの3つのカラムがあります。全てテンプレート項目です。
 ボタンは、ItemTemplateに「削除」ボタン、FooterTemplateに「追加」ボタンを設定しました。追加ボタンクリック時に、グリッドの末尾に1行追加する仕様です。「削除」ボタンクリック時には該当行を削除する仕様ですが、今回はその処理を書いていません。
 テキストボックス、ドロップダウンリストはItemTemplateにのみ設定しました。

 ドロップダウンリストは設計時に仮の内容を設定してありますが、実際は実行時に内容を設定します。

 Page_Loadのポストバック時以外でグリッドに1行追加し、1行の入力行が表示されている状態を初期状態としています。

 追加ボタンクリック時の処理は、
  1.現在のグリッドの表示内容を、テーブルに保存する
  2.保存したテーブルに、新規の行を追加する
  3.保存したテーブルをグリッドにバインドする
  4.グリッドのヘッダを2行にする
  5.保存したテーブルの内容から、グリッドのテンプレート項目を再編集する

 異常が発生するのは1.の処理の個所です。グリッドの1行目のみ、ブラウザ上は実行時に設定した内容が表示されているにもかかわらず、コードでは設計時の内容が返ってきてしまいます。グリッドの2行目以降のドロップダウンは実行時に設定した内容を返します。また、テキストボックスの値は1行目からちゃんと入力値を返してきます。

 そして「削除」ボタンクリックでは、先頭行のドロップダウンのみが設計時の内容に戻ってしまいます。他の2行目以降のドロップダウンはViewStateが効いているのに…。

 作成したヘッダを追加する処理をコメントにすると正常に動作するので、ここが原因なのは間違いないと思われます。が、テキストボックスは正常なのに、ドロップダウンのしかも1行目だけ異常というのは、何かDataGridコントロールのバグのような匂いもしますが…。

------------------------------------------------------------

 ヘッダを2行にできると何かと便利なので、なんとかしてこの個所を解決したく、自分でも処理の順番を代えたり色々やってみましたが、解決方法が見つかりません。

 何かよい方法はありませんでしょうか。よろしくお願い致します。


----------------
WebForm1.aspx
----------------
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
 <HEAD>
  <title>WebForm1</title>
  <META http-equiv="Content-Type" content="text/html; charset=shift_jis">
  <meta name="GENERATOR" content="Microsoft Visual Studio .NET 7.1">
  <meta name="CODE_LANGUAGE" content="Visual Basic .NET 7.1">
  <meta name="vs_defaultClientScript" content="JavaScript">
  <meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">
 </HEAD>
 <body>
  <form id="Form1" method="post" runat="server">
   <asp:DataGrid id="DataGrid1" style="Z-INDEX: 101; LEFT: 21px; POSITION: absolute; TOP: 20px" runat="server"
    AutoGenerateColumns="False" BorderColor="Gray" BorderWidth="1px" ShowFooter="True" Font-Names="MS ゴシック"
    Font-Size="9pt">
    <ItemStyle Font-Size="9pt" Font-Names="MS ゴシック" Wrap="False"></ItemStyle>
    <HeaderStyle Font-Size="9pt" Font-Names="MS ゴシック" ForeColor="Black" BackColor="Silver"></HeaderStyle>
    <FooterStyle ForeColor="Black" BackColor="Silver"></FooterStyle>
    <Columns>
     <asp:TemplateColumn HeaderText="ボタン">
      <ItemTemplate>
       <asp:Button id="btnDelete" runat="server" Text="削除"></asp:Button>
      </ItemTemplate>
      <FooterTemplate>
       <asp:Button id="btnAdd" runat="server" Text="追加"></asp:Button>
      </FooterTemplate>
     </asp:TemplateColumn>
     <asp:TemplateColumn HeaderText="入力テキスト">
      <ItemTemplate>
       <asp:TextBox id="txtInput" runat="server" Width="89px">設計時初期値</asp:TextBox>
      </ItemTemplate>
     </asp:TemplateColumn>
     <asp:TemplateColumn HeaderText="選択ドロップダウン">
      <ItemTemplate>
       <asp:DropDownList id="ddlSelect" runat="server" Width="167px">
        <asp:ListItem Value="設計時内容0" Selected="True">設計時内容0(初期選択)</asp:ListItem>
        <asp:ListItem Value="設計時内容1">設計時内容1</asp:ListItem>
        <asp:ListItem Value="設計時内容2">設計時内容2</asp:ListItem>
       </asp:DropDownList>
      </ItemTemplate>
     </asp:TemplateColumn>
    </Columns>
   </asp:DataGrid>
  </form>
 </body>
</HTML>

----------------
WebForm1.aspx.vb
----------------
Public Class WebForm1
 Inherits System.Web.UI.Page

#Region " Web フォーム デザイナで生成されたコード "

 'この呼び出しは Web フォーム デザイナで必要です。
 <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()

 End Sub
 Protected WithEvents DataGrid1 As System.Web.UI.WebControls.DataGrid

 'メモ : 次のプレースホルダ宣言は Web フォーム デザイナで必要です。
 '削除および移動しないでください。
 Private designerPlaceholderDeclaration As System.Object

 Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init
  ' CODEGEN: このメソッド呼び出しは Web フォーム デザイナで必要です。
  ' コード エディタを使って変更しないでください。
  InitializeComponent()
 End Sub

#End Region

 Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
  ' ページを初期化するユーザー コードをここに挿入します。
  If Not Page.IsPostBack Then
   'グリッドを初期化
   AddRow()
  End If
 End Sub

 Private Sub DataGrid1_ItemCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs) Handles DataGrid1.ItemCommand
  'グリッド内のボタンクリック
  If CType(e.CommandSource, Button).ID() = "btnAdd" Then
   '追加ボタン
   AddRow()
  ElseIf CType(e.CommandSource, Button).ID() = "btnDelete" Then
   '削除ボタン(今回省略)
  End If
 End Sub

 'グリッドの末尾に行を追加する
 Private Sub AddRow()
  '保存用のテーブル作成
  Dim tblTmp As DataTable = New DataTable
  tblTmp.TableName = "TempTable"
  tblTmp.Columns.Add(New DataColumn)
  tblTmp.Columns.Add(New DataColumn)

  '現在のグリッド行の内容をテーブルに保存する
  Dim i As Integer
  For i = 0 To DataGrid1.Items.Count - 1
   '保存用のレコードを作成
   Dim tmpRow As DataRow = tblTmp.NewRow

   'テキストボックスの内容を取得
   Dim txtTmp As TextBox = DataGrid1.Items(i).FindControl("txtInput")
   If Not (txtTmp Is Nothing) Then
    tmpRow.Item(0) = txtTmp.Text
   End If

   'ドロップダウンリストの選択値を取得
   Dim ddlTmp As DropDownList = DataGrid1.Items(i).FindControl("ddlSelect")
   If Not (ddlTmp Is Nothing) Then
    tmpRow.Item(1) = ddlTmp.SelectedValue
   End If

   '作成したレコードをテーブルに追加
   tblTmp.Rows.Add(tmpRow)
  Next

  '末尾に新規レコードを追加
  Dim tmpAddRow As DataRow = tblTmp.NewRow
  tmpAddRow.Item(0) = ""
  tmpAddRow.Item(1) = ""
  tblTmp.Rows.Add(tmpAddRow)

  'グリッドにバインドする
  DataGrid1.DataSource = tblTmp.DefaultView
  DataGrid1.DataMember = tblTmp.TableName
  DataGrid1.DataBind()

  'ヘッダを2行にする
  Dim newHeader As DataGridItem = New DataGridItem(-1, -1, ListItemType.Header)
  Dim newCell As TableCell = New TableCell
  newCell.Text = "一番上のヘッダ"
  newCell.RowSpan = 1
  newCell.ColumnSpan = 3   '3列にわたるセル
  newHeader.Cells.Add(newCell)
  DataGrid1.Controls(0).Controls.AddAt(0, newHeader)

  '保存したレコードよりグリッドを再編集する
  For i = 0 To tblTmp.Rows.Count - 1
   'テキストを編集
   Dim txtTmp As TextBox = DataGrid1.Items(i).FindControl("txtInput")
   If Not (txtTmp Is Nothing) Then
    txtTmp.Text = tblTmp.Rows(i).Item(0).ToString()
   End If

   'ドロップダウンを編集
   Dim ddlTmp As DropDownList = DataGrid1.Items(i).FindControl("ddlSelect")
   If Not (ddlTmp Is Nothing) Then
    'ドロップダウンの内容をクリア
    ddlTmp.Items.Clear()
    'ドロップダウンの内容を動的に編集
    ddlTmp.Items.Insert(0, New ListItem(i.ToString() & ":動的設定内容0", "0"))
    ddlTmp.Items.Insert(1, New ListItem(i.ToString() & ":動的設定内容1", "1"))
    ddlTmp.Items.Insert(2, New ListItem(i.ToString() & ":動的設定内容2", "2"))
    'ドロップダウンの選択状態をセット
    Dim lsiTmp As ListItem = ddlTmp.Items.FindByValue(tblTmp.Rows(i).Item(1).ToString())
    If Not (lsiTmp Is Nothing) Then
     ddlTmp.SelectedIndex = ddlTmp.Items.IndexOf(lsiTmp)
    Else
     ddlTmp.SelectedIndex = -1
    End If
   End If
  Next

 End Sub
End Class
_________________
todo
ぬし
会議室デビュー日: 2003/07/23
投稿数: 682
投稿日時: 2004-01-09 12:40
DataGrid1_ItemCreatedでやるのはどうでしょう。

private void DataGrid1_ItemCreated(object sender, DataGridItemEventArgs e)
{
  if (e.Item.ItemType == ListItemType.Header) {
    DataGrid1.Controls[0].Controls.AddAt(0, 新しいヘッダ行);
  }
}
まう
会議室デビュー日: 2004/01/09
投稿数: 2
お住まい・勤務地: 神奈川県
投稿日時: 2004-01-09 13:08
 todoさん、ありがとうございます。できました!

 最初はItemDataBoundイベントでヘッダ行の追加を書いたのですが、うまく動かないので、DataBind処理の直後に記述するようにしたんです。ItemCreatedイベントの方に書くのは気が付きませんでした。


 ちなみに、VBのコードでは以下の様に記述しました。

 Private Sub DataGrid1_ItemCreated(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DataGridItemEventArgs) Handles DataGrid1.ItemCreated
  If e.Item.ItemType = ListItemType.Header Then
   Dim newHeader As DataGridItem = New DataGridItem(-1, -1, ListItemType.Header)
   Dim newCell As TableCell = New TableCell
   newCell.Text = "一番上のヘッダ"
   newCell.RowSpan = 1
   newCell.ColumnSpan = 3   '3列にわたるセル
   newHeader.Cells.Add(newCell)
   DataGrid1.Controls(0).Controls.AddAt(0, newHeader)
  End If
 End Sub
1

スキルアップ/キャリアアップ(JOB@IT)