- PR -

【再投稿】MasterPageを使用したページでGridViewのSelectedIndexChangedイベントが捕捉出来ない。

1
投稿者投稿内容
matrix
会議室デビュー日: 2008/07/13
投稿数: 15
投稿日時: 2009-02-24 23:01
MasterPageを使用したページでGridViewのSelectedIndexChangedイベントが捕らえられない。

前回の投稿では大変失礼しました。
質問文を再編集して自分なりにわかり易くしたつもりです。
改めまして賢者の皆様宜しくお願い申し上げます。

【何をしようとしているか?】
GridViewとselect SQL文のstringを引数で渡し、SQLの結果をGridViewに表示するクラス群を作成しました。
例として「select 種類, メーカー from CAR」の結果を以下の様にGridViewで表示するものです。
このGridViewは参照用で編集機能は設けていません。
またGridViewの任意の行をクリックすると、その行の各カラム値をCSV形式の文字列で返すクラスも用意しています。
尚、GridViewの行選択機能を実装するため、下図のGridViewの@SelectButtonを設けますが非表示にしています。
行選択機能とは下図のA、B何れのカラムをクリックしても、何位行目がクリックしたか判別できる事です。

     @      A       B
    |種類        |メーカー  |
-------------------------------
選択 |スポーツカー    |フェラーリ |
選択 |ファミリーカー   |ホンダ   |

ShowSelectButton = true;
GridViewRowEventArgs e.Row.Cells[0].Style.Add("display", "none");(非表示にします)

【行選択機能の実装方法】
下記のクラスでGridViewの選択ボタンを非表示にし、行をClickされたらJavaScriptを実行するよう設定しています。(SelectedRow)

public void HideSelectButton(ref GridView vGridView, GridViewRowEventArgs e)
{
//選択ボタンセルを非表示にする(Visible = False だと選択ボタン押下を裏で制御ができないため)
if (e.Row.RowType != DataControlRowType.Pager)
{
e.Row.Cells[0].Style.Add("display", "none");
}

//データ行ではない場合は、何もしない
if (e.Row.RowType != DataControlRowType.DataRow)
{
return;
}

//行をClickされた場合、JavaScriptを実行するよう設定する
string clickEvent = String.Format("SelectedRow('{0}', '{1}')", e.Row.RowIndex, vGridView.ClientID);
e.Row.Attributes.Add("onClick", clickEvent);

【何が出来ないのか?】
前述の機能実装でGridViewの行選択を「SelectedIndexChangedイベント」で拾うわけですが、掲題のとおりMasterPageを使用したフォームでは「SelectedIndexChangedイベント」が捕らえられません。

【生成されたhtml(抜粋)は以下のとおりです。】
-------------------------------------------------------------------------------
(1)自動生成されたPostBack関数(これはMasterPageあり/なしにかかわらず同じです)

function __doPostBack(eventTarget, eventArgument) {
if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
theForm.__EVENTTARGET.value = eventTarget;
theForm.__EVENTARGUMENT.value = eventArgument;
theForm.submit();
}

-------------------------------------------------------------------------------
(2)MasterPageありのページでのGridViewから生成されたtable
下の(3)と異なり「id="ctl00_ContentPlaceHolder1_GridView1"」となってしまいます。
明らかにこのあたりが怪しいです。

<table cellspacing="0" rules="all" border="1" id="ctl00_ContentPlaceHolder1_GridView1" style="border-collapse:collapse;">
<tr>
<th scope="col" style="display:none;">選択</th><th scope="col">種類</th><th scope="col">メーカー</th>
</tr><tr onClick="SelectedRow('0', 'ctl00_ContentPlaceHolder1_GridView1')" style="cursor:hand;">
<td style="display:none;"><a href="javascript:__doPostBack('ctl00$ContentPlaceHolder1$GridView1','Select$0')">選択</a></td><td>スポーツカー</td><td>フェラーリ</td>
</tr><tr onClick="SelectedRow('1', 'ctl00_ContentPlaceHolder1_GridView1')" style="cursor:hand;">
<td style="display:none;"><a href="javascript:__doPostBack('ctl00$ContentPlaceHolder1$GridView1','Select$1')">選択</a></td><td>ファミリーカー</td><td>ホンダ</td>
</tr>
</table>

-------------------------------------------------------------------------------
(3)MasterPageなしのページでのGridViewから生成されたtable

<table cellspacing="0" rules="all" border="1" id="GridView1" style="border-collapse:collapse;">
<tr>
<th scope="col" style="display:none;">選択</th><th scope="col">掲示板名</th>
</tr><tr onClick="SelectedRow('0', 'GridView1')" style="cursor:hand;">
<td style="display:none;"><a href="javascript:__doPostBack('GridView1','Select$0')">選択</a></td><td style="font-family:MS ゴシック;">スポーツカー掲示板</td>
</tr><tr onClick="SelectedRow('1', 'GridView1')" style="cursor:hand;">
<td style="display:none;"><a href="javascript:__doPostBack('GridView1','Select$1')">選択</a></td><td style="font-family:MS ゴシック;">クラッシクカー掲示板</td>
</tr>
</table>

(4)GridViewがクリックされたときにcallされるスクリプト。(これはMasterPageあり/なしにかかわらず同じです)
<!--------------------------------------------------------------------->
<!-- GridViewで行選択された時のスクリプト -->
<!--------------------------------------------------------------------->
<script type="text/javascript" language="javascript">
function SelectedRow(rowNum, gridViewId)
{
__doPostBack(gridViewId, 'Select$' + rowNum);
}
</script>
<!--------------------------------------------------------------------->

以上です。
宜しくお願いします。
ぴあちゃん
ぬし
会議室デビュー日: 2008/02/07
投稿数: 287
投稿日時: 2009-02-25 01:38
プレースホルダーの中のますたーページを継承するページのグリッドビュー
とマスターページ上のグリッドビューはどちらも、GridView1じゃ
ないんですかね?

なんで、プレースホルダーの中のグリッドビューのIDが長くなるのは、
展開した時にIDを一意にするための工夫ですのでなんら問題ないのでは?

同様に、マスターページ中にプレースホルダーを2つに増やし、コンテンツ
ページを2つそれぞれのプレースホルダーに配置させたとしても、3つの
グリッドビューはそれぞれのページ単体で見れば、名前は全部GridView1
だと思いますね。

ctl00_contentplaceholder1_gridview1
ctl00_contentplaceholder2_gridview1
gridview1

になります。たぶん。

追記:
コンテンツページは自分のプレースホルダーが何であるかは関係ないです。

追記:
なんで、アンカーに選択ボタンのスクリプトがありますよね?
rowClicked() を実装するとしたら、
function rowClicked() {
event.srcElement.firstChild.getElementsByTagName("a")[0].click();
}
こうしないと動かないかと。

追記:
rowChanged イベントではなくて、選択ボタンのクリックイベントをハンドリング
してくださいね。


[ メッセージ編集済み 編集者: ぴあちゃん 編集日時 2009-02-25 01:49 ]

[ メッセージ編集済み 編集者: ぴあちゃん 編集日時 2009-02-25 01:53 ]

[ メッセージ編集済み 編集者: ぴあちゃん 編集日時 2009-02-25 01:57 ]
デューン
大ベテラン
会議室デビュー日: 2004/04/21
投稿数: 174
お住まい・勤務地: Tokyo
投稿日時: 2009-02-25 01:53
ざっと見た感じ、ClientIDではなくて、UniqueIDじゃないですか?

ClientID → 'ctl00_ContentPlaceHolder1_GridView1'
UniqueID → 'ctl00$ContentPlaceHolder1$GridView1'


# 前の投稿のときにrainさんが同じ事を回答されていたようですね。

[ メッセージ編集済み 編集者: デューン 編集日時 2009-02-25 02:20 ]
matrix
会議室デビュー日: 2008/07/13
投稿数: 15
投稿日時: 2009-02-25 10:35
ぴあちゃんさん、デューンさん、ありがとうございます。
残念ながらお二人のご回答は私の知らない要素ばかりで消化できません。
したがいまして、何をどうしたら良いのかわかりません。
MasterPageはサイトのページのデザインを統一すためのものと思っていましたが、MasterPageありと無しでは色々と差別を考慮しないといけない事だけは解りました。
ぴあちゃんさん、デューンさんのご回答を元に勉強したいと思います。
デューン
大ベテラン
会議室デビュー日: 2004/04/21
投稿数: 174
お住まい・勤務地: Tokyo
投稿日時: 2009-02-25 11:10
直そうとしているコードは自分で書いたものじゃないのですか?

引用:

//行をClickされた場合、JavaScriptを実行するよう設定する
string clickEvent = String.Format("SelectedRow('{0}', '{1}')", e.Row.RowIndex, vGridView.ClientID);
e.Row.Attributes.Add("onClick", clickEvent);



これによって生成されるのは
引用:

(2)MasterPageありのページでのGridViewから生成されたtable


のなかから抜粋すると

onClick="SelectedRow('1', 'ctl00_ContentPlaceHolder1_GridView1')"

のような部分です。
これはjavascriptでSelectedRow関数によって最終的に

__doPostBack('ctl00_ContentPlaceHolder1_GridView1', 'Select$1')

が実行されるようにできています。

---
ところが、ASP.NETが自動で作った選択ボタンは

<a href="javascript:__doPostBack('ctl00$ContentPlaceHolder1$GridView1','Select$1')">選択</a>

で、javascriptだけ抜き出せば

__doPostBack('ctl00$ContentPlaceHolder1$GridView1','Select$1')

です。

--
並べると

__doPostBack('ctl00_ContentPlaceHolder1_GridView1', 'Select$1')
__doPostBack('ctl00$ContentPlaceHolder1$GridView1', 'Select$1')


違いますよね?

IDが間違ってますのでイベントは発生しません。
つまりIDのとり方が間違っているのではないか。ということになります。


# 脱字修正

[ メッセージ編集済み 編集者: デューン 編集日時 2009-02-25 11:24 ]
rain
ぬし
会議室デビュー日: 2006/10/19
投稿数: 549
投稿日時: 2009-02-25 11:10
引用:

matrixさんの書き込み (2009-02-25 10:35) より:
ぴあちゃんさん、デューンさん、ありがとうございます。
残念ながらお二人のご回答は私の知らない要素ばかりで消化できません。
したがいまして、何をどうしたら良いのかわかりません。
MasterPageはサイトのページのデザインを統一すためのものと思っていましたが、MasterPageありと無しでは色々と差別を考慮しないといけない事だけは解りました。
ぴあちゃんさん、デューンさんのご回答を元に勉強したいと思います。



まずは、どうしてうまくいかないかの原因を調べることです。
行をクリックして、JavaScript が動いて、ポストバックが発生して、SelectedIndexChanged イベントが発生するという(おおざっぱな)流れがあるわけですが、その中のどこまでうまくいっていて、どこからうまくいかなくなっているのかを特定しましょう。

そうすれば、回答の意味がわかると思います。
matrix
会議室デビュー日: 2008/07/13
投稿数: 15
投稿日時: 2009-02-26 14:57
rainさん、デューンさん、白旗を揚げたにもかかわらずコメント頂き誠にありがとうございます。
出張していたためお礼が遅くなりました。

さて、本件の不具合ですが、おかげさまで動作するようになりました。
具体的な解決は以下の通りです。
string clickEvent = String.Format("SelectedRow('{0}', '{1}')", e.Row.RowIndex, vGridView.ClientID);

string clickEvent = String.Format("SelectedRow('{0}', '{1}')", e.Row.RowIndex, vGridView.UniqueID);

ClientIDをUniqueIDにする事で解決しました。

今回の質問でのソースコードはご想像通り私が書いたものではなくネットで拾ったものです。
コードはおおよそ理解したつもりでいましたが安易に質問しました事、反省しております。
HTML,JS,C#は今年に入ってから勉強を始めたばかりです。
本業ではコードを書くことは少ないのですが、コードをイメージが出来ないシステムを設計するのは経験上、後々困る事になることは目に見えているため勉強中です。
rainさん、デューンさん他、この会議室に回答しておられる方々の鋭さには感嘆します。
あらためまして、本件のぐちゃぐちゃな質問文を見て頂き、またご回答をいただきました事、誠にありがとうございました。
1

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