我有一个页面(company.aspx),当您单击页面上的按钮时,按钮单击事件(btnShowDeptsUserControl_click)会动态创建一个用户控件并添加到占位符中。页面将重新加载并显示用户控件。这很好。
我遇到的问题是,当我单击用户控件本身上的按钮时,btnEmailDepts_click事件不会触发,但会重新加载主页(company.aspx)。
我读到解决这个问题的一种方法是在Page_Init中创建动态用户控件,但我是通过单击主页按钮来创建用户控件的。此外,我并没有像通常那样在主页面的代码后面声明用户控件,而是有一个添加用户控件的占位符。
我也读到过,你可以在主页面上添加一个委托来点击用户控制按钮,但这个例子似乎有太多必要的代码来完成这么简单的事情,我认为一定有更好的方法。
以下是相关的代码片段:
company.aspx:
<asp:Button id="btnShowDeptsUserControl" runat="server" OnClick="btnShowDeptsUserControl_Click">Show Depts</asp:Button>
<asp:PlaceHolder ID="phUserControls" runat="server"></asp:PlaceHolder>
company.aspx.cs:
protected void btnShowDeptsUserControl_Click(object sender, EventArgs e)
{
CreateDeptsUserControl();
}
private void CreateDeptsUserControl()
{
phUserControls.Controls.Clear();
var uc = (UserControl)LoadControl("~/controls/ucDepartments.ascx");
phUserControls.Controls.Add(uc);
}
ucDepartments.ascx:
<asp:Button ID="btnEmailDepts" runat="server" Text="Send Email" OnClick="btnEmailDepts_Click" />
ucDepartments.ascx.cs:
protected void btnEmailDepts_Click(object sender, EventArgs e)
{
EmailDepts(); // breakpoint here is never hit
}
private void EmailDepts()
{
// do something
}
如果你阅读MSDN,你会注意到:
但是,添加的控件无法赶上回发数据处理。为了使添加的控件参与回发数据处理(包括验证),必须在Init事件中而不是在Load事件中添加该控件。
您正在click
事件中添加控件,该事件发生在init
和load
事件之后,因此回发将不起作用。
您可以在ini
事件中调用CreateDeptsUserControl
函数,但在那里您必须检测btnShowDeptsUserControl
是否是自己单击的。这并不难,您需要检查提交的值集合,看看是否有btnShowDeptsUserControl
的项。
我只是想发布我所做的工作。Racil Hilan的回答帮助我找到了这个解决方案。我去掉了动态用户控件,使用了aspx中更常见的声明用户控件,但默认情况下将其设置为Visible="False"。
请注意,主页按钮事件为空。还要注意,用户控件Page_Load事件为空。所有检查都在用户控件OnInit事件中完成,该事件在每次主页加载时执行。
在用户控件OnInit事件中,我有两个保护条件,用于检查是什么EVENTTARGET(如果有的话)导致页面/用户控件加载。如果EVENTTARGET(控件ID)是主页按钮的ID,则执行将继续,并将调用LoadSomeData()以及设置用户控件Visible=true。否则,如果任一保护条件的计算结果为false,我们将退出,并且不会加载用户控件,因此不会浪费db/service调用。
company.aspx:
<asp:Button id="btnShowDeptsUserControl" runat="server" OnClick="btnShowDeptsUserControl_Click">Show Depts</asp:Button>
<uc1:ucDepartments ID="ucDepartments" runat="server" Visible="False" />
company.aspx.cs:
protected void btnShowDeptsUserControl_Click(object sender, EventArgs e)
{
// empty, just need the event for inspection later in user control OnInit event.
}
ucDepartments.ascx:
<asp:Button ID="btnEmailDepts" runat="server" Text="Send Email" OnClick="btnEmailDepts_Click" />
ucDepartments.ascx.cs:
protected override void OnInit(EventArgs e)
{
if (string.IsNullOrWhiteSpace(Request.Params["__EVENTTARGET"]))
return;
var controlName = Request.Params["__EVENTTARGET"];
if (controlName != "btnShowDeptsUserControl")
return;
LoadSomeData(); // call method to load the user control
this.Visible = true;
}
protected void Page_Load(object sender, EventArgs e)
{
// empty
}
private void LoadSomeData()
{
// get data from database
// load table / gridview / etc
// make service call
}
protected void btnEmailDepts_Click(object sender, EventArgs e)
{
EmailDepts(); // this event is now executed when the button is clicked
}
private void EmailDepts()
{
// do something
}
包含jquery以在回发后滚动到用户控件的变体:
在主页按钮点击事件中,你还可以做一些事情,比如将一个隐藏的var设置为一个可以在主页上检查的值,准备做一些jquery的事情,比如如果用户控件在页面下方,将其滚动到视图中(我在当前任务中实际正在做这件事)。
这不仅会在单击主页按钮后将现在加载的用户控件滚动到视图中,还会注意setupDepts()中的代码。我隐藏了执行回发以加载用户控件的asp按钮,并显示了一个常规的html按钮。它们看起来都一样(都说ShowDepts),但普通的html按钮在单击时会触发jquery,将包含用户控件的div切换为关闭,再次单击,它将打开,再次单击它将关闭,等等。
这样,当单击主页按钮时,您只加载一次用户控件(进行一次db/service调用),然后可以在随后单击备用按钮时切换显示或隐藏它。这种方法可以用于多个按钮或链接,只要它们都具有相同的类ID。例如,您可能在页面顶部有一个"显示Depts"按钮/链接,在页面底部有另一个,这就是我当前任务中的情况。
company.aspx:
<asp:Button id="btnShowDeptsUserControl" runat="server" class="btnShowDepts" OnClick="btnShowDeptsUserControl_Click">Show Depts</asp:Button>
<button class="btnToggleDepts" style="display: none;">Show Depts</button>
<div id="divShowDepts" style="display: none;">
<asp:HiddenField runat="server" id="hdnShowDepts"/>
<uc1:ucDepartments ID="ucDepartments" runat="server" Visible="False" />
</div>
<script language="javascript" type="text/javascript">
$(function () {
toggleDeptsUserControl();
if ($('#<%=hdnShowDepts.ClientID%>').val() === "show")
setupDepts();
});
function setupDepts() {
$('.btnShowDeptsUserControl').hide();
$('.btnToggleDeptsUserControl').show();
scrollToDepts();
}
function scrollToDepts() {
$('#divShowDepts').toggle(700, function () {
if ($(this).is(":visible")) {
$('html, body').animate({ scrollTop: ($(this).offset().top) }, 'slow');
}
});
}
function toggleDeptsUserControl() {
$('.btnToggleDeptsUserControl').on('click', function (event) {
event.preventDefault();
scrollToDepts();
});
}
</script>
company.aspx.cs:
protected void btnShowDeptsUserControl_Click(object sender, EventArgs e)
{
hdnShowDepts.Value = "show";
}