代码改变世界

通过Handler实现ASP.NET WebForm自定义控件局部刷新

2011-01-20 01:48  落小呆  阅读(900)  评论(1编辑  收藏  举报

看到这样的标题,也许马上会有人说直接用UpdatePanel不就行了,的确在大部分时候使用UpdatePanel就能实现我们需要的业务需求,但UpdatePanel的灵活性很有限,当业务需求比较复杂的时候,过多的使用UpdatePanel会导致页面很复杂,也可能会是页面的实现看起来很别扭,性能有时候也不是那么理想。

那么在ASP.NET WebForm里面能否自己实现局部的刷新?

要做到页面的Ajax获取服务器资源并不困难,但关键是服务器如何去做到每次只是渲染需要刷新的部分,而不是整个页面,那接下来就介绍如果实现局部(用户自定义控件)的渲染。

首先定义渲染用户自定义控件的控制器类,继承Page对象,由于在呈现服务器控件时默认会验证控件是否显示在HtmlForm控件的开始和结束标记之间,因此需要覆盖该验证:

 代码

    /// <summary>
    
/// 视图生成控制器
    
/// </summary>
    internal class Controller : Page
    {
        
/// <summary>
        
/// 覆盖服务器控件生成验证
        
/// </summary>
        
/// <param name="control"></param>
        public override void VerifyRenderingInServerForm(Control control)
        {

        }
    }

接下来就是定义用户自定义控件的是视图生成引擎类:

 代码

    /// <summary>
    
/// 视图生成引擎
    
/// </summary>
    public class ViewEngine<T> where T : UserControl, IDisposable
    {
        
private Controller _controller;

        
public ViewEngine()
        {
            _controller 
= new Controller();
        }

        
/// <summary>
        
/// 加载控件
        
/// </summary>
        
/// <param name="path"></param>
        
/// <returns></returns>
        public T LoadViewControl(string path)
        {
            _controller.EnableViewState 
= false;
            
return (T)_controller.LoadControl(path);
        }

        
/// <summary>
        
/// 生成视图
        
/// </summary>
        
/// <param name="control">控件类</param>
        
/// <returns>返回控件HTML</returns>
        public string RenderView(T control)
        {
            
try
            {
                _controller.Controls.Add(control);
                StringWriter output 
= new System.IO.StringWriter();
                HttpContext.Current.Server.Execute(_controller, output, 
false);
                _controller.Controls.Clear();
                
return output.ToString();
            }
            
catch { return string.Empty; }
        }

        
/// <summary>
        
/// 施放资源
        
/// </summary>
        public void Dispose()
        {
            _controller.Dispose();
        }
    }

 

现在简单的视图引擎基本就已经完成,然后就是如何使用该视图引擎渲染用户自定义控件,然后返回用户页面。

假设现在需要异步呈现用户自定义控件UserGet.aspx,那么定义一个用户自定义Handler用来接收页面的Ajax请求:

 代码

    public void ProcessRequest(HttpContext context)
    {
        context.Response.ContentType 
= "text/plain";

        
int id = int.Parse(context.Request.Form["id"]);
        
var user = Data.Users.FirstOrDefault(u=>u.ID == id);

        
var engine = new ViewEngine<UserGet>();
        UserGet view 
= engine.LoadViewControl("/Controls/UserGet.ascx");
        view.DataBind(user);
        context.Response.Write(engine.RenderView(view));
        engine.Dispose();
        context.Response.Flush();
    }

 

根据用户Post的信息获取用户反馈信息,然后通过前面定义的视图引擎加载用户自定义控件并获取用户自定义控件对象,然后将数据绑定到用户自定义控件对象,最后将渲染结果写入Response返回用户。

在页面Ajax请求定义的Handler,然后根据返回结果替换页面元素:

 代码

    <script type="text/javascript">
        function getUserDetail(id) {
            $.post(
"/Controls/UserGetHandler.ashx", { id: id }, function (result) {
                $(
"#divUserDitail").html(result);
            });
        }
    
</script>

 

这样基本就实现页面的局部刷新,但这样的局部刷新虽然会比较灵活,但也增加了开发的工作量。

注意:通过该方式局部刷新的用户自定义控件是无状态的。

 

 示例代码