在一个页面中希望一个没有在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.
用Page_Load动态加载Trigger写的Page,Render 回来的Script. asyncPostBackControlIDs丢了。
相同的客户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);
}
}
问题终于比较好的解决了。
<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.
用Page_Load动态加载Trigger写的Page,Render 回来的Script. asyncPostBackControlIDs丢了。
相同的客户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);
}
}
问题终于比较好的解决了。