Ajax开发实例教程.NET页面屏聊系统_[Asp.Net教程]
前段时间,懒羊采用ajax+asp开发了一套页面屏聊系统(
点击查看原文),后来有些朋友问我能否移植到.Net中去。由于工作关系,正好前段时间需要用微软的Asp.Net Ajax开发包开发一套项目,所以对此作了个简单了解,发现使用Asp.Net Ajax开发包去开发要比原来的asp+ajax简单得多,而且开发完后对浏览器的兼容也大大的提高了。因此懒羊这里就再次献丑,将一些开发心得提供出来与大家一起分享,并提供用户控件供大家下载使用。
一、Asp.NET Ajax框架介绍
主要对Asp.NET Ajax的安装以及本文中所要用到的控件进行简单的说明,大家如有兴趣可以通到网络上查询更多的资料。
1、何为Asp.NET Ajax?
Asp.NET Ajax原代号“Atlas”是一个集成了强大的客户端脚本库的Web技术开发包,并且能够与Asp.NET 2.0紧密的结合在一起。我们在Web 应用程序开发中,通过它可以直接调用Web服务器来更新Web页面上某个部分的数据,而不需要重新加载页面来达到页面数据的更新。
当然Asp.Net Ajax的功能并不是仅仅只有如上所叙的那么点点,由于很多的功能我们这里用不到,就不多费口舌了。ASP.NET AJAX Control Toolkit中有数十种超炫的控件,大家有兴趣可以一个个试试。
2、Asp.NET Ajax如何安装?
关于Asp.NET Ajax的组成主要有三块内容:
① ASP.NET AJAX:这部分是ASP.NET AJAX的核心部分,包括了核心AJAX类型系统,网络协议层(networking stack),组件模型,扩展器(extender)基类,以及与ASP.NET集成的服务器端功能(包括广受欢迎的ScriptManager,UpdatePanel,和 Timer控件)。
下载地址:
微软 IT168下载
② ASP.NET AJAX Futures CTP:这一部分就是被ASP.NET AJAX暂时“抛弃”的原有CTP版本中“非核心”的部分,也叫做“Value-add”包,其中包括服务器端的扩展器控件(Extender Control)、Web部件,客户端的各种控件、拖放功能实现、ASP.NET AJAX XML脚本等。所谓“抛弃”,实际上只是意味着微软公司暂时不会对这些内容进行官方的支持,而选择使用“社区支持”的方法。这样,微软公司将不会为这部分内容提供详细的开发文档,开发者只能在社区中互相讨论以找到问题的解决方案。若要安装这部分内容,则必须首先安装“核心”部分的ASP.NET 2.0 AJAX Extensions。
下载地址:
微软 IT168下载
③ ASP.NET AJAX Control Toolkit: 它是一个免费的、开源的、由微软公司和开发者社区共同创建的ASP.NET服务器端控件包,其中包含了数十种基于ASP.NET AJAX的、组件化的、提供某个专一Ajax功能的ASP.NET AJAX服务器端控件和ASP.NET AJAX扩展器控件,这些控件同样是创建一个完善的Ajax应用程序所必不可少的。
下载地址:
codeplex.com IT168下载
ASP.NET AJAX Control Toolkit下载后为压缩包文件,在下载完成以后直接解压,解压后先运行AjaxControlExtender\AjaxControlExtender.vsi进行安装,安装成功后打开Visual Studio.NET 2005并在工具栏添加SampleWebSite\Bin\AjaxControlToolkit.dll。
由于本文只采用到ScriptManager、UpdatePanel、Timer等控件,因此只需要安装ASP.NET AJAX就可以完成屏聊的开发。安装成功后我们打开Visual Studio.NET 2005中并新建Web Site,在项目模板中会出现一项ASP.NET AJAX-enabled Web site,如下图:
图一 在Visual Studio.NET中添加AJAX控件
并且会在工具箱中出现AJAX Extensions控件,如下图:
图二 Visual Studio.NET工具栏中AJAX Extensions控件
3、ScriptManager控件
ScriptManager是Asp.NET Ajax一个重要的控件,它用来处理页面上的所有Asp.NET Ajax组件以及局部页面的更新,生成相关的客户端脚本,所有需要支持Asp.NET Ajax的ASP.NET页面上有且只能有一个ScriptManager控件。在ScriptManager控件中我们可以指定需要的脚本库,或者指定通过JS来调用的Web Service,还可以指定页面错误处理。
Script属性用来包含那些ASP.NET Atlas自带的标准JS库或者是自定义的JS脚本。我们可以使用Path属性来指定一个JS的路径或者使用ScriptName来指定脚本名。
代码如下:
4、UpdatePanel控件
UpdatePanel控件是一个功能非常强大的控件,同样的我这里也不去讲太多关于此控件的用法,主要记住以下两个属性。
① Triggers属性
Triggers的类型有两种AsyncPostBackTrigger,PostBackTrigger。
AsyncPostBackTrigger主要用来指定某个控件的某个事件引发异步回传(asynchronous postback),即部分更新。属性有ControlID和EventName。分别用来指定控件ID和控件事件,若没有明确指定EventName的值,则自动采用控件的默认值,比如button就是click。把ContorlID设为UpdatePanel外部控件的ID,可以使外部控件控制UpdatePanel的更新。
PostBackTrigger是来指定UpdatePanel内的某个控件引发整个页面的更新(normal postback)。
例如:
② UpdateMode 属性
UpdateMode同样有两个值:Always(总是更新),Conditional(有条件更新)。
确定当asynchronous postbacks发生时,是否总是更新。若页面中只有一个UpdatePanel控件,这个值好像没有什么意义。但是当页面中存在多个UpdatePanel,或者UpdatePanel中包含UpdatePanel的复杂情况时,这个值的设定就可以使各个UpdatePanel在各种合适时机更新,而我们这个系统就会出现多个UpdatePanel,并且会嵌套使用。
二、屏聊系统规划及介绍
采用Asp.NET Ajax开发屏聊系统相对于Asp+Ajax开发要相对简单得多,我们只需要像普通的Web编程一样,拖拖拽拽就可以将整个系统堆建起来,在前台我们也不需要写太多的Javascript代码,直接由框架生成就可以了,只是将传统.NET下的控件放在UpdatePanel控件里面,并为UpdatePanel设置一定的属性值,就可以实现局部区域的刷新。
1、屏聊系统界面区域结构
我们在
《Ajax开发页面聊天系统》已经知道,页面屏聊系统的页面主要由两部分组成,一是最小化时的页面(AnchorCall1_Min),另一则是还原时的页面,我们这里称为最大化时的页面(AnchorCall1_Max)。为了便于大家的理解,懒羊在这将页面所要安排的UpdatePanel控件位置绘制如下(以下红框圈注部分为UpdatePanel控件)。
图三 UpdatePanel控件位置排布图
AnchorCall1_Min区域:
Min0区域:由一个img的Html控件与ImageButton控件构成,img通过JS代码将界面由最小化转为最大化界面。ImageButton控件来控制屏聊页面的关闭,并且停止屏聊程序的运行,稍后会作详细的介绍。
Min1区域:由一个Label控件构成,用于显示屏聊用户的提示信息,如登陆信息、改名信息等等。
AnchorCall1_Max区域:
Max0区域:与Min0区域相似,只是img控件是实现由最大化界面向最小化界面切换。
Max1区域:由两个ImageButton控件和一个TextBox控件构成。TextBox主要用于显示系统自动生成的呢称。而ImageButton一个为改名按扭,另一个将聊天记录生成为HTML文件。
Max2区域:本区域是整个系统的一个核心区域,主要用于显示聊天记录,由于聊天记录是定时刷新的,也就是定期会从服务器读取聊天信息并更新显示区域,我们显示聊天信息的区域采用一个可以多行的TextBox控件来显示,由于聊天信息量的增多,我们就会去拖动TextBox控件的滚动条,但因为我们会通过Ajax中的Timer控件来定期更新TextBox中的内容,因此TextBox中的滚动条会因此而不断的复位,而我们拖动时就会很不方便,出于人性化考虑我们还必须通过客户端代码来控制服务器端Timer控件的启用与停止,另外还有两个采用隐藏(style=display:none)的Button控件,主要是为了协助客户端肛码控制Timer控件的启用与停止,后面同样我们将重点介绍。提示信息区与Min1区相似为一个Label控件。
Max3区域:由一个ImageButton控件与TextBox控件构成。主要实现聊天信息的发送功能,本功能支持Alt+S。
三、屏聊系统功能介绍
1、访问者浏览包含屏聊系统的网页,屏聊系统会根据当前时间自动生成呢称,并根据当前页面以及当前时间来调用同一个页面上所有访问者的聊天信息。为了减轻调用的信息量故采用时间限制,也就是访问者只调用从访问者登陆之后的信息,而并不是在这个页面上所有的聊天信息。
2、用户在登陆页面、修改呢称、退出页面时都会对应的信息写入数据库并且传递给其它在线的访问者。
3、为了尽量的缩小在主页面上的显示区,可以将页面最小化,最小化时的页面只显示提示信息,但不显示聊天信息,但不会丢失聊天信息,当需要查看时,可以将页面切换至最大化。
3、改名功能:访问者可以更换自己喜欢的呢称,但当用户所更改的呢称在当前页面中已经存在,用户将无法修改,并在提示区域进行提示。
4、聊天信息的查看:在界面介绍已经提到,由于Timer控件的定时更新,导致不方便拖动聊天信息显示的文本框,故必须在拖动文本框时可能调用服务器端程序将Timer控件停止。
5、系统发送支持Alt+S,这是为了方便一些习惯于其它即时通工具的用户,比如QQ,至少说懒羊习惯这个快捷键,真的很方便噢,呵呵。
6、关闭:本系统中这一功能是一个重点更是一个难点。由于页面流量的产生,访问者越来越多,而每个访问者都会在数据库留下痕迹,因此数据库也就越来越庞大,我们不可能定期去清理数据库,也无法去清理数据库,我们很难确定啥时页面有人,而且也耗不起这个人力,这就要求我们程序能够自动的去处理数据库,而这一点只能在关闭时实施。关闭时清理数据库主要包括两个方面:一是当此访问者退出时不是最后一位,那么访问者在退出之前将退出信息添加至提示信息库并清除此访问者在线信息,但如果为最后一位访问者,系统将会在此访问者退出前清理这个页面所有信息,包括聊天信息、提示信息、在线信息。
四、系统开发重难点解释
1、全局呢称与访问者的登陆时间设定
呢称与登陆时间在本系统一直贯穿始终,所有聊天信息的调用都必须根据这两个关键字段。由于.NET中的C#代码功能相当强大,这就使得我们不需要再像之前文章中将这两个关键值通过JS代码来实现,而且通过JS代码实现后的传值也不是很方便,那么我们将通过什么样的方式来实现呢?我们可以先在前台拖放两个文本框,作为传递关键值的一个媒介。为了使页面在回传时不会对呢称与登陆时间进行重新设置,我们还必须在页面加载时必须判断是否为客户端回发还是第一次加载。
代码如下:
if (!this.IsPostBack)
{
this.LoginTime.Text = DateTime.Now.ToString();
this.RndName.Text = ServerGetName();
this.nc.Text = this.RndName.Text;
}
public string ServerGetName() //生成默认呢称
{
string RndName = "LY" + DateTime.Now.Year.ToString() + DateTime.Now.Month.ToString() + DateTime.Now.Day.ToString() + DateTime.Now.Hour.ToString() + DateTime.Now.Minute.ToString() + DateTime.Now.Second.ToString();
return RndName;
}
2、客户端调用服务器端函数
客户端是没有直接方式调用服务器端函数,我们只能通过页面调用控件来进行页面PostBack回发,从而达到调用服务器端的函数。本系统中的关闭功能、快捷键(Alt+S)发送功能、聊天信息拖动滚动条时停止更新聊天信息的功能都用到此方法,下面我们就开始来看看这三个功能的具体实现方式:
① 关闭功能
关闭功能主要出现在Min0区与Max0区、主页面退出时发生。
其中主页退出时使用页面事件window.onunload来调用Min0区中的关闭按钮(Close)的事件函数。我们先看看关闭按扭的所引用的事件函数:
protected void close_Click(object sender, ImageClickEventArgs e)
{
closeEmsg(); //具体的处理程序略(源代码见文末打包下载)
}
其次添加如下JS代码:
function unloadpage()
{
__doPostBack("AnchorCall1close","") //调用关闭按钮
}
我想很多朋友可能不明白上面这段代码,AnchorCall!close为关闭按钮的name,我们可以通过运行页面,然后查看页的HTML源代码,可以看到close按钮的name为AnchorCall1close,同样我们可能通过同样的方法来调用其它铵钮所触发的事件,例如存在某一个按钮为AnchorCall1Button1,那么我们JS调用的代码则为:__doPostBack("
AnchorCall1Button1","")
② 快捷键(Alt+S)发送功能
通过前面的学习,我们不难写出此功能的代码,这里的代码主要通过调用发送按钮,我们通过页面源代码可以知道,发送按钮的名称为:AnchorCall1ImageButton1,那么代码则为:__doPostBack("AnchorCall1ImageButton1",""),由于我们快捷键的发送是通过按键来触发的,因此我们就必须将以上代码添加至
onkeydown事件下。
代码如下:
this.fscontent.Attributes.Add("
onkeydown", "keypress(event)");
JS代码keypress函数:
function keypress(event)
{
var keycode = event.keyCode?event.keyCode:event.which?event.which:event.charCode;
if((keycode==83)&&(event.altKey)){
__doPostBack("AnchorCall1ImageButton1","");
}
}
③ 聊天信息拖动停止聊天信息功能
相对于前面两个功能的实现,这个功能多了点步骤,但原理还是一致的。由于系统中并没有控制Timer控件的启用与关闭的控件,因此我们需要先在Max2区域中添加两个按钮Button1(关闭Timer)与Button2(启用Timer),然后设置其style=”display:none”,并为两个按钮添加如下代码:
protected void Button1_Click(object sender, EventArgs e)
{
this.Timer2.Enabled = true; //启用
}
protected void Button2_Click(object sender, EventArgs e)
{
this.Timer2.Enabled = false; //停止
}
现在我们来具体的看一下如何在拖动文本框时调用Button2按钮,在客户端并没有拖动文本框的事件,那我们不得不求助于
onmousemove事件,当鼠标在上面移动时触发,如果我们将调用服务器的代码直接置入事件中,我们就会因移动不断的去调用服务器,这样就会加重服务器的负载,因此我们必须在JS中通过一定的Flag值来控制是否得得调用服务器程序。代码如下:
首先设定Flag:
var Timer2Flag=1;
再建立两个JS函数:
function stopTimer2() //控制停止调用Timer
{
if(Timer2Flag==1) //当为真时调用后,就不再调用,一直等鼠标离开文本框后再次移入才会调用
{
__doPostBack("AnchorCall1Button2","");
Timer2Flag=0;
}
}
function startTimer2() //控制启动调用Timer
{
__doPostBack("AnchorCall1Button1","");
Timer2Flag=1;
}
④ 保存聊天记录
系统的聊天功能是通过参数传递给一个新的页面并打开新页面,新页面根据URL参数从数据库中读出相关的聊天信息。为了打开新的页面,我们首先给“保存记录”添加客户端事件,在添加的过程中我们将此访问者的呢称、登陆时间、当前URL传递过去,如下:
this.ImageButton2.Attributes.Add("
onclick", "window.open('Anchor_ChatRecord.aspx?url=" + Request.Url.ToString() +
"&begindate=" +
this.LoginTime.Text + "&rndname="+
this.RndName.Text+"')");
这样我们就可以很方便的打开新页面,而且能够将关键值传递给新页面,然后我们在新的页面中输入如下代码,以方便调用数据库信息,首先在新页面(Anchor_ChatRecord.aspx)添加一个Label控件,用于显示聊天信息。然后在后台Page_load中输入如下代码:
if (Request["url"] != null && Request["begindate"] != null && Request["rndname"] != null)
{
string TempStr = "";
string url = Request["url"].ToString();
string begindate = Request["begindate"].ToString();
string rndname = Request["rndname"].ToString();
string str = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + HttpContext.Current.Server.MapPath(ConfigurationManager.AppSettings["AnchorCallDateBase"]);
OleDbConnection conn = new OleDbConnection(str);
conn.Open();
string sql = "select * from chatroom where frompage='"+url+"' and datediff('s','" + begindate + "',dateandtime)>0 order by id desc";
OleDbCommand cmd = new OleDbCommand(sql, conn);
OleDbDataAdapter da = new OleDbDataAdapter(cmd);
DataSet ds = new DataSet();
da.Fill(ds);
if (ds.Tables[0].Rows.Count > 0)
{
for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
{
TempStr = "
" + ds.Tables[0].Rows[i]["nc"].ToString() + ":" + ds.Tables[0].Rows[i]["chatmsg"].ToString() + "
[" + DateTime.Parse(ds.Tables[0].Rows[i]["dateandtime"].ToString()).ToShortTimeString() + "]";
this.Label1.Text += TempStr;
}
}
cmd.Dispose();
conn.Close();
conn.Dispose();
Page.ClientScript.RegisterStartupScript(this.GetType(), "", "");
}
else
{
this.Label1.Text = "懒羊提示:参数错误!";
Page.ClientScript.RegisterStartupScript(this.GetType(),"","");
}
五、Visual Studio 2005开发步骤
通过以上的学习,我们可以简单的了解屏聊系统的整个开发思路及在开发中所出现的重点难点。读者可以试着去按照功能思路去实际操作一下,下面懒羊把使用VS2005操作的具体步骤附上,但我还是希望读者能够先看一下前面的内容再来看下面的内容:
1、打开VS2005—> 新建—> 网站—> ASP.Net网站;
2、为了方便以后移植,我们为项目添加用户控件。右击项目文件—> 添加新项;
3、拖动ScriptManage控件到页面,并为Scripts属性添加anchormain.js,如下图:
图四 为Scripts属性添加anchormain.js
Anchormain.js为屏聊系统界面客户端代码,其中包括页面位置显示、页面加载、关闭时所触发的事件功能,代码如下,详细可以参照《
Ajax开发页面聊天系统》一文。
// JScript 文件
window.onload = getMsg;
window.onresize = resizeDiv;
window.onscroll= resizeDiv;
window.onunload=unloadpage;
window.
onerror = function(){alert("程序出错问题,请与懒羊联系!");
var divWidth,divHeight,docHeight,docWidth;
var Timer2Flag=1;
function resizeDiv()
{
try{
divHeight = parseInt(document.getElementById("eMsg").offsetHeight,10);
divWidth = parseInt(document.getElementById("eMsg").offsetWidth,10);
document.getElementById("eMsg").style.top =(document.documentElement.clientHeight - divHeight + parseInt(document.documentElement.scrollTop,10))+"px";
document.getElementById("eMsg").style.left = (parseInt(document.documentElement.scrollLeft,10) + document.documentElement.clientWidth - divWidth)+"px";
}
catch(e){
}
}
function moveDiv()
{
try
{
if(parseInt(document.getElementById("eMsg").style.top,10) <= (docHeight - divHeight + parseInt(document.documentElement.scrollTop,10)));
{
window.clearInterval(objTimer);
objTimer = window.setInterval("resizeDiv()",1);
}
divTop = (parseInt(document.getElementById("eMsg").style.top,10))+"px";
document.getElementById("eMsg").style.top =( divTop - 1 )+"px";
}
catch(e){
}
}
function getMsg()
{
try{
document.getElementById("AnchorCall1_Max").style.display="none";
divHeight = parseInt(document.getElementById("eMsg").offsetHeight,10)
divWidth = parseInt(document.getElementById("eMsg").offsetWidth,10)
docWidth = document.documentElement.clientWidth;
docHeight = document.documentElement.clientHeight;
document.getElementById("eMsg").style.top =(parseInt(document.documentElement.scrollTop,10) + docHeight + 10)+"px";// divHeight
document.getElementById("eMsg").style.left =(parseInt(document.documentElement.scrollLeft,10) + docWidth - divWidth)+"px"; document.getElementById("eMsg").style.visibility="visible" ;
objTimer = window.setInterval("moveDiv()",10) ;
}
catch(e){}
}
function changemax() //还原屏聊系统
{
document.getElementById("AnchorCall1_Min").style.display="none";
document.getElementById("AnchorCall1_Max").style.display="";
}
function changemin() //最小化屏聊系统
{
document.getElementById("AnchorCall1_Min").style.display="";
document.getElementById("AnchorCall1_Max").style.display="none";
}
function closeMsg()//关闭屏聊系统
{
document.getElementById("eMsg").style.display="none";
}
function unloadpage()
{
__doPostBack("AnchorCall1close","")
}
function stopTimer2()
{
if(Timer2Flag==1)
{
__doPostBack("AnchorCall1Button2","");
Timer2Flag=0;
}
}
function startTimer2()
{
__doPostBack("AnchorCall1Button1","");
Timer2Flag=1;
}
function keypress(event)
{
var keycode = event.keyCode?event.keyCode:event.which?event.which:event.charCode;
if((keycode==83)&&(event.altKey)){
__doPostBack("AnchorCall1ImageButton1","");
}
}
4.根据屏聊界面拖放UpdatePanel控件,并为UpdatePanel控件设置Triggers和UpdateMode。
拖放完UpdatePanel控件后,再从工具箱中拖出两个Timer控件,并将Timer控件的Interval设置为1000(1秒钟运行一次)。设置完Timer,我们来设置每一个UpdatePanel控件,我们将UpdatePanel控件的UpdateMode都设为Conditional,Triggers则添加UpdatePanel控件内的子控件,其中Min1区域还需添加Timer1,Max2区域添加Timer2。
最终页面HTML代码如下:
<%@ Register Assembly="System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
Namespace="System.Web.UI" TagPrefix="asp" %>
懒羊屏聊系统
onmousemove="this.src='images/max_1.gif'" onmouseout="this.src='images/max.gif'" onclick="changemax();" alt="" src="images/max.gif" id="img1" /> class="timg" ID="close" runat="server" ImageUrl="images/close.gif" onClick="close_Click" />
onclick="changemax();">

懒羊屏聊系统
onmousemove="this.src='images/min_1.gif'" onmouseout="this.src='images/min.gif'" onclick="changemin();" alt="" src="images/min.gif" />
class="timg" ID="close1" runat="server" ImageUrl="images/close.gif" onClick="close_Click" />
-
- onClick="ImageButton3_Click">
- 开发:懒羊(杨剑)
Width="291px" BorderColor="#FFC0C0" BorderStyle="Solid" BorderWidth="1px">
onClick="Button1_Click" />
onClick="Button2_Click" />
- 大家好!
- onclick="ImageButton1_Click" runat="server" ImageUrl="images/fs.gif">
为了更好的显示页面,我们还必须对页面进行样式控制,由于样式文件与原来文章中的CSS样式相同,这里就不多说了,直接添加到项目中就可以了。
来源:it168