UpdatePanel中动态加入AsyncPostBackTrigger出现的问题

  在一个页面中希望一个没有在Update Panel中的Button或别的可以引发PostBack的控件提交一个异步AsyncPostBack。设置UpdatePanel的 ChildrenAsTriggers为False。设置AsyncPostBackTrigger为指定的控件。
<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional" ChildrenAsTriggers="false">
<ContentTemplate>
<%= DateTime.Now.ToLongTimeString() %>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="Button1" />
</Triggers>
</asp:UpdatePanel>
<asp:Button ID="Button1" runat="server" Text="Button" />
这段代码可以正常运行。可是这种写法不灵活,必须在设计时指定引发AsyncPostBackTrigger的控件。没有办法在运行时指定。后来在Page_Load中换成了下面的写法。想可以动态指定。
protected void Page_Load(object sender, EventArgs e)
{
AsyncPostBackTrigger trigger = new AsyncPostBackTrigger();
trigger.ControlID = this.Button1.ID;
this.UpdatePanel1.Triggers.Add(trigger);
}
这段代码虽然可以动态指定Trigger,可是第一次引发PostBack是一个无刷新的异步提交。可是第二次总是一个传统的提交。出现了问题。
ViewSource 看到Render回来的html几乎一模一样。都是使用Sys.WebForms.PageRequestManager._initialize (ScriptManager1, document.getElementById(form1));
Sys.WebForms.PageRequestManager.getInstance()._updateControls([fUpdatePanel1], [Button1], [], 90);
这样的方法来注册UpdatePanel和AsyncPostBack的Control。
可是第二种写法总是出错。估计是请求一次以后回来的Script搞出的问题。
用第一种设计时指定的方法Render回来的的Script。asyncPostBackControlIDs 为Button1.
Click to Open in New Window
用Page_Load动态加载Trigger写的Page,Render 回来的Script. asyncPostBackControlIDs丢了。
Click to Open in New Window
相同的客户javascript代码注册UpdatePanel和asyncPostBackControl第二办法出了问题。估计是服务器端 UpdatePanel的代码问题。可能是Asp.Net的LifeCycle引发的原因。反射UpdatePanel的方法:发现 UpdatePanel的OnLoad会调用Initialize()
Initialize() 这个internal virtual方法中调用自己triggers的Initialize()
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if (!base.DesignMode && !this.ScriptManager.IsInAsyncPostBack)
{
this.Initialize();
}
}
protected internal virtual void Initialize()
{
if ((this._triggers != null) && this.ScriptManager.SupportsPartialRendering)
{
this._triggers.Initialize();
}
}
AsyncPostBack的Initialize() 会注册自己到ScriptManager.RegisterAsyncPostBackControl中
protected internal override void Initialize()
{
base.Initialize();
this._associatedControl = base.FindTargetControl(true);
this.ScriptManager.RegisterAsyncPostBackControl(this._associatedControl);

}
是为了实现客户端代码Sys.WebForms.PageRequestManager.getInstance()._updateControls([fUpdatePanel1], [Button1], [], 90); Button1这个参数。
UpdatePanel 会在OnInit()中调用this.RegisterPanel();,这个方法会注册自己到ScriptManager.RegisterUpdatePanel
private void RegisterPanel()
{
if (!base.DesignMode && !this._panelRegistered)
{
for (Control parent = this.Parent; parent != null; parent = parent.Parent)
{
UpdatePanel panel = parent as UpdatePanel;
if (panel != null)
{
panel.RegisterPanel();
break;
}
}
this.ScriptManager.RegisterUpdatePanel(this);
this._panelRegistered = true;
}
}
就是客户端代码Sys.WebForms.PageRequestManager.getInstance()._updateControls ([fUpdatePanel1], [Button1], [], 90); fUpdatePanel1这个参数。
从Render回来的代码看。UpdatePanel1每次都成功的注册到ScriptManager的UpdatePanel中没有丢。但是Button1丢了。分析注册逻辑的代码,发现On_Load的调用过程可能导致注册出错:
if (!base.DesignMode && !this.ScriptManager.IsInAsyncPostBack)
{
this.Initialize();
}
要求不是DesignMode并且不是IsInAsyncPostBack。看来是这里的要求导致在第二次Page_Load时注册Button1失败了。幸好UpdatePanel 的Initialize()也会有一次注册的机会。把代码移到Page的OnInit中:
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
AsyncPostBackTrigger trigger = new AsyncPostBackTrigger();
trigger.ControlID = this.Button1.ID;
this.UpdatePanel1.Triggers.Add(trigger);
}
问题解决了。
可是在Page的OnInit时各个控件的状态还没有初始化,控件的LoadViewState() LoadPostData() 还没有被调用,各个控件的状态还不太对。不利于做逻辑处理决定是否添加这个UpdatePanel的Trigger。当Page OnInit后在Page的OnLoad时控件的状态才正确。所以还是需要在Page的Page_Load中写这段代码。需要在PageLoad时强行的为UpdatePanel1注册Button1。想尽一切办法调用一次UpdatePanel1的Initialize方法。
protected void Page_Load(object sender, EventArgs e)
{
AsyncPostBackTrigger trigger = new AsyncPostBackTrigger();
trigger.ControlID = this.Button1.ID;
this.UpdatePanel1.Triggers.Add(trigger);
if (this.ScriptManager1.IsInAsyncPostBack)
{
UpdatePanel1.GetType().GetMethod("Initialize", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(UpdatePanel1, null);
}
}
问题终于比较好的解决了。
将确认按钮加入 UpdatePanel 的触发器可能会导致上述错误的出现,这是因为确认按钮(通常是一个 input type="submit" 的控件)会触发整个页面的提交,而不是异步回发。 在 UpdatePanel 正确配置触发器非常重要,因为触发器决定了哪些控件的事件可以触发 UpdatePanel 的异步回发。如果将一个不支持异步回发的控件添加到触发器,就会导致整个页面的重新加载,而不是异步更新指定的内容,从而出现错误。 如果需要在点击确认按钮时触发 UpdatePanel 的异步回发,可以考虑使用以下方法: 1. 将确认按钮替换为一个普通的按钮,并使用 JavaScript 代码来触发异步回发。 例如: ```html <asp:UpdatePanel ID="UpdatePanel1" runat="server"> <Triggers> <asp:AsyncPostBackTrigger ControlID="Button1" EventName="Click" /> </Triggers> <ContentTemplate> <!-- UpdatePanel 的内容 --> </ContentTemplate> </asp:UpdatePanel> <asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" /> <input type="button" value="确认" onclick="doPostBack();" /> <script type="text/javascript"> function doPostBack() { __doPostBack('<%= UpdatePanel1.ClientID %>', ''); } </script> ``` 2. 使用 ASP.NET AJAX 的 UpdateProgress 控件,在异步回发时显示进度提示信息,避免用户误操作或多次提交。 例如: ```html <asp:UpdatePanel ID="UpdatePanel1" runat="server"> <Triggers> <asp:AsyncPostBackTrigger ControlID="Button1" EventName="Click" /> </Triggers> <ContentTemplate> <!-- UpdatePanel 的内容 --> </ContentTemplate> </asp:UpdatePanel> <asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" /> <asp:UpdateProgress ID="UpdateProgress1" runat="server" AssociatedUpdatePanelID="UpdatePanel1"> <ProgressTemplate> <!-- 进度提示信息 --> </ProgressTemplate> </asp:UpdateProgress> ``` 通过上述方法,可以避免将确认按钮加入触发器出现错误的问题
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值