ユーザーが必要な数のセカンダリ電話フィールドを動的に生成したいユーザーフォームに取り組んでいます(ボタンクリックイベント時)。このページでダニエルの動的コントロールのインスタンス化をたどりました:データベースを使用せずに動的 ASP.NET ユーザー コントロールを再インスタンス化するにはどうすればよいですか?
このページで lordscarlet によって提案された「イベント バブリング」ソリューションも実装しました: ascx usercontrols でのイベント処理
私の user.aspx ページの関連部分:
<asp:Panel ID="phonePnl" runat="server"></asp:Panel>
<tr><td><asp:Button ID="phoneBtn" Text="Add Secondary Phone" OnClick="phoneBtn_Click" runat="server" /></td></tr>
user.aspx.cs CodeBehind の関連部分
// ============================================================================
protected void phoneBtn_Click(object sender, EventArgs e)
{
UserControl controlToAdd = new UserControl();
controlToAdd = (UserControl)controlToAdd.LoadControl("~/DynamicData/FieldTemplates/SecondaryPhone.ascx");
controlToAdd.ID = Guid.NewGuid().ToString();
Panel phonePnl = (Panel)fvUser.FindControl("phonePnl");
Literal lit = new Literal();
lit.Text = "<tr><td>Secondary Phone</td><td>";
phonePnl.Controls.Add(lit);
phonePnl.Controls.Add(controlToAdd);
lit = new Literal();
lit.Text = "</td></tr>";
phonePnl.Controls.Add(lit);
myControlList.Add(controlToAdd.ID, controlToAdd.AppRelativeVirtualPath);
Session["myControlList"] = myControlList;
}
// ============================================================================
protected override void OnInit(EventArgs e)
{
InitializeComponent();
if (!IsPostBack)
{
myControlList = new Dictionary<string, string>();
Session["myControlList"] = myControlList;
}
else
{
myControlList = (Dictionary<string, string>)Session["myControlList"];
foreach (var registeredControlId in myControlList.Keys)
{
UserControl controlToAdd = new UserControl();
controlToAdd = (UserControl)controlToAdd.LoadControl(myControlList[registeredControlId]);
Panel phonePnl = new Panel();
phonePnl = (Panel)fvUser.FindControl("phonePnl");
phonePnl.Controls.Add(controlToAdd);
}
}
base.OnInit(e);
}
// ============================================================================
private void InitializeComponent()
{
this.Load += new System.EventHandler(this.Page_Load);
SecondaryPhoneControl.BubbleClick += new EventHandler(admin_user_BubbleClick);
}
// ============================================================================
private void admin_user_BubbleClick(object sender, EventArgs e)
{
//todo
}
最後の行を追加したことに注意してください:
Session["myControlList"] = myControlList;
また、fvUser は、user.aspx ページの FormView ID にすぎません。
ダニエルのソリューションにはありませんでしたが、私の考えでは、追加するコントロールごとに、それを辞書に追加する必要があります。私はこれで完全に見当違いですか?
私のユーザー コントロールは、TextBox と Button を持つ ascx です (ユーザーがそのフィールドを必要としない場合は、コントロールを削除します)。この削除はまだ実際には実装されていませんが、この問題が解決された後、親の分離コードにイベントが存在することに注意してください。
セカンダリ電話.ascx
<%@ Control Language="C#" CodeBehind="SecondaryPhone.ascx.cs" Inherits="TwentyFourSeven.DynamicData.FieldTemplates.SecondaryPhone" %>
セカンダリフォン.ascx.cs
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Collections.Specialized;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Xml.Linq;
using System.Web.DynamicData;
namespace TwentyFourSeven.DynamicData.FieldTemplates
{
public partial class SecondaryPhone : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
}
public void SetPhone(String phone)
{
secPhoneTxt.Text = phone;
}
protected override void LoadViewState(object savedState)
{
base.LoadViewState(savedState);
secPhoneTxt.Text = (String)ViewState["secPhoneTxt"];
}
protected override object SaveViewState()
{
ViewState["secPhoneTxt"] = secPhoneTxt.Text;
return base.SaveViewState();
}
private void secPhoneBtn_Click(object sender, EventArgs e)
{
}
public event EventHandler BubbleClick;
protected void OnBubbleClick(EventArgs e)
{
if (BubbleClick != null)
{
BubbleClick(this, e);
}
}
protected override void OnInit(EventArgs e)
{
InitializeComponent();
base.OnInit(e);
}
private void InitializeComponent()
{
this.secPhoneBtn.Click += new System.EventHandler(this.secPhoneBtn_Click);
this.Load += new System.EventHandler(this.Page_Load);
}
}
}
デバッグ時、ページが最初にロードされたときに OnInit が正しく機能し、[セカンダリ電話を追加] ボタンをクリックすると最初のクリックで機能します。2 回目のクリックで、OnInit メソッドの次の行で Null 参照例外 (オブジェクト参照がオブジェクトのインスタンスに設定されていません) がスローされます。
phonePnl.Controls.Add(controlToAdd);
デバッグ中に、ボタンの最初のクリックで、私の phoneBtn_Click メソッドで、controlToAdd.Application、controlToAdd.Cache なども Null 参照例外をスローすることに気付きましたが、それでもコントロールを生成してページを返します。また、コントロールとその ID をディクショナリに追加します。
次に、ボタンの 2 回目のクリックで、例外の原因となる行に到達する直前に、phonePnl 変数が null になります。これが例外の原因であると推測できますが、この場合、 phonePnl 変数が null であり、2 回目の OnInit 呼び出し/最初のポストバックではないのはなぜですか?
私は一日中これに頭を悩ませてきました。誰かが洞察を提供してくれることを願っています。