リピーターまたは GridView での最初のクリックでItemCommandが起動しない
-
26-09-2019 - |
質問
この 2 日間、私は気が狂いそうになりました。誰かがこれを見たことがあるといいのですが。
リピーターまたはグリッドビュー内のコントロールの最初のクリックでItemCommandイベントが発生せず、その後のクリックはすべて機能するという問題が発生しています。コントロールは次のように Base.aspx のプレースホルダーに読み込まれます
private void LoadUserControl()
{
string controlPath = LastLoadedControl;
if (!string.IsNullOrEmpty(controlPath))
{
ph.Controls.Clear();
UserControl uc = (UserControl)LoadControl(controlPath);
ph.Controls.Add(uc);
}
}
これがビューステートの問題なのか、どのページ イベントで DataBind() を使用するべきなのか疑問に思っています。さまざまなページイベントでデータバインドを実験し、結果に変化がなくページとコントロールでビューステートを有効にしました。
これは GridView テンプレートですが、リピーター コントロールでも同じ動作をするため、このコントロールが問題であるとは思えません。
<ItemTemplate>
<asp:RadioButton ID="rbEnable" GroupName="MyGroup" runat="server" Text="Enabled" Checked="<%# ((EducateMe.BaseTypes.AbstractLink)Container.DataItem).IsActive == true %>" />
<asp:RadioButton ID="rbDisable" runat="server" GroupName="MyGroup" Text="Disabled" Checked="<%# ((EducateMe.BaseTypes.AbstractLink)Container.DataItem).IsActive != true %>" />
<asp:Button ID="btnEnable" runat="server" CommandArgument="<% # Container.DataItemIndex %>" CommandName="Enable" ToolTip="Enable" Text="Save" />
<asp:Button ID="btnDisable" runat="server" CommandArgument="<% # Container.DataItemIndex %>" Visible="false" CommandName="Disable" ToolTip="Disable" Text="Disable" />
</ItemTemplate>
関連する可能性のある追加情報:
私が気づいたのは、ユーザーコントロールの Page_Load イベントでコントロールを再バインドしていることです。おそらくコントロールの状態が書き換えられるため、これが原因ですが、ascx のこの領域に if(!IsPostback) を追加すると、このコード セクションは aspx ページの場合のようにまったく起動しません。それがコントロールを再バインドする正しいセクションだと思います。
解決
マイク・W
何時間もこれをいじった結果、問題の根本が見つかりました。
リピーターやグリッドビューとは特に関係ありません。
これは単にポストバック上の動的コントロールの問題です。
問題を解決するには:
驚くべきことに、コード内で欠落しているのは 1 行だけです。
コントロールをロードするときに、次のようにその ID に何かを割り当てます。
UserControl uc = (UserControl)LoadControl(controlPath);
uc.ID = "mycontrol";
ph.Controls.Add(uc);
こうすることで、ポストバック時に、ページはどのコントロールがどのコントロールであるかを認識します。
これをもっと簡単に説明するために、問題を単純化してみましょう。
次に、ボタンを 2 回続けてクリックして別のボタンを動的に作成するシナリオを示します。
- 単一のボタン Button1 を作成します。これをクリックすると、別のボタン Button2 が動的にロードされます。Button2 のアクションは現在時刻を表示するのと同じくらい単純であると仮定します。
- 次に、「Button1」をクリックします。
- Button2 を保持するには、次を利用する必要があります。
ViewState
ページに動的コントロールがあることを伝えます。あなたがやったように、コントロールのパス、またはそのクラスの名前を記憶することができます。 - ページがポストバックされた瞬間に、
Page_Load
, を見てみましょう。ViewState
保持しようとしているコントロールがあることを確認するため、それをそこにロードします (これは、LoadUserControl()
上記の関数)。 - ここまでで、Button2 が表示され、クリックすると正常に動作します。
- Button2 をクリックせずに、Button1 をもう一度クリックしてください (これは、2 つの異なる動的コントロールを切り替えることと同じです)。
- 今何が起こっているか推測してください:
Page_Load
Button2をからロードしますViewState
. 。そしてそのClick
Button1 のイベントは、プレースホルダーをクリアした後、別の Button2 インスタンスをロードします。 - ID を割り当てていないため、次の手順で ID が割り当てられます。
UniqueID
, 、これら 2 つの Button2 には次のようなものがあります。 ctl02 そして ctl03 - ここで「Button2」をクリックします。
- 「大丈夫です、古いものを上書きします」と言うでしょう。はい、ただし ID がなければできません。
- ポストバックで識別するための ID を与えていないため、
UniqueID
, 、順次生成されます。 - 今ページが探しているのは ctl03, 、それは存在しないので、
Click
発火しない。 - しかし、今では、まったく新しい Button2 ができています。
UniqueID
ctl02. - この新しい Button2 をクリックすると、ポストバックでは問題なく動作します。これは唯一の Button2 なので、偶然にも
UniqueID
の ctl02.
では、ID を割り当てるとどのように機能するのでしょうか?
こうすることで、生成された新しいコントロールはそれぞれ同じ ID を持つため、ポストバック時に、生成されたかどうかに関係なく、探しているものを見つけることができます。 Page_Load
または別のボタンで Click
イベント。
これで機能する理由が説明できれば幸いですが、気にする限り、ID を割り当てるだけで問題は解決します。
その背後にあるメカニズムと、なぜそうなるのかを共有するのは興味深いことだと思いました。=)
他のヒント
私はそれを考え出したが、私は理由を理解していない。
元のコードはでした:
Me.rpAgreementContractors.DataSource = dtContractors
Me.rpAgreementContractors.DataBind()
Me.tblAgreementContractors.Visible = True
Me.phDataPane.Controls.Add(Me.tblAgreementContractors)
私は、テーブルが表示されるように、それを変更し、私はデータソースを設定し、それをバインドする前に、プレースホルダに追加します。問題が解決します。
Me.tblAgreementContractors.Visible = True
Me.phDataPane.Controls.Add(Me.tblAgreementContractors)
Me.rpAgreementContractors.DataSource = dtContractors
Me.rpAgreementContractors.DataBind()
私はあなたのコードの残りの部分についてはわからないんだけど、私が見たときに、私はIsPostBack
セクションの間違った側に何かを置いているため、通常はこのような「後続のアクションとは異なる最初のアクションの振る舞い」の問題があります。
例えば、私は彼らが生まれたとき、最初のポストバックであり、初期ページのロードがその部分をやったことはありませんだって私のイベントは、第二ポストバックまで仕事をしませんので、それは、ポストバックだとき自分が結合見つけます。
私はあなたが正しい軌道に乗っていると思います。あなたが適切なタイミングであなたのイベントを結合し、アップ配線しています。
作ります