蜗牛,在赛跑

--努力去改变吧
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

CVS的使用教程

Posted on 2007-07-03 12:59  body  阅读(1995)  评论(0编辑  收藏  举报

CVS的使用教程

1、什么是CVS?

CVS - Concurrent Versions System(并发版本管理系统)是一个版本控制管理系统,它是目前最为广泛使用的一个系统。

在多人共同开发一个大型项目时,源代码的维护和版本维护是一件令人头疼的事情,由于多人开发, 每个开发人员都拥有此项目的副本,所以如果要手动维护同一个文件多人的修改是十分困难的事情。另外,可能你需要的项目的版本不是当前开发的最新的版本, 如果为了这个目的而为每一个版本保留一个备份几乎是不可能的。

CVS不仅可以维护源代码,事实上,所有的文本文件都可以使用CVS来管理,当然也可以管理二进制文件,只是需要特殊的命令选项罢了。

CVS把文件保存在一个名叫仓库(repository)的地方,仓库中保存的文件并不是每个版本的副本,而是可以从任意版本回溯到初始版本的一些代码的主控信息,这样,就节省了大量的存储空间。 仓库不仅可以建立在本机上,也可以建立在网络上。另外CVS支持版本分支(tag),这样可以从任意的版本中衍生出另外一个版本进行开发,必要时,还可以把这个分支合并到主开发分支去。

2.如何得到CVS?

论坛用的是基于windows系统的winCVS 1.2版本,可从论坛进行下载,下载地址:http://bbs.miforum.net/download/WinCVS120.rar

CVS的官方站点:http://www.cvsgui.org

3、如何使用CVS?

可以依照dreamaster所做的演示动画进行操作:观看演示动画

也可依照以下步骤进行。

第一步:启动winCVS

启动后的界面如下:

第二步:设置工作目录,使用Change Location选择自己的工作目录。

第三步:设置通讯连接

1、选择菜单:Admin--Preferences

2、在Enter the CVSROOT中输入test@mifcvs.vicp.net:/miforum
其中test为用户名;mifcvs.vicp.net为CVS主机地址;/miforum为MiForum的CVS的Repository。

注意:大家记得把下图中的Checkout Readonly取消(默认是被选的)不然Checkout下来的文件要先修改文件的属性才能编辑。

另外,使用代理服务器上网的会员记得设置好自己的Proxy Server:

第四步:登陆CVS服务器

1、点击Admin--Login

输入密码:test(登陆密码为test)

当在Log区出现如下图示时表示登陆成功了。

如出现下图,你就登陆失败了。

第五步:获取CVS文件模块

在服务器上有一个名为test的Module用于测试是否成功

选择Create下的Checkout Module

 

输入在服务器上的模块名称:在本例中为test

成功以后会如图:

论坛不同的主题小组将建立不同的模块,因此如果需要检出不同的模块,请到论坛查看相应的帖子

 

posted @ 2007-06-12 15:13 诸葛依驰 阅读(58) | 评论 (0)编辑 收藏


2007年5月18日

     摘要: 介绍给按钮增加单击弹出确认框的功能是经常要用到的,我们一般是通过在RowDataBound事件里编码的方式实现,麻烦,所以扩展一下。控件开发1、新建一个继承自GridView的类。 /**//// <summary>/// 继承自GridView/// </summary>[ToolboxData(@"<{0}:SmartGridVie...  阅读全文

posted @ 2007-05-18 00:41 诸葛依驰 阅读(244) | 评论 (1)编辑 收藏

介绍
ASP.NET的GridView控件允许你通过设置它的EditIndex属性来编辑数据行,此时整个数据行都处于编辑模式。 如果你在EditItemTemplate的一些列中使用了DropDownList控件,那么你也许不希望整个数据行都处于编辑模式。 因为,如果每一个DropDownList控件都有很多选项的话,那么一次加载所有DropDownList控件的所有选项就会导致页面执行缓慢。

另外,如果你的数据行的编辑模式需要占用更多的空间的话,那么针对每一个独立的单元格进行编辑要优于针对整个数据行进行编辑。 这里,我将示范如何实现这样的功能,又如何去处理事件验证(event validation)。


背景
本文基于我之前写的一篇文章:GridView和DataList响应单击数据行和双击数据行事件。如果你不知道如何让GridView响应单击数据行事件,那么你可以在阅读本文之前先看看这篇文章。


编辑某一个独立的GridView单元格。


我所演示的这个GridView有一个不可见的asp:ButtonField控件,它处于GridView的第一列,名为“SingleClick”。 它用于给GridView的数据行增加单击事件。
<Columns>                
    
<asp:ButtonField Text="SingleClick" CommandName="SingleClick" Visible="False" />
</Columns>

其它每一列的ItemTemplate中有一个可见的Label控件和一个不可见的TextBox或DropDownList控件。 为了方便,我们称Label为显示控件,TextBox或DropDownList为编辑控件。
    <asp:TemplateField HeaderText="Task">
        
<ItemTemplate>
            
<asp:Label ID="DescriptionLabel" runat="server" Text='<%# Eval("Description") %>'></asp:Label>
            
<asp:TextBox ID="Description" runat="server" Text='<%# Eval("Description") %>' Width="175px" visible="false"></asp:TextBox>
        
</ItemTemplate>
    
</asp:TemplateField>

这里的办法就是用显示控件来显示数据,当单元格所包含的显示控件被单击的时候,则把显示控件的Visible属性设置为false并且把编辑控件的Visible属性设置为true。 这里不用使用EditItemTemplat。

在RowDataBound事件内循环为每一数据行的每一单元格增加单击事件。 使用单元格在数据行中的索引作为事件参数,这样在单元格触发了单击事件后我们就可以知道到底是哪个单元格被单击了。
    protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
    
{
        
if (e.Row.RowType == DataControlRowType.DataRow)
        
{
            
// 从第一个单元格内获得LinkButton控件
            LinkButton _singleClickButton = (LinkButton)e.Row.Cells[0].Controls[0];
            
// 返回一个字符串,表示对包含目标控件的 ID 和事件参数的回发函数的 JavaScript 调用
            string _jsSingle = ClientScript.GetPostBackClientHyperlink(_singleClickButton, "");

            
// 给每一个可编辑的单元格增加事件
            for (int columnIndex = _firstEditCellIndex; columnIndex < e.Row.Cells.Count; columnIndex++)
            
{
                
// 增加列索引作为事件参数
                string js = _jsSingle.Insert(_jsSingle.Length - 2, columnIndex.ToString());
                
// 给单元格增加onclick事件
                e.Row.Cells[columnIndex].Attributes["onclick"= js;
                
// 给单元格增加鼠标经过时指针样式
                e.Row.Cells[columnIndex].Attributes["style"+= "cursor:pointer;cursor:hand;"
            }
     
        }

    }

在RowCommand事件内读出命令参数和事件参数。 这会告诉我们被选中的行和列的索引。
    int _rowIndex = int.Parse(e.CommandArgument.ToString());      
    
int _columnIndex = int.Parse(Request.Form["__EVENTARGUMENT"]);

因为知道了被选中的行和列的索引,所以可以通过把显示控件的Visible设置为false,编辑控件的Visible设置为true来把某个独立的单元格设置为编辑模式。 然后通过清除单元格的属性来删除被选中单元格的单击事件。
    // 获得被选中单元格的显示控件并设置其不可见
    Control _displayControl = _gridView.Rows[_rowIndex].Cells[_columnIndex].Controls[1]; 
    _displayControl.Visible 
= false;
    
// 获得被选中单元格的编辑控件并设置其可见
    Control _editControl = _gridView.Rows[_rowIndex].Cells[_columnIndex].Controls[3];
    _editControl.Visible 
= true;
    
// 清除被选中单元格属性以删除click事件
    _gridView.Rows[_rowIndex].Cells[_columnIndex].Attributes.Clear();

下面有一些代码用于回发服务器后设置焦点到编辑控件,如果编辑控件是DropDownList的话,那么它的SelectedValue要设置为显示控件的值,如果编辑控件是TextBox的话,那么为了做好编辑的准备就要使它的文本被选中。
    // 设置焦点到被选中的编辑控件
    ClientScript.RegisterStartupScript(GetType(), "SetFocus"
        
"<script>document.getElementById('" + _editControl.ClientID + "').focus();</script>");
    
// 如果编辑控件是DropDownList的话
    
// SelectedValue设置为显示控件的值
    if (_editControl is DropDownList && _displayControl is Label)
    
{
        ((DropDownList)_editControl).SelectedValue 
= ((Label)_displayControl).Text;
    }
                 
    
// 如果编辑控件是TextBox的话则选中文本框内文本
    if (_editControl is TextBox)
    
{
       ((TextBox)_editControl).Attributes.Add(
"onfocus""this.select()");
    }

在这个Demo中,我把事件被触发的历史记录也写到了页里。

如果GridView处于编辑模式的话,那么要在RowUpdating事件里去查找被选中行的每一个单元格。 如果发现单元格处于编辑模式的话,那么就调用“更新”代码。 在这个Demo中,数据保存在DataTable里,而这个DataTable则储存在session中。
    // 循环每一列以找到处于编辑模式下的单元格
    for (int i = 1; i < _gridView.Columns.Count; i++)
    
{
        
// 获得单元格的编辑控件
        Control _editControl = _gridView.Rows[e.RowIndex].Cells[i].Controls[3];
        
if (_editControl.Visible)
        
{
           . update the data
        }

    }

为了确保RowUpdating事件在编辑单元格后被激发,要在Page_Load中来触发这个事件。 编辑了TextBox后,通过按回车键或者单击另一单元格来使页面做回发处理,下面的这段代码就是用于确保任何数据的改变都会被更新。
    if (this.GridView1.SelectedIndex > -1)
    
{
        
this.GridView1.UpdateRow(this.GridView1.SelectedIndex, false);
    }
   


为了验证而注册回发和回调数据
在RowDataBound中创建的自定义事件必须要在页中注册。 通过重写Render方法来调用ClientScriptManager.RegisterForEventValidation。 通过GridViewRow.UniqueID返回行的唯一ID,按纽的唯一ID通过在行的唯一ID后附加“$ct100”而生成。
    protected override void Render(HtmlTextWriter writer)
    
{
        
foreach (GridViewRow r in GridView1.Rows)
        
{
            
if (r.RowType == DataControlRowType.DataRow)
            
{
                
for (int columnIndex = _firstEditCellIndex; columnIndex < r.Cells.Count; columnIndex++)
                
{
                    Page.ClientScript.RegisterForEventValidation(r.UniqueID 
+ "$ctl00", columnIndex.ToString());
                }

            }

        }

      
        
base.Render(writer);
    }

这将防止任何“回发或回调参数无效”的错误。


这个Demo中的其它示例
使用SQL数据源控件编辑某一独立的GridView单元格
用SqlDataSouce控件实现这个技术需要对GridView的RowUpdating事件做一些修改。 当更新GridView的行的时候,SqlDataSource控件一般要把值(values)从EditItemTemplate转移到NewValues集合里。 因为我们没有使用EditItemTemplate,所以这种情况下值(values)不会自动地转移到NewValues集合里。
    e.NewValues.Add(key, value);

我在App_Data文件夹下使用了一个简单的SQL Server Express数据库。 (要使用你自己的数据库的话,你可以修改web.config里的连接字符串)


使用对象数据源控件编辑某一独立的GridView单元格
本示例使用了App_Code文件夹内的两个类:
    ·Task.cs – 任务对象
    ·TaskDataAccess.cs – 管理任务对象

Aspx页的后置代码与SQL Data Source示例是一样的。 ObjectDataSource通过TaskDataAccess.cs类里的GetTasks和UpdateTask方法来管理数据。


有着电子数据表样式的GridView
这里有一个与电子数据表的样式很像的GridView。 (虽然它看起来像一个电子数据表,但是并不是真的有像电子数据表一样的功能,它仍然是一个GridView。)

这里虽然有一些单击后改变单元格样式的附加代码,但是主要的代码还是与上面所述是相同的。



用SQL数据源控件实现有着电子数据表样式的GridView
本示例与上面的基本相同,但是它修改了GridView的RowUpdating事件以使其允许用SqlDataSource控件来工作。
 

参考
    ·GridView和DataList响应单击数据行和双击数据行事件
    ·ASP.NET 2.0数据教程


结论
如果你想在GridView中一次只针对一个单元格进行编辑,那么这个方法将会对你有所帮助。


译者注:事件验证(EventValidation)。出于安全目的,此功能验证回发或回调事件的参数是否来源于最初呈现这些事件的服务器控件。如果数据有效并且是预期的,则使用ClientScriptManager.RegisterForEventValidation方法来注册回发或回调数据以进行验证。

posted @ 2007-05-18 00:34 诸葛依驰 阅读(117) | 评论 (0)编辑 收藏

GridView控件不允许你插入新记录。 本文中我将举例说明快速解决这个问题的方法。


介绍
几个月前我写了一篇文章,是讲述一个允许你在DataGrid里添加一条新记录的技巧。 GridView控件不允许你插入新记录。 这种情况下开发人员经常使用如下的技术增加新记录:

    ·他们在GridView的下面放置一个DetailsView控件。 用户可以通过DetailsView增加新记录,然后这条新记录就会显示在GridView里。
    ·他们通过一个超级链接使用户连接到另一个使用DetailsView增加新记录的web form。 一旦记录被添加后就会返回之前的页。

这些方法都有它们自己的缺点。 第一种方法占用了太多的屏幕空间,即使你增加的只是很少的记录。 所以它不是“主要用于编辑,偶尔增加记录”情况下的好的选择。 第二种选择需要额外创建一个web form,因为来回导航会需要向服务器发送更多的请求。 本文中我将举例说明快速解决这个问题的方法。


解决方案
GridView控件提供了一个被称作Empty Data Template的模板。 当GridView里没有数据显示的时候这个模板就会显示出来。 一般在没有数据显示的时候,这个模板会被用于显示一个给出示给用户的状态信息。 但是,你也可以为了别的目的而是用它。 本例中,你将使用它来给GridView增加新的记录。

新建一个Web Form示例
开始先在Visual Studio中新建一个web站点。 拖拽一个SQL数据源控件并配置它以从Northwind数据库的Customers表中选择出CustomerID、CompanyName、ContactName和Country列。


确保选择了“高级”按钮,并且选中“生成INSERT、UPDATE和DELETE语句”复选框。


现在,在你的web form里添加一个GridView控件,设置它的DataSourceID属性为SqlDataSource1。 启用这个GridView的编辑、删除和分页。 在GridView的智能标签中选择“编辑列…”选项。


在GridView中增加一个ButtonField,并设置它的CommandName属性为Insert。 用户通过单击插入按钮来增加新的记录。


现在右键单击GridView选择编辑模板 – Empty Data Template菜单选项。 拖拽DetailsView控件到Empty Data Template内,设置它的DataSourceID属性为SqlDataSource1。


同时设置它的DefaultMode属性为Insert。 当Empty Data Template显示的时候,DetailsView将会做好插入记录之前的准备。

现在来到web form的后置代码中写出GridView的RowCommand事件处理的代码,出示如下:
protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
    
if (e.CommandName == "Insert")
    
{
        GridView1.DataSourceID 
= "";
        GridView1.DataBind();
    }

}

这里我们检查了GridViewCommandEventArgs的CommandName是否是“Insert”。 如果我们设置了GridView的DataSourceID属性为空,然后调用GridView的DataBind()方法的话, 那么GridView将不会有任何数据,从而显示Empty Data Template。

现在我们来处理DetailsView控件的ItemInserted事件。 当DetailsView成功的插入了一条新记录的时候,这个ItemInserted事件就会被触发。 在ItemInserted事件内写出如下代码:
protected void DetailsView1_ItemInserted(object sender, DetailsViewInsertedEventArgs e)
{
    GridView1.DataSourceID 
= "SqlDataSource1";
    GridView1.DataBind();
}

这里我们再次设置了GridView的DataSourceID属性为SqlDataSource1,然后再次绑定它。 这样GridView就可以显示出最新插入的记录。





总结
GridView控件不允许你插入新的记录。 但是,通过它的Empty Data Template的帮助和DetailsView控件,你就可以有一个插入新记录的非常棒的方法。 用这种方法你可以节省屏幕空间,也不需要再用额外的页了。
下面的截图显示了我们的web form

posted @ 2007-05-18 00:31 诸葛依驰 阅读(121) | 评论 (0)编辑 收藏

介绍
在2005年9月我写了关于在asp.net 2.0里使用ajax的5篇系列文章。那几篇文章告诉了大家如何在asp.net 2.0中使用ajax。虽然使用ajax可以改善程序的相应速度,以及减少回发数据,但它需要相当多的客户端脚本才能带到我们所期望的结果。现在asp.net ajax在有同样功能的情况下,减少了很多代码。这篇文章里,我将用一个例子“hello world”,向大家介绍asp.net ajax。在未来的几个月内你将会看到本系列文章的更多内容。


asp.net ajax概述
微软把自己的ajax实现命名为asp.net ajax。微软已经有了一个开发web站点的asp.net平台,不要怀疑,你可以非常简单的在这个平台上增加ajax开发环境。今天人们关注ajax的主要原因有:
    ·用户响应
    ·减少回发数据
    ·丰富的用户体验

在传统的web站点中,用户提交数据后需要等待,直到页面完成数据回发并相应结果。这意味着用户需要等待更长的时间。而在ajax中,页面的处理本质上来说是异步的。自然,web页也就能更快的响应用户的操作。

在传统的web应用程序中,web页经常要频繁的将数据回发到服务器,即使只是一小部分需要改变也不例外。这导致了需要更多的网络流量,以及更长的实现来显示页面。而在ajax中只是这个页面的一小部分才刷新,从而避免了整个页面的数据都回发至服务器。这自然改善了性能和用户体验。

asp.net提供了令人印象深刻的诸如Grids和Lists之类的服务器控件。但是,一些UI效果最好使用客户端代码来实现。如菜单、进度条、有自动完成功能的文本框、拖拽、提示框、对话框就是最好的例子。asp.net ajax提供了一个控件似的用法来实现。(更多的稍后讲)


asp.net ajax架构
全部的asp.net ajax由两部分组成:
    ·服务端组件
    ·客户端组件

注意上面说的“组件”这个词就是指一些二进制和脚本之类的东西,没有别的意思。

服务端组件
服务端组件包括:
    ·服务器控件
    ·web服务
    ·服务器控件扩展

asp.net ajax允许你在你的应用程序中使用服务器控件来完成ajax的一些功能。最值得注意的控件是ScriptManager和UpdatePanel。ScriptManager控件包含了所有脚本资源,任何web页,如果想使用ajax就必须引入ScriptManager控件。UpdatePanel控件允许你在整个页中局部刷新某一部分。你可以认为它是一个可以把任何web服务器控件赋予ajax功能的控件。

asp.net 2.0中的Membership和Profile是asp.net中服务端的功能。很幸运,asp.net ajax提供了一套web服务,可以让你在客户端中使用这些特性。例如,你可以使用客户端脚本来检查用户是否通过验证。

asp.net ajax也允许你开发自己的ajax服务器控件。这些控件也能有客户端行为,也能根据你的需求提供丰富的自定义功能。


客户端组件
asp.net ajax客户端组件由javascript脚本库组成。这些脚本库全部是面向对象的javascript并且相对于传统的javascript功能上有了很大的增强。例如,传统的javascript中你需要使用document.getElementById()方法来访问页中的html标记。而使用了ajax的客户端类库后,你可以将这些标记升级为控件,如Label,Button控件等。asp.net ajax客户端组件的另一个好处就是它不依赖于某一中浏览器,而是可以在几乎所有流行的浏览器中工作,如IE,FireFox,Safari等。

注意:
上面提及的客户端组件的一些部分现在已经被称作“asp.net ajax futures”分离出来了,然而,它仍然是整个客户端组件的一部分


asp.net ajax control toolkit
asp.net ajax control toolkit是一个有着丰富功能的ajax控件的集合,你可以在你的应用程序中使用它们。它也提供了一个SDK,使你也可以开发自己的控件。这些控件包括CollapsiblePanel,ConfirmButton,HoverMenu和ModalPopup。


开发一个简单的ajax程序
为了开发这个程序,你需要在你的机器上安装asp.net ajax 1.0 rc。让我们开始新建一个web站点。注意,当你安装了asp.net ajax之后,则会出现一个新的名字为“asp.net ajax enabled web site”的模板。下图出示新建web站点的对话框的所有模板。


我们并不是必须要使用这个模板。如果你不使用它的话,你需要手动作一些工作,比如新建一个web.config文件,引用System.Extensions程序集。这个程序集包括了asp.net ajax的核心功能。

如果你打开了默认web页,你会发现代码中已经有了一个ScriptManager控件。拖拽一个Label控件到你的web窗体上,再拖拽两个UpdaetPanel控件和一个UpdateProgress控件到你的web窗体上。注意,这些控件在你的工具箱的ajax extensions选项卡里。

拖拽一个Button控件和一个Label控件到第一个UpdatePanel控件里。再拖拽一个Label控件和一个Timer控件到第二个UpdatePanel控件里。设置Timer控件的Interval属性为3000毫秒。最后,拖拽一个Label控件到UpdateProgress控件里,并设置它的Text属性为“Wait... Server is processing your request...”。

在你的Page_Load事件中添加如下代码:
protected void Page_Load(object sender, EventArgs e)
{    
    Label2.Text 
= "Time Stamp : " + DateTime.Now.ToString();
}
这段代码比较简单,它设置了Label控件的Text属性为一个字符串加上当前时间。现在,我们接着写第一个UpdatePanel控件里的按钮的单击事件的代码。

protected void Button1_Click(object sender, EventArgs e)

    System.Threading.Thread.Sleep(
3000); 
    Label1.Text 
= "Time Stamp : " + DateTime.Now.ToString();
}
这段代码设置了让程序3秒后执行,并给Label控件赋值为当前时间。最后,我们写一段Timer控件的Tick事件的代码。

protected void Timer1_Tick(object sender, EventArgs e)

    Label4.Text 
= "Timer is ticking : " + DateTime.Now.ToString();
}
Tick事件在每经过一个Interval属性所设置的间隔时间后都被触发。这段代码给Lable控件赋值为当前时间。

现在设置你的UpdateProgress控件的AssociatedUpdatePanelID属性为你的第一个UpdatePanel控件的ID。这个UpdateProcess控件将显示一段处理文字,用来告诉用户其所关联的UpdatePanel控件正在被更新。


本文结束。你已经开发了一个有ajax功能的web窗体。运行这个web,你将会看到如下一些效果:
    ·当你单击第一个UpdatePanel控件里的按钮时,则仅仅在这个UpdatePanel控件里的Label控件的值有所改变。其他Label控件的值并没有改变,这意味着仅仅在UpdatePanel区域的控件进行了刷新。
    ·当你单击第一个UpdatePanel控件里的按钮时,那个UpdateProgress控件显示了一段信息用来说明刷新还没有完成。
    ·在第二个UpdatePanel控件内的Label控件会每隔3秒自动的刷新一次。

下面这个图显示了运行这个web窗体后的结果


posted @ 2007-05-18 00:22 诸葛依驰 阅读(74) | 评论 (0)编辑 收藏

     摘要: 介绍尽管AJAX是种客户端技术,但实际上的开发过程,它经常要调用一个服务器端的过程。通常,网站上的数据是存放在一个关系型数据库中,为了让AJAX更有用处,处理服务器端数据需要一种简单可靠的方法。幸运的是,ASP.NET AJAX提供了一种有效的基础架构来做这件事情,浏览器和服务器在Internet上可以进行AJAX通信。自然而然,Web Service在数据传输和客户端/服务器之间的一般通信方面可...  阅读全文

posted @ 2007-05-18 00:21 诸葛依驰 阅读(178) | 评论 (0)编辑 收藏

介绍
ASP.NET AJAX可以使你的web应用程序具有更丰富的功能和更多的用户响应。 本文中,我将演示如何通过ASP.NET AJAX的帮助,给像GridView这样的数据绑定控件的数据行增加popup提示框。

初看这个需求后,你可能会想到使用AJAX Control Toolkit来实现这个功能。 因为AJAX Control ToolKit里包含一个悬浮菜单控件(HoverMenu)。 但是,如果菜单是动态读取的话,你就不能使用这个控件了。 一个HoverMenu Extender仅能被附加到一个目标控件。 我们可以想象一下,如果你有一个GridView,它里面有一个HyperLinkField类型的列。 当用户的鼠标经过这个HyperLink的时候,你希望弹出一个Popup提示框来显示该数据行的详细信息。 此时,使用AJAX Control Toolkit就不能达到我们的要求了。 本文中,我将图文结合的演示如何完成这样的功能。


提示框的图例
在开讲之前让我们先来看一看这个提示框是如何显现的。 请看下图:


上图演示了一个内含GridView控件的Web窗体。 这个GridView控件由一个HyperLinkField类型的列构成。 当你的鼠标浮动到任何超链上的时候,就会弹出一个提示框,用来显示改数据行的更详细的信息。 这段通过提示框显示的描述文本是从数据库中动态读取的,也就是说它不是静态文本。

现在就让我们开始开发这个提示框吧!

首先新建一个名为AJAXTooltip的ASP.NET AJAX-Enabled Web Site。



创建数据库
为了实现本示例的功能,你需要创建一个数据库,该数据库内有一个名为Menus的表。 右键单击App_Data文件夹,选择“添加新项…”。 然后添加一个名为Database.mdf的SQL数据库。


在服务器资源浏览器中创建一个名为Menus的表。 其表结构如下:


MenuID列是关键字,它是每一条菜单的唯一ID。 Text列保存着用来在浏览器中显示的菜单项的文本。 NavigateUrl列为单击该菜单项后应当链接到的URL。 最后的TooltipText列保存的是当鼠标经过菜单项后所显示的详细文本。

建完表后,再在表中插入一些数据,这样就会给之后测试你的web程序时提供方便。


创建Web Service
ASP.NET AJAX允许你通过客户端脚本调用web services。 在我们的这个例子中就使用了这项技术。 首先在你的web程序中新建一个web service(WebService.asmx),并在其内添加一个web method。代码如下:
[WebMethod]
public string GetToolTipText(int menuid) 
{
    
string strConn = ConfigurationManager.ConnectionStrings["connstr"].ConnectionString;
    SqlConnection cnn 
= new SqlConnection(strConn);
    
    cnn.Open();
    
    SqlCommand cmd 
= new SqlCommand();
    cmd.Connection 
= cnn;
    cmd.CommandText 
= "select tooltiptext from menus where menuid=@id";
    
    SqlParameter p 
= new SqlParameter("@id", menuid);
    cmd.Parameters.Add(p);
    
    
object obj = cmd.ExecuteScalar();
    
    cnn.Close();
    
    
return obj.ToString();
}

其中的GetToolTipText()方法需要一个菜单ID作为参数,然后返回提示框文本。 这段代码首先使用ConfigurationManager类从web.config中获取数据库连接字符串。 然后创建一个SqlConnection和一个SqlCommand对象。 最后,使用SqlCommand类的ExecuteScalar()方法,根据菜单ID获得相应的提示框文本。

数据库连接字符串保存在web.config中的<connectionStrings>节点下。代码如下:
<connectionStrings>
    
<add name="connstr" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\Database.mdf;Integrated Security=True;User Instance=True" providerName="System.Data.SqlClient" />
</connectionStrings>

注意Database.mdf文件的路径使用的是AttachDbFilename属性。 用这种方法就会使App_Data文件夹(DataDirectory)中的数据库附加到SQL Server Express上。

到此之前都和以往开发web service是一样的。 但是,这个web service是从客户端脚本调用的。 也就是说,客户端脚本为了调用这个web service需要由一个代理。 我们可以给这个web service增加一个[ScriptService]属性来实现这个特性。 该属性在System.Script.Services命名空间内。 该命名空间在System.Web.Extensions程序集中。 [ScriptService]属性必须像下面这样应用到web service类中。
[ScriptService]
public class WebService : System.Web.Services.WebService

这样就完成了我们的web service


开发Web Form
现在打开默认的web form – Default.aspx – 确保其内有ScriptManager控件的实例。 拖拽一个SQL数据源控件到页上,并配置它,以使它可以从Menus表中读取全部记录。


接下来,拖拽一个GridView控件进来并设置它的DataSourceID属性为SqlDataSource1。 继续设置这个GridView控件,使它有一个类型为HyperLinkField的列。 然后如下设置该HyperLinkField列的属性:


指定DataNavigateUrlFields属性为一个用逗号分隔的字段列表,其中所有字段的值都可以作用于URL中。 DataNavigateUrlFormatString属性指向格式化后的URL。 因为我们的Menus表中的NavigateUrl列保存的就是URL,所以我们不需要做任何格式化的工作。 因此DataNavigateUrlFormatString属性只包含一个站位符 – {0}。 在运行时,NavigateUrl列的真实值将会替代{0}。 最后,DataTextField属性的值为超链所显示的文本。

在我们如此设置了GridView控件之后,再拖拽一个Panel控件到页上。 设置这个Panel控件的BorderStyle属性为Solid,BorderColor属性为#FF8000,BackColor属性为Yellow。 这个Panel控件是用来显示提示框的。

最后,我们需要使用ScriptManager控件添加一个指向到我们的web service的引用。 如下图所示,定位到ScriptManager的Services属性,然后添加一个指向到我们的web service的引用即可。


创建AJAX类
ASP.NET AJAX给客户端脚本增加一些面向对象的特性。 为了使用这些特性,我们需要开发一个名为ToolTip的类。 这个ToolTip类是用来显示提示框的,我们首先要隐藏它,然后调用我们的web service。 ToolTip类的全部代码如下:
<script type="text/javascript">
Type.registerNamespace(
"Demo");

Demo.ToolTip
=function(panelid)
{
  
this._panelid=panelid;
  
this.x=0;
  
this.y=0;
}

        
Demo.ToolTip.prototype
=
{
  get_PanelID:
function()
  
{
    
return this._panelid;
  }
,
            
  set_PanelID:
function(panelid)
  
{
    
this._panelid=panelid;
  }
,
            
  BeginShowToolTip:
function(event,menuid)
  
{
    WebService.GetToolTipText(menuid,
this.
    EndShowToolTip,
this.OnError,this.OnTimeOut);
    
this.x=event.clientX + 10;
    
this.y=event.clientY + 10;
  }
,
            
  EndShowToolTip:
function(result)
  
{
    
var pnl=$get(tooltip.get_PanelID());
    
if(pnl.innerText!=null)
    
{
      pnl.innerText
=result;
    }

    
else
    
{
      pnl.textContent
=result;
    }

  pnl.style.visibility
="visible";
  pnl.style.display
="inline";
  pnl.style.position
="absolute";
  pnl.style.left
= tooltip.x + "px";
  pnl.style.top
= tooltip.y + "px";
  }
,
            
  HideToolTip:
function()
  
{
    
var pnl=$get(this.get_PanelID());
    pnl.style.visibility
="hidden";
    pnl.style.display
="none";
  }
,
            
  OnError:
function(result)
  
{
    alert(result.get_message());
  }
,         
           
  OnTimeOut:
function(result)
  
{
    alert(result);
  }

}

        
Demo.ToolTip.registerClass(
"Demo.ToolTip");
</script>

我们需要把上面的这段脚本放到ScriptManager标记之后。 一般来说,你应该把它放到</form>标签之后。

这段代码首先使用Type类的registerNamespace()方法注册了一个名为Demo的命名空间。

然后创建了一个名为ToolTip的类。 这个ToolTip类的构造函数需要一个用来显示提示框的Panel的ID作为参数。 这个Panel的ID存储在一个名为_panelid的私有变量中。 另外,构造函数内还声明两个私有变量 – (x 和 y) – 它们用来保存鼠标的坐标。

在ToolTip类的原型中定义了一些属性和方法。 getter和setter方法用来读取和设置PanelID这个属性。 PanelID这个属性非常简单,就是设置和返回变量_panelid而已。

BeginShowToolTip()方法用来调用web service的GetToolTipText()方法。 它需要两个参数 - (event和menuid)。 这两个参数所提供的信息分别是当前的JavaScript事件和需要显示的提示框的菜单项的ID。 其内部会调用web service的GetToolTipText()方法。 注意,WebService会为真实的web service生成一个客户端代理。 GetToolTipText()方法的第1个参数是menuid。 第2、3、4个参数分别是执行成功、失败、超时后所调用的方法。 最后,变量x和y被设置为鼠标当前的位置。 为了确保弹出框不会显示在鼠标下面,所以给x和y坐标分别加上10个像素的偏移量。 你也可以根据不同的需求调整这个偏移量。 当用户的鼠标经过HyperLinkField列的超链上的时候,就会调用这个BeginShowToolTip()方法。

一旦web service返回了提示框的文本就会调用EndShowToolTip()方法。 web service的返回值就是该方法的result参数。 就下来的代码通过设置Panel的visibility、position、left和top属性来显示它自己。 注意,为了使我们的这个类能在IE和FireFox中工作,必须要保证innerText属性是有效的。

HideToolTip()方法会在鼠标离开超链后被调用,它会通过设置Panel的CSS属性来隐藏掉Panel。

OnError()和OnTimeout()方法会以弹出窗口的方式来显示相应的错误信息。

最后,用我们刚创建好的这个ToolTip类的registerClass()方法将ToolTip类注册到ASP.NET AJAX的客户端框架。

现在,将如下这段脚本添加到web form的<head>节点中。
<script type="text/javascript">
var tooltip=null;    
function pageLoad()
{
tooltip
=new Demo.ToolTip("Panel1");
tooltip.HideToolTip();
}

</script>

这段脚本中有一个名为pageLoad()的函数。 当该网页在浏览器中加载的时候,这个函数会被ASP.NET AJAX框架自动地调用。 在这个函数内部首先会创建一个ToolTip类的实例, 然后调用ToolTip类的HideToolTip()方法来隐藏掉Panel。


附加上JavaScript事件处理器
我们的GridView控件所包括的数据行是依靠于数据库中的Menus表中的记录的。 为了使用户的鼠标在经过任何超链上的时候都调用BeginShowToolTip()方法,我们需要在GridView的RowDataBound事件内写一些代码。 其全部内容如下:
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
    
if (e.Row.RowType == DataControlRowType.DataRow)
    
{
        HyperLink hl 
= e.Row.Cells[0].Controls[0as HyperLink;
        
int menuid = Convert.ToInt32(GridView1.DataKeys[e.Row.RowIndex].Value);
        hl.Attributes.Add(
"onmouseover""tooltip.BeginShowToolTip(event," + menuid + ")");
        hl.Attributes.Add(
"onmouseout""tooltip.HideToolTip()");
    }

}

GridView的每一行,包括HeaderRow和FooterRow都会触发RowDataBound事件。 所以我们首先要检查当前行是否是DataRow,也就是说,行中必须包括实际的数据值。 如果是数据行,那么就使用Cell中的控件集合来得到HyperLink控件。 菜单ID可以通过GridView的DataKeys集合来获取。 最后,使用HyperLink控件的Attributes集合来增加名为onmouseover和onmouseout的客户端事件处理器。 onmouseover对应ToolTip类的BeginShowToolTip()方法,onmouseout对应ToolTip的HideToolTip()方法。

以上就是本文的全部内容。 你现在就可以运行一下这个web form,看看我们做的这个提示框的效果。


总结
ASP.NET AJAX允许你通过客户端脚本调用web services。 这个特性可以带给我们很多不同以往的实现。 在本例中,我们给GridView的数据行创建了一个动态的提示框。 ASP.NET AJAX extensions可以让我们以面向对象的方式来编写JavaScript,它将使我们的代码变得更健壮、更清晰。


作者:Bipin Joshi
Email:http://www.dotnetbips.com/contact.aspx
简介:Bipin Joshi是DotNetBips.com的管理员。他是http://www.binaryintellect.com/的发起人,这个公司提供.NET framwork的培训和咨询服务。他在印度孟买为开发者提供培训。他也是微软的MVP(ASP.Net)和ASPInsiders的会员。

posted @ 2007-05-18 00:11 诸葛依驰 阅读(103) | 评论 (0)编辑 收藏


2007年5月15日

http://chs.gotdotnet.com/quickstart/default.aspx

posted @ 2007-05-15 20:13 诸葛依驰 阅读(26) | 评论 (0)编辑 收藏

很不错的Ajax技术学习站点(针对我我自己而言哈)
http://ajax.schwarz-interactive.de

posted @ 2007-05-15 20:12 诸葛依驰 阅读(23) | 评论 (0)编辑 收藏

//递归算法--遍历指定目录下的子目录及文件(C#.net),希望有用,顺带数据入库 

  private void button1_Click(object sender, System.EventArgs e)
  {
   Conn.Open();

   displayItems(textBox1.Text);
   //MessageBox.Show(dirs.Length.ToString());
   Conn.Close();
  }
 /*这里是递归算法的遍历程序部分*/
  private void displayItems(string path)
  {
   try
   {
    DirectoryInfo di=new DirectoryInfo(path);
    FileInfo[] SubFiles=di.GetFiles();

    FileSystemInfo[] dirs = di.GetDirectories();

      foreach(FileInfo fileNext in SubFiles)
      {
     /*-----------------------------------------------------------------------------------------------------*/
       string path_total=path + "/" +fileNext.ToString();
       int path_start=path_total.IndexOf("/")+1;
       int path_end=path_total.LastIndexOf("/");
       string path_name;
       if(path_start-1==path_end)
       {
         path_name="";
       }
       else
       {
         path_name=path.Substring(path_start,path_end-path_start);
       }
       switch(path_start.ToString())
       {
        case "....":
         break;
       }
     /*-----------------------------------------------------------------------------------------------------*/
       string sql="insert into pic_data(pic_name,pic_path,pic_time) values(’"+ fileNext.ToString() +"’,’"+ path_name +"’,’"+ DateTime.Now.ToString() +"’)";
       SqlCommand Cmd=new SqlCommand(sql,Conn);
       if(checkBox_insertdb.Checked==true)
       Cmd.ExecuteNonQuery();

       richTextBox1.Text=richTextBox1.Text + "\r\n" + path + "/" +fileNext.ToString() + "  ("+sql+")";
      }
    foreach(DirectoryInfo diNext in dirs)
    {
     displayItems(path + "/" + diNext.ToString());
    }
   }
   catch(Exception ex)
   {
    richTextBox1.Text=ex.Message +"\r\n"+ richTextBox1.Text;
   }

  } 
 }