[asp.net]Application对象与PageRequestManager对象的事件顺序

本文详细介绍了ASP.NET AJAX中Sys.Application与PageRequestManager对象的事件处理机制,包括init、load、endRequest等事件的触发时机及处理方法。还探讨了如何在客户端捕获并处理服务端异常。

转自:http://www.windysky.com.cn/blog/html/389/

 

个Application对象,指的不是服务端的Application对象,而是由ScriptManager控件生成的客户端脚本中,Sys对象的 Application对象。它的完整名称为Sys.Application。PageRequestManager对象的完整名称为 Sys.WebForms.PageRequestManager。

  Application对象包含init事件和load事件,其 中init事件只有在页面第一次加载以后才会发生,而load事件在客户端获得Ajax请求回发的时候,也会发生。两个事件的的处理,可以通过 Sys.Application.add_init(handler)和Sys.Application.add_load(handler)来添加处理 程序,其中handler是你的事件处理程序。该对象的另外两个事件,disposing和unload,可以通过add_disposing和 add_unload两个函数添加。关于这两个事件的作用,请看后面。

  PageRequestManager对象包含 initializeRequest、beginRequest、pageLoading、pageLoaded、endRequest等事件。 PageRequestManager对象的事件比较特殊,不能直接添加处理程序,而是要先通过调用 Sys.WebForms.PageRequestManager.getInstance()获取该对象的实例,然后才能添加事件处理程序。

   假设我有一个变量instance,该变量保存了PageRequestManager对象的实例,然后可以通过以下方法添加事件处理程 序:instance.add_initializeRequest(handler)、 instance.add_beginRequest(handler)、instance.add_pageLoading(handler)、 instance.add_pageLoaded(handler)、instance.add_endRequest(handler)。其中 handler是你的事件处理程序。

  在页面加载的,无论是第一次加载还是Ajax请求,都会发生PageRequestManager对象的所有事件。只是页面第一次加载的时候,PageRequestManager对象都还没生成,所以页 面第一次加载的时候,我们唯一能处理的属于该对象的事件是endRequest,该事件也是我们所能处理的第一个事件。然后就是Application对 象的init与load两个事件,他们的顺序如下:PageRequestManager.endRequest、Application.init、 Application.load。Application的disposing与unload两个事件,是发生在我们离开页面的时候。当 我们离开页面时,无论是点击超链接还是用脚本改变location还是刷新页面,就算关闭窗体,都会触发这两个事件。两个事件的发生顺序如 下:Application.unload、Application.disposing。其中,disposing事件是我们能处理的最后一个事件。

  当 我们在页面中使用了微软Ajax扩展中的UpdatePanel控件时,当页面部分回发时,会触发PageRequestManager对象的所有事件及 Application对象的load事件,他们的顺序如下:PageRequestManager.initializeRequest、 PageRequestManager.beginRequest、PageRequestManager.pageLoading、 PageRequestManager.pageLoaded、Application.load、 PageRequestManager.endRequest。

  当我们在含有UpdatePanel控件的页面中,进行两次部分页回发的时候,上述两个对象的事件中,只会处理一次。例如,两次回发分别为a和b,事件的顺序如下:

引用
PageRequestManager.initializeRequest  //a请求
PageRequestManager.beginRequest  //a请求
PageRequestManager.initializeRequest  //b请求
PageRequestManager.endRequest  //a请求
PageRequestManager.beginRequest  //b请求
PageRequestManager.pageLoading  //b请求
PageRequestManager.pageLoaded  //b请求
Application.load  //b请求
PageRequestManager.endRequest  //b请求



需要注意的地方是,虽然此时a请求被强制结束了,但服务端还是会处理a请求的,并返回结果的。只是a请求的返回结果,客户端不再处理而已。

   在PageRequestManager.endRequest事件中,我们可以处理服务端未处理的Exception。通过参数(这些事件的处理程序 都像服务端事件一样,包含两个参数,一个是sender,一个是args。如:endRequestHandler(sender, args))args,我们可以调用args.get_error()来获取错误处理对象。通过判断该对象是否为undefined就知道服务端是否发生 错误了。通过调用args.get_error().message可以获取服务端错误信息。手动处理完错误信息后,可以调用 args.set_errorHandled(true)来禁止默认的错误处理程序(默认是把错误通过alert()显示出来)。

  还有一个地方是需要注意的,用UpdatePanel进行Ajax回发的时候,也会触发服务端Page_Load事件,就像普通的页面回发一样,此时Page.IsPostback的值为True。

<think>我们正在处理一个关于.NET框架Web Form页面的问题。用户使用了editBytiny(可能指的是TinyMCE编辑器)来编辑内容,并将数据保存到数据库,但在保存后页面不显示编辑框以及已保存的数据。 根据用户描述,问题发生在保存数据到数据库之后,页面没有正确显示编辑器已保存的数据。 我们需要考虑以下几个方面: 1. 数据是否成功保存到数据库?需要确认保存操作是否成功执行。 2. 页面在回发(PostBack)后,是否重新绑定了数据?即,是否从数据库重新加载了数据并设置到编辑器? 3. 编辑框(TinyMCE)的初始化是否正确?特别是在回发后,是否重新初始化了编辑器? 4. 页面加载时,是否根据不同的PostBack状态执行了正确的操作? 由于是Web Form,我们还要注意ViewState页面生命周期。 步骤建议: 1. 确保保存操作后,从数据库重新获取数据并绑定到页面控件。 2. 在页面加载事件(Page_Load)中,区分首次加载回发。在回发时,可能不需要重新绑定数据(除非必要),但保存操作后需要重新绑定。 3. 对于TinyMCE编辑器,需要确保在回发后,编辑器重新初始化,并且内容被正确设置。 可能的原因及解决方案: - 原因1:保存操作后,页面重定向到自身(或其他页面),但没有重新加载数据。 解决方案:在保存按钮的点击事件处理程序中,保存数据后,立即从数据库获取最新数据并绑定到编辑器。 - 原因2:TinyMCE编辑器在回发后没有重新初始化,导致编辑器区域变为普通文本区域。 解决方案:确保在每次页面加载(包括回发)后,都初始化TinyMCE编辑器。注意,如果页面有更新面板(UpdatePanel),则需要在异步回发后重新初始化编辑器。 - 原因3:数据绑定时机不对。可能在Page_Load中绑定数据,但保存操作发生在Page_Load之后,导致保存后的新数据没有在本次回发中显示。 解决方案:在保存按钮的点击事件处理程序中,保存数据后,立即将新数据设置到编辑器控件(或绑定的字段),并确保编辑器初始化脚本在页面中执行。 具体操作步骤: 1. 在保存按钮的点击事件中,保存数据到数据库后,立即重新从数据库获取该数据,并赋值给编辑器所在的控件(比如一个TextBox)。 2. 确保在Page_Load中,如果是回发,不要重新绑定数据(避免覆盖用户输入),但我们在保存后已经重新赋值,所以通常Page_Load中我们只在首次加载时绑定数据。 但是,如果保存后需要刷新页面上的其他数据,则可能需要重新绑定。 3. 初始化TinyMCE的脚本应该在每次页面加载时都执行(包括回发)。可以将初始化脚本放在一个UpdatePanel中,或者使用ScriptManager在回发后注册启动脚本。 示例代码结构: 在Web Form的.aspx页面中,放置一个TextBox用于编辑器内容,并将其设置为多行文本: ```aspx <asp:TextBox ID="txtContent" runat="server" TextMode="MultiLine" Rows="10" Columns="80"></asp:TextBox> ``` 在页面底部,引入TinyMCE并初始化(注意:TinyMCE的初始化应该在该TextBox控件之后): ```html <script src="//cdn.tiny.cloud/1/your-api-key/tinymce/5/tinymce.min.js"></script> <script> tinymce.init({ selector: '#<%= txtContent.ClientID %>', // 其他配置 }); </script> ``` 但是,在回发后,如果整个页面重新加载,那么TinyMCE会重新初始化。但是,如果我们在保存后只更新部分页面(如UpdatePanel),则需要在异步回发后重新初始化。 如果使用UpdatePanel,可以在异步回发完成后重新初始化TinyMCE: ```aspx <asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager> <asp:UpdatePanel ID="UpdatePanel1" runat="server"> <ContentTemplate> <asp:TextBox ID="txtContent" runat="server" TextMode="MultiLine" Rows="10" Columns="80"></asp:TextBox> <asp:Button ID="btnSave" runat="server" Text="Save" OnClick="btnSave_Click" /> </ContentTemplate> </asp:UpdatePanel> ``` 然后在Page_Load中注册一个启动脚本(仅在回发时)来重新初始化编辑器,或者使用以下方式: ```csharp protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { // 首次加载:从数据库加载数据并设置到txtContent txtContent.Text = GetContentFromDB(); } else { // 如果是回发,确保TinyMCE重新初始化 // 由于UpdatePanel异步回发,我们需要在回发后重新初始化TinyMCE ScriptManager.RegisterStartupScript(this, GetType(), "ReinitTinyMCE", "tinymce.init({selector:'#" + txtContent.ClientID + "'});", true); } } ``` 但是,上面的重新初始化脚本可能会重复初始化,导致问题。更好的做法是在每次异步回发后,先移除旧的TinyMCE实例,再重新初始化。或者,TinyMCE提供了重新初始化的方法,但通常我们销毁再重建。 实际上,TinyMCE在异步更新后,如果该编辑器所在的DOM元素被更新,那么我们需要先销毁旧的编辑器实例,再重新初始化。 因此,在异步回发前,我们应该销毁编辑器实例(在UpdatePanel的异步回发开始前),然后在回发结束后再初始化。 我们可以使用PageRequestManager来注册异步回发开始结束的客户端事件: ```javascript var prm = Sys.WebForms.PageRequestManager.getInstance(); prm.add_beginRequest(BeginRequestHandler); prm.add_endRequest(EndRequestHandler); function BeginRequestHandler(sender, args) { // 获取当前编辑器实例并移除 var editor = tinymce.get('<%= txtContent.ClientID %>'); if (editor) { editor.remove(); } } function EndRequestHandler(sender, args) { // 重新初始化编辑器 tinymce.init({ selector: '#<%= txtContent.ClientID %>', // 其他配置 }); } ``` 这样,每次异步回发后,编辑器都会被重新初始化。 4. 保存操作(btnSave_Click)的代码示例: ```csharp protected void btnSave_Click(object sender, EventArgs e) { // 获取编辑器内容(注意:由于TinyMCE,文本框的内容在回发时可能不会自动更新,因为TinyMCE是客户端编辑器) // 我们需要在保存前,确保将编辑器内容同步回文本框 // 可以在保存按钮的客户端点击事件中,先执行同步操作,再回发 // 或者,我们可以在Page_Load中通过Request.Form获取内容(但这样绕过了Web Form的机制) // 方法1:在客户端点击保存按钮时,同步TinyMCE内容到文本框 // 给保存按钮添加客户端onclick事件:在回发前同步内容 // 例如:<asp:Button ... OnClientClick="syncTinyMCE();" ... /> // 方法2:在服务器端,我们可以通过Request.Form[txtContent.UniqueID]来获取内容(但需要确保TinyMCE更新了隐藏字段,通常它会更新对应的textarea) // 推荐方法1: // 页面中的脚本: // function syncTinyMCE() { // tinymce.triggerSave(); // 这会同步所有TinyMCE编辑器内容到对应的textarea // return true; // } // 然后按钮:OnClientClick="syncTinyMCE();" // 这样,在服务器端,我们就可以直接使用txtContent.Text来获取内容 string content = txtContent.Text; // 保存到数据库 SaveContentToDB(content); // 保存后,我们可以重新从数据库加载内容(可选,如果保存过程中内容被处理过) // 或者,如果不需要重新加载,可以忽略 // 注意:因为我们使用了UpdatePanel,所以不需要整个页面刷新,但需要更新编辑器区域? // 如果我们重新设置txtContent.Text,那么需要重新初始化编辑器(上面的EndRequestHandler会处理) // 将最新的内容设置回文本框(如果保存过程中内容有变化,比如做了清理等) // txtContent.Text = content; // 或者重新从数据库读取 txtContent.Text = GetContentFromDB(); // 由于在UpdatePanel中,所以只需要异步刷新,不需要整个页面回发 } ``` 总结步骤: 1. 在页面中放置TextBox用于TinyMCE编辑器。 2. 在页面中引入TinyMCE脚本,并初始化该TextBox。 3. 如果使用UpdatePanel,则在异步回发前后通过客户端脚本销毁重建TinyMCE编辑器。 4. 在保存按钮的客户端点击事件中,调用syncTinyMCE函数(内部调用tinymce.triggerSave())来同步内容到TextBox。 5. 在保存按钮的服务器端事件中,获取TextBox的内容,保存到数据库,然后重新从数据库加载内容并赋给TextBox(可选,如果保存后内容有变化则必须)。 6. 由于使用了UpdatePanel,页面不会整页刷新,但TextBox的内容更新会反映在页面上,并且TinyMCE在异步回发后重新初始化,显示新内容。 注意:如果用户没有使用UpdatePanel,那么每次回发都会整页刷新,那么就不需要客户端脚本处理异步回发,只需要在每次页面加载时初始化TinyMCE(在Page_Load中绑定数据,包括回发后)。 但整页刷新会导致页面闪烁,所以推荐使用UpdatePanel。 另外,如果保存后不重新加载数据,那么保存后编辑器显示的是提交前的内容(因为txtContent.Text在回发时被重新设置为ViewState中的原始值,除非我们在保存后修改了它)。所以,我们在保存操作中保存后重新设置txtContent.Text为最新值(从数据库读取),这样在页面回发后,文本框内容就是最新的,再通过TinyMCE初始化,就会显示最新内容。 因此,关键在于: - 保存前同步编辑器内容到文本框(客户端) - 保存后更新文本框内容为最新值(服务器端) - 每次异步回发后重新初始化编辑器(客户端) 按照以上步骤,应该能够解决问题。 如果用户的问题不是使用了UpdatePanel,那么需要根据实际情况调整。 由于用户的问题描述中提到了“editBytiny”,我们假设这是TinyMCE编辑器。如果使用的是其他编辑器,原理类似。 如果用户没有使用UpdatePanel,那么整个页面会在回发后刷新,那么只需要在Page_Load中确保数据正确绑定即可: ```csharp protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { // 首次加载绑定 txtContent.Text = GetContentFromDB(); } // 注意:如果是回发,那么ViewState会恢复控件状态,包括txtContent.Text(但TinyMCE的内容不会通过ViewState保存,所以我们需要在回发时同步到服务器端,然后保存后重新设置) // 实际上,在整页回发的情况下,我们在保存按钮点击事件中已经通过客户端同步将最新的内容放到了txtContent,所以txtContent.Text在回发时已经更新(在Page_Load之前就已经由ViewState机制恢复了?不对,应该是通过表单值恢复的) // 但是,在保存按钮点击事件中,我们通过同步机制(OnClientClick)将编辑器的内容同步到了txtContent,然后在btnSave_Click中,我们获取到了txtContent.Text(即更新后的内容),然后保存到数据库。 // 保存后,我们希望显示最新保存的内容,所以我们在btnSave_Click中重新设置txtContent.Text(从数据库加载),这样在Page_Load之后(包括后续的控件状态恢复),txtContent.Text已经被更新。 // 在整页回发的情况下,不需要额外的TinyMCE重新初始化,因为页面会重新加载,在页面底部我们引入了初始化脚本,会自动初始化。 } ``` 所以,对于整页回发的情况,处理更简单: 1. 在保存按钮的OnClientClick中调用syncTinyMCE()(同步编辑器内容到文本框)。 2. 在btnSave_Click中,保存txtContent.Text到数据库,然后重新从数据库加载内容并赋给txtContent.Text。 3. 页面重新加载后,TinyMCE初始化脚本会运行,将txtContent(包含最新内容)显示为编辑器。 因此,根据用户是否使用UpdatePanel,我们采取不同的客户端处理方式。 最后,如果用户的问题仍然存在,需要检查数据库操作是否成功,以及是否在页面中正确设置了文本框的内容。 由于问题描述有限,以上提供的是常见的解决方案。 </think>针对在 .NET Framework Web Form 页面中使用 TinyMCE 编辑器(editBytiny)保存数据后不显示编辑框内容的问题,以下是系统性解决方案: --- ### **问题原因分析** 1. **编辑器初始化失败** - 页面回发(PostBack)后 TinyMCE 未重新初始化 - 编辑器脚本加载顺序错误或依赖缺失 2. **数据绑定失效** - 保存后未从数据库重新加载数据 - 控件未正确绑定更新后的数据源 3. **动态控件状态丢失** - 包含 TinyMCE 的容器控件(如 `UpdatePanel`)未正确处理异步回发 --- ### **解决方案** #### **1. 确保编辑器正确初始化** 在 Page_Load 中添加初始化逻辑,强制每次回发后重建编辑器: ```javascript // 在页面底部添加初始化脚本 function initTinyMCE() { tinymce.init({ selector: '#<%= txtEditor.ClientID %>', // 匹配文本框ID plugins: 'advlist link image lists', toolbar: 'undo redo | bold italic | alignleft aligncenter alignright' }); } // 注册脚本管理器(Web Form 必须) Sys.Application.add_load(initTinyMCE); ``` #### **2. 正确处理数据绑定** 在保存按钮事件中,显式重新加载数据: ```csharp protected void btnSave_Click(object sender, EventArgs e) { // 1. 同步编辑器内容到服务器端控件 string content = Request.Form[txtEditor.UniqueID]; // 2. 保存到数据库(伪代码) YourDataAccessLayer.SaveContent(content); // 3. 重新加载数据并绑定 txtEditor.Text = YourDataAccessLayer.GetContent(); // 4. 强制更新界面 ScriptManager.RegisterStartupScript(this, GetType(), "refreshEditor", "initTinyMCE();", true); } ``` #### **3. 修复 UpdatePanel 异步刷新问题** 若使用 `UpdatePanel`,需注册异步回发后的初始化: ```csharp protected void Page_Load(object sender, EventArgs e) { ScriptManager.RegisterStartupScript( this, GetType(), "initEditor", "initTinyMCE();", true ); } ``` #### **4. 关键 HTML 结构示例** ```aspnet <asp:UpdatePanel runat="server"> <ContentTemplate> <!-- 编辑器容器 --> <asp:TextBox ID="txtEditor" runat="server" TextMode="MultiLine" /> <!-- 保存按钮 --> <asp:Button ID="btnSave" runat="server" OnClick="btnSave_Click" Text="保存" /> </ContentTemplate> </asp:UpdatePanel> <!-- 引入 TinyMCE --> <script src="//cdn.tiny.cloud/1/YOUR_API_KEY/tinymce/6/tinymce.min.js"></script> ``` --- ### **调试步骤** 1. **检查网络请求** - 浏览器开发者工具中确认 TinyMCE 脚本是否加载成功(无 404 错误) - 验证保存操作是否触发正确的 AJAX/PostBack 请求 2. **验证数据流** - 断点检查 `btnSave_Click` 是否获取到编辑器内容 - SQL Profiler 监控保存后是否执行数据查询 3. **控件状态检查** - 查看页面源码确认回发后 `txtEditor` 的 `value` 属性是否包含新数据 - 检查是否存在 JavaScript 控制台错误(如 `tinymce is not defined`) --- ### **注意事项** 1. **编辑器同步机制** TinyMCE 不会自动同步内容到原文本框,需在提交前调用 `tinymce.triggerSave()` 或通过 `Request.Form` 获取内容 [^1]。 2. **脚本加载顺序** 确保 TinyMCE 脚本在 jQuery 之后加载,避免冲突。 3. **UpdatePanel 陷阱** 动态生成的编辑器需在 `asyncPostBack` 后手动调用 `tinymce.remove()` 清理旧实例 [^3]。 --- 通过以上步骤,可解决编辑器及数据在回发后不显示的问题。若仍存在异常,需检查是否其他脚本(如 jQuery 插件)冲突或存在 ViewState 失效问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值