在ASP.NET AJAX中使用自定义ViewManager局部更新数据

有时你不想用updatepanel,因为每次发出一个请求时,它会回发许多你不必用到的信息。当然updatepanel是强大的,易于使用的,但它不是一直都是一种高效的方法。你可能想不使用viewstate和postback,而要获得一个页面传递过来的数据结果,而且你想这个网页能被你驱动和使用最少的数据回发。

下面要讲的内容来自于Scott Guthries ViewManager 。最近我的一个想法促使我在客户端做许多的事情,也许我能不使用updatepanel。我之前已经做了许多通用的ViewManager,基本上就是允许你更容易地设置控件的属性并让你在执行和更新它之前设置它的任何属性。不要责备我之前写的文章,我发现我写的viewmanager更容易使用。所以我才分享它。

Data Control:
你需要创建一个用来更新数据页面的用户控件。就我来说,我会给这个控件一些属性,以至于你可以设置当前页和页面大小。我会把数据更新到一个listview里面,我的数据来自于一个数据库,我会使用LINQ to SQL来访问数据库。

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="Data.ascx.cs" Inherits="NoUpdatePanels.Data"  EnableViewState="false" %>
<asp:ListView ID="lvData" runat="server" ItemPlaceholderID="plcItem">           
    
<LayoutTemplate>
        
<br /><br />
        
<asp:PlaceHolder ID="plcItem" runat="server"></asp:PlaceHolder>
    
</LayoutTemplate>
    
<ItemTemplate>
        Name: 
<%# Eval("Name"%>
        
<hr />
    
</ItemTemplate>
</asp:ListView>

using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;

namespace NoUpdatePanels {
    
public partial class Data : System.Web.UI.UserControl {

        
#region Properties

        
public int CurrentPage { getset; }
        
public int PageSize { getset; }

        
#endregion

        
#region Constructors/Load

        
// Constructor, just init properties
        public Data() {
            
this.CurrentPage = 0;
            
this.PageSize = 5;
        }

        
protected void Page_Load(object sender, EventArgs e) {
            TestDataContext db 
= new TestDataContext();

            var query 
= (from p in db.Persons
                         select p).Skip(CurrentPage 
* PageSize).Take(PageSize);

            lvData.DataSource 
= query;
            lvData.DataBind();
        }

        
#endregion

    }
}

大体上,我所做的是根据当前页和页的大小,获得页面数据,并绑定到listview上。当然这个控件的viewstate也被我停用了。

The Page:
hosting网页是用来获得控件更新后的数据。所有的工作都在客户端使用web service完成。但在这里我没有用web service(懒一点)而是在我的网页上用了一个静态方法,然后我在ScriptManager里设置EnablePageMethods=true。就是这样了,大体上网页要做的事是使用网页的方法来获得网页的数据。这个网页方法接受一个current page参数,并根据数据控件设置的currentpage属性生成一个viewmanager实例,然后更新控件,返回数据。

这个网页使用了JavaScript来调用方法。并把结果放到一个div里。这这里有一点要注意的,脚本在网页结束的时候不会停下来,也不会进行真正的错误检查,它只是我的一种想法的原型。下面是html代码和后台代码:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="NoUpdatePanels._Default" %>

<%@ Register src="Data.ascx" tagname="Data" tagprefix="uc1" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    
<title>Client Side Data Loading</title>   
</head>
<body>
    
<form id="form1" runat="server">
        
<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="true"></asp:ScriptManager>

        
<a href="http://weblogs.asp.net/controlpanel/blogs/posteditor.aspx?SelectedNavItem=NewPost#" onclick="PreviousPage();">Previous &lt;</a> - <a href="http://weblogs.asp.net/controlpanel/blogs/posteditor.aspx?SelectedNavItem=NewPost#" onclick="NextPage();">Next &gt;</a>
        
<div id="contentRegion">       
            Loading
        
</div>

    
</form>
    
<script type="text/javascript">
        var currentPage 
= 0;       
       
        function LoadPage(page) {
            PageMethods.GetDataPage(page, function(result) {
                
// We loaded our data populate our div.               
                document.getElementById("contentRegion").innerHTML = result;
            },
            function(error) {
                alert(error.get_message());
            });
        }
       
        function PreviousPage() {
            currentPage
--;
            LoadPage(currentPage);   
        }
       
        function NextPage() {
            currentPage
++;
            LoadPage(currentPage);
        }
       
        
// Add our load event handler
        Sys.Application.add_load(LoadPage);
    
</script>
</body>
</html>

using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Web.Services;

namespace NoUpdatePanels {
    
public partial class _Default : System.Web.UI.Page {

        [WebMethod()]
        
public static string GetDataPage(int page) {

            
// Create an instance of our viewmanager.
            ViewManager<Data> man = new ViewManager<Data>("~/Data.ascx");

            
// Set the current page property.
            man.Control.CurrentPage = page;

            
// Return the rendered control.
            return man.Render();
        }

    }
}

The ViewManager:
这是通用viewmanager,它实际上是负责更新控件的工作。

using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Text;
using System.IO;

namespace NoUpdatePanels {

    
/// <summary>
    
/// A generic user control rendering helper, basically you initialise the view manager and
    
/// call render to render that control, but the benifit of this version is you can access the control
    
/// the view manager is rendering and can set custom properties etc.
    
/// </summary>
    
/// <typeparam name="T">The type of the control you are rendering</typeparam>
    public class ViewManager<T> where T : Control {

        
#region Properties

        
private T _control = default(T);

        
/// <summary>
        
/// Gives you access to the control you are rendering allows
        
/// you to set custom properties etc.
        
/// </summary>
        public T Control {
            
get {
                
return _control;
            }
        }

        
// Used as a placeholder page to render the control on.
        private Page _holder = null;

        
#endregion

        
#region Constructor

        
/// <summary>
        
/// Default constructor for this view manager, pass in the path for the control
        
/// that this view manager is render.
        
/// </summary>
        
/// <param name="inPath"></param>
        public ViewManager(string path) {
            
//Init the holder page
            _holder = new Page();

            
// Create an instance of our control
            _control = (T)_holder.LoadControl(path);

            
// Add it to our holder page.
            _holder.Controls.Add(_control);
        }

        
#endregion

        
#region Rendering

        
/// <summary>
        
/// Renders the current control.
        
/// </summary>
        
/// <returns></returns>
        public string Render() {
            StringWriter sw 
= new StringWriter();

            
// Execute the page capturing the output in the stringwriter.
            HttpContext.Current.Server.Execute(_holder, sw, false);

            
// Return the output.
            return sw.ToString();
        }

        
#endregion

    }

}

 

posted @ 2009-09-28 13:52  liyou  阅读(663)  评论(0编辑  收藏  举报