ASP.NET自定义控件复杂属性声明持久性浅析

转自:http://www.cnblogs.com/tedzhao/archive/2008/05/10/1190772.html

在自定义控件的开发过程中,我们经常要给控件添加一些复杂类型的属性。利用声明持久性(Declarative Persistence)可使得页面开发人员能够让页面开发人员在ASP.NET页面中,声明性地设置这些复杂属性值,而无需编写任何C#或者VB.NET代码。

参见下面的例子:

  • GridView的DataKeyNames属性,其数据类型是string[]:
<asp:GridView ID="GridView1" runat="server" DataKeyNames="ID, Title, Author">
</asp:GridView>

GridView的RowStyle属性,其数据类型是System.Web.UI.WebControls.TableItemStyle:

<asp:GridView ID="GridView1" runat="server">
    <RowStyle BackColor="Red" ForeColor="Black"/>
</asp:GridView>

GridView的Columns属性,其数据类型是:System.Web.UI.WebControls.DataControlFieldCollection

<asp:GridView ID="GridView1" runat="server" DataSourceID="ObjectDataSource1" >
    <Columns>
         <asp:BoundField DataField="Title" HeaderText="Title" SortExpression="Title" />
         <asp:BoundField DataField="ID" HeaderText="ID" SortExpression="ID" />
    </Columns>
</asp:GridView>

GridView的PagerTemplate属性, 其数据类型是System.Web.UI.ITemplate:

<asp:GridView ID="GridView1" runat="server">
    <PagerTemplate>
         <div>
             <span>Pager Template</span>
         </div>
    </PagerTemplate>
</asp:GridView>

那如何才能实现在ASPX中声明性地设置这些复杂属性哪?

下面我将逐一讲述这些属性背后的故事,本文的重点不在于如何维护这些属性的状态,而是如何由ASPX Markup到复杂属性的构建。

一、由ASPX Markup 到C# 或者VB.NET class

1.ASP.NET管道

ASPPipe

对于ASPX页面的请求,ASP.NET管道的目标是找到一个完全代表被请求页面的托管类,如果该类不存在,则即时创建并且编译。

ASP.NET页面由标记(Markup)和代码(Codebehind)文件组成,整个页面编译过程包含两个主要步骤:首先将ASPX Markup装换成一个适合ASP.NET类层次结构的C#或者VB.NET临时类,我们可以从ASP.NET的临时文件夹中找到包含该类的文件;其次将该临时类编译成一个程序集,最后将得到的程序集装入托管该应用程序的AppDomain中。

对于特定的请求,HttpApplication对象从config文件中获取处理对象以服务该请求,通过下面的代码片断我们可以看出.aspx资源与PageHandlerFactory相关联。 在ASP.NET管道中PageHandlerFactory对象将创建当前请求页面的实例,随后将请求交由该页面处理。

<httpHandlers>
     <add path="*.aspx" verb="*" type="System.Web.UI.PageHandlerFactory" validate="True"/>
     <add path="*.ashx" verb="*" type="System.Web.UI.SimpleHandlerFactory" validate="True"/>
</httpHandlers>

2.PageHandlerFactory

PageHandlerFactory负责找到包含请求页面类的程序集,如果该程序集还没有被创建,则即时动态创建。请求页面类是通过解析ASPX资源的Markup代码创建的,并且存放在ASP.NET的临时文件夹%AppData%"Local"Temp"Temporary ASP.NET Files中。

3.ControlBuilder

而ControlBuilder类就是负责将ASPX Markup声明解析成为ASP.NET Server控件,通常页面上的每个控件都有一个默认的 ControlBuilder 类相关联。在ASPX页面解析过程中,ASP.NET 页框架首先会生成与页面控件树对应的 ControlBuilder 对象树,然后 ControlBuilder 树用于生成页代码并创建控件树。

ControlBuilder 定义了如何解析控件标记中的内容的,我们可以通过自定义ControlBuilder类来重写此默认行为。

在页面解析过程中,ControlBuilder将会检查ASP.NET Server控件是否标示了ParseChildren(true) Attribute。如果被标示则该控件内部嵌套的子节点将被解析为控件的子属性,否则该节点会被解析为ASP.NET Server控件,并添加到原控件的Controls集合,关于该Attribute见下一节。

二、相关的Attributes

1.ParseChildrenAttribute

ParseChildrenAttribute应用于自定义控件类上,该Attribute将会告诉ASPX页面解析器如何解析自定义控件内部的嵌套节点。

下表详细的描述了ParseChildrenAttribute的用法:

Attribute Usage

描述

ParseChildren(true)

          嵌套的子节点必须对应着当前控件的属性,如果找不到对应属性将会产生一个解析错误。另外在当前控件的Tag内部也不允许任何文字节点。

          例子:Repeater 以及其他数据绑定控件。

ParseChildrenAttribute(true, "PropertyName")

          当前控件必须包含一个Public的属性,属性名等同于参数PropertyName。该属性应该是一个集合类的数据类型。

          而嵌套的字节点必须对应着该属性的子Element.

          例子:HtmlTable, HtmlTableRow控件。

          ParseChildrenAttribute(false)

          ParseChildrenAttribute(false, "PropertyName")

          ParseChildrenAttribute is not applied to the control.

          嵌套的子节点必须是ASP.NET 服务器控件。页面解析器会根据该节点创建一个子控件,然后在当前控件上调用IParserAccessor.AddParsedSubObject方法,该方法的默认实现是将解析到的子控件添加到当前控件的Controls集合。

          任何Literal文字节点将被创建为LiteralControl的示例。

          例子:Panel控件。

ParseChildrenAttribute (Type childControlType)

          嵌套的子节点必须是指定的ASP.NET 服务器控件类型。

          例子:MultiView控件。

WebControl类上已经被ParseChildrenAttribute(True)标示了,所以每个直接或者间接从WebControl派生的控件都会默认支持内部属性声明持久性。

在下面的例子中RowStyle节点将被解析为GridView控件的子属性:

<asp:GridView ID="GridView1" runat="server">
    <RowStyle BackColor="Red" ForeColor="Black"/>
</asp:GridView>

2.  PersistChildrenAttribute

PersistChildrenAttribute应用于自定义控件类上,是一个DesignTime的Attribute。用于指定是否将自定义控件内部的嵌套节点解析为子控件,True将意味着解析该节点为控件。

WebControl类上已经被PersistChildrenAttribute (False)标示了,而Panel类则被PersistChildrenAttribute (True)标示。

示例:

[ParseChildren(false), PersistChildren(true)]
public class MyControl : WebControl
{ }

在设计时添加一个Button控件到MyControl中:

<cc1:MyControl2 ID="MyControl21" runat="server" BorderStyle="Dotted" Height="56px" Width="349px">
 <asp:Button ID="Button2" runat="server" Text="Button" /> 
</cc1:MyControl2>

这个时候用户可以在VS IDE的Design View中选中子Button控件,而如果MyControl被PersistChildrenAttribute (False)标示的话,子控件Button不能被选中。

3.  PersistenceModeAttribute

PersistenceModeAttribute应用在ASP.NET 服务器控件属性上,是一个DesignTime的Attribute,用于指定用如何在设计时将ASP.NET Server控件属性(Property)保存到ASP.NET 页面

或者说在 ASPX Mrakup中以何种方式声明该属性。

PersistenceMode.InnerProperty则指定属性在 ASP.NET 服务器控件中保持为嵌套标记。

三、再看例子

1. GridView的DataKeyNames属性,其数据类型是string[]:

<asp:GridView ID="GridView1" runat="server" DataKeyNames="ID, Title, Author">
</asp:GridView>

默认情况下ASP.NET页面解析引擎会将ASPX Markup中赋予DataKeyNames属性的值直接设置到该属性上,由于该属性的数据类型为string[],直接设置将会失败。

那GridView做了些什么哪,见下面的代码片断:

[TypeConverter(typeof(StringArrayConverter))]
public virtual string[] DataKeyNames
{get; set;} 

也就是说通过给属性添加特定的TypeConvertor来实现属性的设置,在上面的例子中StringArrayConvter将string装化为string[]后,设置到DataKeyNames属性上。

2. GridView的RowStyle属性,其数据类型是TableRowStyle:

<asp:GridView ID="GridView1" runat="server">
    <RowStyle BackColor="Red" ForeColor="Black"/>
</asp:GridView>

由于GridView控件已经标示了ParseChildrenAttribute(True),所以其内部嵌套的节点将被解析为自身的属性。

另外RowStyle属性也添加了PersistenceModeAttribute来指定如何生成ASPX Markup代码。

[PersistenceMode(PersistenceMode.InnerProperty)]
public TableItemStyle RowStyle
{get;} 
3. GridView的Columns属性,其数据类型是DataFieldCollection:
<asp:GridView ID="GridView1" runat="server" DataSourceID="ObjectDataSource1" >
    <Columns>
         <asp:BoundField DataField="Title" HeaderText="Title" SortExpression="Title" />
         <asp:BoundField DataField="ID" HeaderText="ID" SortExpression="ID" />
    </Columns>
</asp:GridView> 

ASP.NET页面是如何来解析上面的一段代码哪?首先Columns节点将被解析为GridView的属性,可是Columns内部的子节点是如何被解析并添加到Columns集合中去的哪?

另外在VS IDE Source View中准备添加Columns属性的子节点代码的时候,为什么VS IDE会帮我们列出所有可实例化的子类型?Intiligence

让我们来看一下Columns属性的数据类型:DataControlFieldCollection.

ASP.NET页面解析器在解析控件属性的时候,如果发现该属性实现了IList接口,解析完成该属性的子节点后,会去调用该属性的Add方法来添加这些子Element。

另外在设计时也会通过该属性数据类型的Item子属性获取可以实例化的子Element类型,并且通过智能提示表现出来。

也就是说这些集合类属性必须实现IList接口才可以实现属性的声明持久化。

看一下上面示例的Markup代码对应的C#代码,注意代码行16,17。

 1[System.Diagnostics.DebuggerNonUserCodeAttribute()]
 2private global::System.Web.UI.WebControls.BoundField @__BuildControl__control23()
 3{
 4      global::System.Web.UI.WebControls.BoundField @__ctrl;
 5      @__ctrl = new global::System.Web.UI.WebControls.BoundField();
 6      @__ctrl.DataField = "ID";
 7      @__ctrl.HeaderText = "ID";
 8      @__ctrl.SortExpression = "ID";
 9      return @__ctrl;
10}
11 
12[System.Diagnostics.DebuggerNonUserCodeAttribute()]
13private void @__BuildControl__control22(System.Web.UI.WebControls.DataControlFieldCollection @__ctrl)
14{
15      global::System.Web.UI.WebControls.BoundField @__ctrl1;
16      @__ctrl1 = this.@__BuildControl__control23();
17      @__ctrl.Add(@__ctrl1);
18}
19 
20[System.Diagnostics.DebuggerNonUserCodeAttribute()]
21private global::System.Web.UI.WebControls.GridView @__BuildControlGridView1()
22{
23      global::System.Web.UI.WebControls.GridView @__ctrl;
24      @__ctrl = new global::System.Web.UI.WebControls.GridView();
25      this.GridView1 = @__ctrl;
26      @__ctrl.ApplyStyleSheetSkin(this);
27      @__ctrl.ID = "GridView1";
28 
29      this.@__BuildControl__control22(@__ctrl.Columns);
30 
31      return @__ctrl;
32}

参照上面说的几点我们就可以写出自定义的集合类属性的声明持久化。

当然了这只是实现了ASPX到CS,我们还需要给集合类以及子Element添加关于状态管理的代码(实现IStateManager接口)才可以在实际项目中使用,这一点我就不再赘述了。

4. GridView的PagerTemplate属性,其数据类型是ITemplate:

其实ITemplate节点内部就是一个控件集合,TemplateBuilder负责将该Tag构建成为一个控件组。

在运行时我们通过ITemplate接口的InstantiateIn方法将一个实例化的Template放到指定的Container中去。

全文完。

 

posted @ 2009年3月5日 19:43 | 醉了醉了 阅读 (0) | 评论 (0) | 编辑 | 目录 [ Control ]

星期五 2009年02月27日

 jQuery入门[6]-动画

jQuery直接各种动画,常见的被封装成各种方法,如show()/hide()/slideDown()/fadeIn()等等,参见:Effects
最灵活的则属于animate( params, [duration], [easing], [callback] )方法,参见:animate
其中params为动画的运行结果,可以为各种样式属性,jQuery将在duration指定的时间内,将对象的当前状态渐变为params参数指定的值。如:

    $("#go").click(function(){
      $("#block").animate({ 
        width: "70%",
        opacity: 0.4,
        marginLeft: "0.6in",
        fontSize: "3em", 
        borderWidth: "10px"
      }, 1500 );
    });

params也可以是一些相对数据:

    $("#right").click(function(){
      $(".block").animate({"left": "+=50px"}, "slow");
    });
    $("#left").click(function(){
      $(".block").animate({"left": "-=50px"}, "slow");
    });

通过stop()函数可将对象再在执行的动画暂停。选择符:animated可以判断对象是否处在动画运行状态。
以下为来自官网的一个例子:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
                    "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script>
  $(document).ready(function(){
    $("#show").click(function () {
var n = $("div").queue("fx");
      $("span").text("Queue length is: " + n.length);
    });
function runIt() {
      $("div").show("slow");
      $("div").animate({left:'+=200'},2000);
      $("div").slideToggle(1000);
      $("div").slideToggle("fast");
      $("div").animate({left:'-=200'},1500);
      $("div").hide("slow");
      $("div").show(1200);
      $("div").slideUp("normal", runIt);
    }
    runIt();
  });
</script>
<style>
  div { margin:3px; width:40px; height:40px;
        position:absolute; left:0px; top:30px;
        background:green; display:none; }
  div.newcolor { background:blue; }
  span { color:red; }
</style>
</head>
<body>
<button id="show">Show Length of Queue</button>
<span></span>
<div></div>
</body>
</html>

效果为不断变化的一个方块,因为最后一个动画$("div").slideUp("normal", runIt)执行后又 调用runIt方法,所以动画不断循环。

 

posted @ 2009年2月27日 16:26 | 醉了醉了 阅读 (0) | 评论 (0) | 编辑 | 目录 [ JQuery ]

 jQuery入门[5]-AJAX

jQuery为AJAX提供了非常丰富的支持,参见Ajax
其中最基本当属$ajax(),通过不同的参数,这个方法可以录活支持各种AJAX应用场景。如:

$.ajax({
url: "test.html",
cache: false,
success: function(html){
$("#results").append(html);
}
});
完整参数列表参见:options
当然,常用的应该是这些:
  • load()--直接将AJAX请求结果作为jQuery对象内容
  • $.get()--用get方式请求
  • $.post()--用post方式提交
  • ajaxStart()/ajaxComplete()/ajaxError()……--全局的ajax事件响应

DEMO:
建一个GenericHandler作AJAX请求服务端:CubeHandler.ashx

<%@ WebHandler Language="C#" Class="CubeHandler" %>
using System;
using System.Web;
public class CubeHandler : IHttpHandler {
public void ProcessRequest (HttpContext context) {
        context.Response.ContentType = "text/plain";
int number = 0;
int.TryParse(context.Request.Params["number"], out number);
        context.Response.StatusCode = 200;
        context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
        context.Response.Write(string.Format("{0} cubed is {1}",number,Math.Pow(number, 3)));
    }
public bool IsReusable {
get {
return true;
        }
    }
}

因为用的是Request.Params,所以这个handler能同时支持get和post,

<!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>
<title>ajax</title>
<script src="../scripts/jquery-1.2.3.intellisense.js" type="text/javascript"></script>
<script type="text/javascript">
        $(function(){
//设置指示器
            $('#divIndicator').ajaxStart(function(){$(this).show()})
                            .ajaxSuccess(function(){$(this).hide()})
                            .ajaxError(function(msg){$(this).hide();alert(msg);});
//ajax get 请求
            $('#btnGetCubeInGet').click(function(){
var number = $('#txtNumber').val();
                $.get('CubeHandler.ashx?number='+number,function(result){
                    alert(result);
                });
            });
//ajax post 提交
            $('#btnGetCubeInPost').click(function(){
var number = $('#txtNumber').val();
                $.get('CubeHandler.ashx',{'number':number},function(result){
                    alert(result);
                });
            });
        });
</script>
<style type="text/css">
        .indicator
{
            color: #FF0000;
            position: absolute;
            top: 0px;
            right: 0px;
            display: none;
}
</style>
</head>
<body>
<div id="divIndicator" class="indicator">
<img src="indicator.gif" />loading</div>
    plz input a number:<input id="txtNumber" />
<input type="button" id="btnGetCubeInGet" value="Get cube(get)" />
<input type="button" id="btnGetCubeInPost" value="Get cube(post)" />
</body>
</html>

点击按钮后的效果:

 

posted @ 2009年2月27日 16:25 | 醉了醉了 阅读 (0) | 评论 (0) | 编辑 | 目录 [ JQuery ]

 jQuery入门[4]-链式代码

jQuery另一个很令人惬意的地方是,一般的代码都是一行一行写,jQuery的代码可以一串一串写。
这一点,在前面的文章中已经介绍过了。
直接来一个Demo:

<!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>
<title>chainning code</title>
<script src="../scripts/jquery-1.2.3.intellisense.js" type="text/javascript"></script>
<script type="text/javascript">
        $(function(){
//添加四个按钮
            $('<input type="button" value="click me"/><input type="button" value="triggle click me"/><input type="button" value="detach handler"/><input type="button" value="show/hide text"/>').appendTo($('body'));
//找出所有按钮
            $('input[type="button"]')
                .eq(0)//找到第一个按钮
                    .click(function(){
                        alert('you clicked me!');
                    })
                .end().eq(1)//返回所有按钮,再找到第二个
                    .click(function(){
                        $('input[type="button"]:eq(0)').trigger('click');
                    })
                .end().eq(2)//返回所有按钮,再找到第三个
                    .click(function(){
                        $('input[type="button"]:eq(0)').unbind('click');
                    })
                .end().eq(3)//返回所有按钮,再找到第四个
                    .toggle(function(){
                        $('.panel').hide('slow');
                    },function(){
                        $('.panel').show('slow');
                    });
        });
</script>
<style type="text/css">
        .panel
{
            padding: 20px;
            background-color: #000066;
            color: #FFFFFF;
            font-weight: bold;
            width: 200px;
            height: 50px;
}
</style>
</head>
<body>
<div class="panel">welcome to jQuery!</div>
</body>
</html>


现在,链式代码已经成为jQuery非常流行的一个特点了,在使用链条方式写代码时,可能会用到eq()/filter()……(reference:http://docs.jquery.com/Traversing)等方法变化jQuery对象的对应范围,然后,又可以用end()函数将范围复原到原来的状况。
需要注意的是,有几个函数并不返回jQuery对象,所以链条就不能继续下去,比如get()就不能像eq()那样用。

 

posted @ 2009年2月27日 16:25 | 醉了醉了 阅读 (0) | 评论 (0) | 编辑 | 目录 [ JQuery ]

 jQuery入门[3]-事件

jQuery对事件的支持主要包括:

  • bind()--为事件绑定处理程序,如:
        $("p").bind("mouseenter mouseleave", function(e){
    $(this).toggleClass("over");
    });
  • unbind()--注销绑定在事件上的处理程序,如:$(document).unbind('ready');,如不给参数,则清除所有事件处理程序。
    $("#unbind").click(function () {
    $("#theone").unbind('click', aClick);
    });
  • trigger()--触发某类事件。
    $("button:first").trigger('click');
  • triggerHandler()--触发某类事件,但不触发默认的事件处理逻辑,比如a的定向。
    $("input").triggerHandler("focus");
  • one()--为事件绑定只能被触发一次的处理程序。
        $("div").one("click", function(){
    });
  • ready()/click()/change()/toggle(fn,fn)/dblclick()……各种常规事件的快捷方式,xxx(fn)为绑定处理程序,xxx()为触发事件

jQuery 1.2的事件支持命名空间,
  $("div").bind("click", function(){ alert("hello"); });
$("div").bind("click.plugin", function(){ alert("goodbye"); });
$("div").trigger("click!"); // alert("hello") only

DEMO:

<!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>
<title>Events</title>
<script src="../scripts/jquery-1.2.3.intellisense.js" type="text/javascript"></script>
<style type="text/css">
        textarea
{
            height: 118px;
            width: 280px;
}
</style>
<script type="text/javascript">
        $(function(){
            $('textarea').bind('propertychange',function(){
                $('#result').html($('textarea').val())
            }
            ).bind('change',function(){
                alert($('textarea').val());
            });
        });
</script>
</head>
<body>
<textarea></textarea>
<div id='result'></div>
</body>
</html>

运行效果如下:

 

posted @ 2009年2月27日 16:23 | 醉了醉了 阅读 (0) | 评论 (0) | 编辑 | 目录 [ JQuery ]

 jQuery入门[2]-选择器

jQuery之所以令人爱不释手,在于其强大的选择器表达式令DOM操作优雅而艺术。
jQuery的选择符支持id,tagName,css1-3 expressions,XPath,参见:http://docs.jquery.com/Selectors
DEMO:

<!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>
<title>Selector</title>
<script src="../scripts/jquery-1.2.3.intellisense.js" type="text/javascript"></script>
</head>
<body>
<input value="1" /> + 
<input value="2" />
<input type="button" value="=" />
<label>&nbsp;</label>
<script type="text/javascript">
        $("input[type='button']").click(function(){
var i = 0;
            $("input[type='text']").each(function(){
                i += parseInt($(this).val());
            });
            $('label').text(i);
        });
        $('input:lt(2)')
            .add('label')
            .css('border','none')
            .css('borderBottom','solid 1px navy')
            .css({'width':'30px'});
</script>
</body>
</html>

运行效果如下:

代码分解:
$("input[type='button']")用于找到type属性为button的input元素(此为CSS表达式,IE7才开始支持,所以在IE6中通常用jQuery的这种表达式代替CSS代码设置样式)。click()函数为button添加click事件处理函数。
在button_click时,$("input[type='text']")找出所有输入框,each()函数遍历找出来的数组中的对象的值,相加后设到label中。
        $('input:lt(2)')
            .add('label')
两行代码意为:所有input中的前面两个(lt表示序号小于)再加上label对象合并成一个jQuery对象。
            .css('border','none')
            .css('borderBottom','solid 1px navy')
            .css({'width':'30px'});
以上三行代码都是针对之前的jQuery对象设置CSS样式,如果一次需要设置多个CSS值,可用另一种形式,如:
            .css({'border':'none','borderBottom':'solid 1px navy','width':'30px'});
css()函数如果只传一个字符串参数,则为取样式值,比如css('color')为取得当前jQuery对象的样式属性color的值。jQuery对象有多种这样的函数,比如,val('')为设value,val()为取value,text('text')为设innerText,text()为取得innerText,此外还有html(),用于操作innerHTML,而click(fn)/click(),change(fn)/change()……系统函数则为事件的设置处理函数与触发事件。
由于多数jQuery对象的方法仍返回当前jQuery,所以jQuery代码通常写成一串串的,如上面的
            .css('border','none')
            .css('borderBottom','solid 1px navy')
            .css({'width':'30px'});
,而不需要不断重复定位对象,这是jQuery的链式特点,后面文章还会有补充。

 

posted @ 2009年2月27日 16:23 | 醉了醉了 阅读 (0) | 评论 (0) | 编辑 | 目录 [ JQuery ]

 JQuery

CSS 的杠杆知识,以 CSS 选择器定位页面元素机制为基础,jQuery 继承了表现文档结构
的简洁(terse)而易读(legible)的方法。由于做专业的 web 开发的必备知识是 CSS 语法,
jQuery 为想在页面加上行为的设计师提供了一个入口。

总是以集合工作,当我们通知 jQuery,查找所有带类collapsible的元素并隐藏它,不必循环
每个返回的元素。相反,如 .hide()方法被设计工作在对象集上而不是单独元素。这种技术
被称为隐含秩代(implicit iteration),意味着很多循环结构变得不必要了。
允许在一行有多个动作,为了避免过度使用临时的变量或浪费的重复,jQuery 在它的大多
数方法中使用了一个称为链式的编程模式,这 意味着在对象的很多操作的结果都这个对象的
本身,为下一个动作做准备以应用它。

 

$() 工厂函数
无论我们想在 jQuery 中使用哪种选择器类型(CSS, XPath 或者自定义),我们总会以美
元符号和圆括($())号开始。
在第一章提到,$() 函数不需要做for循环来访问一组元素,放在圆括号里面的东西都会自动
的进行循环并作为 jQuery 对象存储。我们可把任何东西放到 $() 函数的圆括号里面。包含
一些更变通的实例:
A tag name: $('p') gets all paragraphs in the document.
An ID: $('#someid')
gets the single element in the document that has the corresponding someid
第11 页
ID.
A class: $('.someclass')
gets all elements in the document that have a class of someclass.

 

CSS 选择器
jQuery 支持大部分的选择器, 包括在 World Wide Web Consortium 网站上列出的
http://www.w3.org/Style/CSS/#specs) CSS 规范 1 到 3。这个支持允许开发者增强他们的
网站,而不必担心有些浏览器(特别是 IE6 或者更低)可能不理解高级选择器,只有这些
浏览器支持 JavaScript 就可以了。

 

XPath 选择器
XML 路径语言(XPath)是一种在 XML 文档中指定不同元素或者它们的值的语言,它与
CSS 在 HTML 文档中指定元素的方法相类似。jQ uery 库支持支持一套基本的 XPath 选择
器,如果我们想的话,我们可以让它与 CSS 选择器一起工作。使用 jQuery,不管文档的
类型如何,我们都可使用 XPath 和 CSS 选择器。
当谈到属性选择器时,jQuery 使用 XPath 指定属性的约定,属性通过在方括号里用 @ 符
第14 页
号作为前缀指定,而不是用 CSS 的方法,它缺乏灵活性。例如,选择所有带有 title 属性
的链接,我们会这样写:
$('a[@title]')
XPath 语法允许方括号不使用 @ 的另一个用法来指定一个不包含其它元素的元素。例如,
我们可用下面的选择器表达式来得到所有包含一个 ol 元素的 div 元素:
$('div[ol]')
样式化链接
属性选择器接收类正则表达式的语法来指定一个字符串的开始(^)与结束($)。它们也可用
asterisk(*) 来指示一个字符串的任意位置。
举例来说,我 们想显示带不同文本颜色的不同种链接,我 们首页在我们的样式表中定义样式:
a {
color: #00f; /* make plain links blue */
a.mailto {
color: #f00; /* make email links red */
}
a.pdflink {
color: #090; /* make PDF links green */
}
a.mysite {
textdecoration:
none; /* remove internal link underline */
borderbottom:
1px dotted #00f;
}
然后,我们用加入三个类(mailto、pdflink 和 mysite),并用 jQuery 将它们加到适合的链
接。
为了得到所有的 email 链接,我 们创建一个选择器来查找所有的 anchor 元素 (a) ,选 择器
用以 mailto 开头 (^="mailto:") 的 href 属性 ([@href]),如下:
$(document).ready(function() {
$('a[@href^="mailto:"]').addClass('mailto');
});
为了得到所有连接到 PDF 文件的链接,我们使用美元符号($)不是用脱字符号(^),为了得
到所有以 .pdf 结尾的 href 属性的链接,代码如下:
$(document).ready(function() {
$('a[@href^="mailto:"]').addClass('mailto');
$('a[@href$=".pdf"]').addClass('pdflink');
});
最后,为了得到内部链接,例如,在 mysite.com 连接到其它页面,我们用星号:
$(document).ready(function() {
第15 页
$('a[@href^="mailto:"]').addClass('mailto');
$('a[@href$=".pdf"]').addClass('pdflink');
$('a[@href*="mysite.com"]').addClass('mysite');
});
这里,mysite.com 在 href 的值出可出现在任何地方。如果我们也想在 mysite.com 里包含
链接到任何子域名,那么这是特别重要的。
应用到三种链接的三个类,我们应该下面的样式应用:
用虚线下划线的蓝色文本:
<a href="http://www.mysite.com/asyoulikeit/">As You Like It</a>
Green text: <a href="hamlet.pdf">Hamlet</a>
Red text: <a href="mailto:henryiv@king.co.uk">email</a>

 

posted @ 2009年2月27日 16:22 | 醉了醉了 阅读 (0) | 评论 (0) | 编辑 | 目录 [ JQuery ]

 jQuery入门[1]-构造函数

jQuery入门[1]-构造函数
jQuery入门[2]-选择器
jQuery入门[3]-事件
jQuery入门[4]-链式代码
jQuery入门[5]-AJAX
jQuery入门[6]-动画
JQuery优点
◦体积小(v1.2.3 15kb)
◦丰富的DOM选择器(CSS1-3 + XPath) ◦跨浏览器(IE6,FF,Safari,Opera)
◦链式代码
◦强大的事件、样式支持
◦强大的AJAX功能
◦易于扩展,插件丰富
jQuery的构造函数接收四种类型的参数:

  • jQuery(expression,context)
  • jQuery(html)
  • jQuery(elements)
  • jQuery(fn)

第一种根据表达式(ID,DOM元素名,CSS表达式,XPath表达式)找出文档中的元素,并组装成一个jQuery对象返回。
DEMO:

<!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>
<title>jQuery basic</title>
<style type="text/css">
        .selected 
{
            background-color:Yellow;
}
</style>
<script src="../scripts/jquery-1.2.3.intellisense.js" type="text/javascript"></script>
</head>
<body>
<h3>jQuery构造函数</h3>
<ul>
<li>jQuery(expression,context)</li>
<li>jQuery(html)</li>
<li>jQuery(elements)</li>
<li>jQuery(fn)</li>
</ul>
<script type="text/javascript">
</script>
</body>
</html>

将以下jQuery代码加入文末的脚本块中:

jQuery("ul>li:first").addClass("selected");

页面运行效果如下:

其中jQuery()可替换为快捷方式$(),如果$被其它对象占用,可使用jQuery.noConflict()函数取消快捷方式。
"ul>li:first"中ul>li表示所有位于ul下的li元素(为CSS表达式,XPath方式可用ul/li),:first表示其中的第一个。addClass()为jQuery对象用来添加CSS样式类的函数,相反的函数为removeClass()。
再加入以下代码:

$('ul').append($('<li>new item</li>'));

运行效果如下:

其中$('<li>new item</li>')将其中的字符串转换为DOM对象,然后通过append()函数加入ul对象的最后。
接下来:

        $(document).ready(function(){
            $('ul').css('color','red');
        });

则效果如:

jQuery构造函数中还可以真接传入DOM对象,如document,或jQuery对象(当然就没什么意义)。ready()函数为document添加事件处理函数,将ul的颜色设为红色。
$(document).ready()由于应用场景众多,所以可以直接用$(fn)来代替,fn表示处理函数。(ready处理函数貌似在文档内容载入完成后执行,无需等待相关其它图片等资源载入完成,所以比load事件要更早执行,对于这点,没有具体证实)

        $(function(){
            alert('welcome to jQuery');
        });

以上代码的效果是页面一载入,就弹出一个对话框。

 

posted @ 2009年2月27日 16:22 | 醉了醉了 阅读 (0) | 评论 (0) | 编辑 | 目录 [ JQuery ]

星期日 2009年02月15日

 LINQ体验(7)——LINQ to SQL语句之Group By/Having和Exists/In/Any/All/Contains

我们继续讲解LINQ to SQL语句,这篇我们来讨论Group By/Having操作符和Exists/In/Any/All/Contains操作符。

Group By/Having操作符

适用场景:分组数据,为我们查找数据缩小范围。

说明:分配并返回对传入参数进行分组操作后的可枚举对象。分组;延迟

1.简单形式:

var q =
    from p in db.Products
    group p by p.CategoryID into g
    select g;

语句描述:使用Group By按CategoryID划分产品。

说明:from p in db.Products 表示从表中将产品对象取出来。group p by p.CategoryID into g表示对p按CategoryID字段归类。其结果命名为g,一旦重新命名,p的作用域就结束了,所以,最后select时,只能select g。当然,也不必重新命名可以这样写:

var q =
    from p in db.Products
    group p by p.CategoryID;

我们用示意图表示:

GroupBy分组统计示意图

如果想遍历某类别中所有记录,这样:

foreach (var gp in q)
{
    if (gp.Key == 2)
    {
        foreach (var item in gp)
        {
            //do something
        }
    }
}

2.Select匿名类:

var q =
    from p in db.Products
    group p by p.CategoryID into g
    select new { CategoryID = g.Key, g }; 

说明:在这句LINQ语句中,有2个property:CategoryID和g。这个匿名类,其实质是对返回结果集重新进行了包装。把g的property封装成一个完整的分组。如下图所示:

GroupBy分组匿名类示意图

如果想遍历某匿名类中所有记录,要这么做:

foreach (var gp in q)
{
    if (gp.CategoryID == 2)
    {
        foreach (var item in gp.g)
        {
            //do something
        }
    }
}

3.最大值

var q =
    from p in db.Products
    group p by p.CategoryID into g
    select new {
        g.Key,
        MaxPrice = g.Max(p => p.UnitPrice)
    };

语句描述:使用Group By和Max查找每个CategoryID的最高单价。

说明:先按CategoryID归类,判断各个分类产品中单价最大的Products。取出CategoryID值,并把UnitPrice值赋给MaxPrice。

4.最小值

var q =
    from p in db.Products
    group p by p.CategoryID into g
    select new {
        g.Key,
        MinPrice = g.Min(p => p.UnitPrice)
    };

语句描述:使用Group By和Min查找每个CategoryID的最低单价。

说明:先按CategoryID归类,判断各个分类产品中单价最小的Products。取出CategoryID值,并把UnitPrice值赋给MinPrice。

5.平均值

var q =
    from p in db.Products
    group p by p.CategoryID into g
    select new {
        g.Key,
        AveragePrice = g.Average(p => p.UnitPrice)
    };

语句描述:使用Group By和Average得到每个CategoryID的平均单价。

说明:先按CategoryID归类,取出CategoryID值和各个分类产品中单价的平均值。

6.求和

var q =
    from p in db.Products
    group p by p.CategoryID into g
    select new {
        g.Key,
        TotalPrice = g.Sum(p => p.UnitPrice)
    };

语句描述:使用Group By和Sum得到每个CategoryID 的单价总计。

说明:先按CategoryID归类,取出CategoryID值和各个分类产品中单价的总和。

7.计数

var q =
    from p in db.Products
    group p by p.CategoryID into g
    select new {
        g.Key,
        NumProducts = g.Count()
    };

语句描述:使用Group By和Count得到每个CategoryID中产品的数量。

说明:先按CategoryID归类,取出CategoryID值和各个分类产品的数量。

8.带条件计数

var q =
    from p in db.Products
    group p by p.CategoryID into g
    select new {
        g.Key,
        NumProducts = g.Count(p => p.Discontinued)
    };

语句描述:使用Group By和Count得到每个CategoryID中断货产品的数量。

说明:先按CategoryID归类,取出CategoryID值和各个分类产品的断货数量。 Count函数里,使用了Lambda表达式,Lambda表达式中的p,代表这个组里的一个元素或对象,即某一个产品。

9.Where限制

var q =
    from p in db.Products
    group p by p.CategoryID into g
    where g.Count() >= 10
    select new {
        g.Key,
        ProductCount = g.Count()
    };

语句描述:根据产品的―ID分组,查询产品数量大于10的ID和产品数量。这个示例在Group By子句后使用Where子句查找所有至少有10种产品的类别。

说明:在翻译成SQL语句时,在最外层嵌套了Where条件。

10.多列(Multiple Columns)

var categories =
    from p in db.Products
    group p by new
    {
        p.CategoryID,
        p.SupplierID
    }
        into g
        select new
            {
                g.Key,
                g
            };

语句描述:使用Group By按CategoryID和SupplierID将产品分组。

说明:既按产品的分类,又按供应商分类。在by后面,new出来一个匿名类。这里,Key其实质是一个类的对象,Key包含两个Property:CategoryID、SupplierID。用g.Key.CategoryID可以遍历CategoryID的值。

11.表达式(Expression)

var categories =
    from p in db.Products
    group p by new { Criterion = p.UnitPrice > 10 } into g
    select g;

语句描述:使用Group By返回两个产品序列。第一个序列包含单价大于10的产品。第二个序列包含单价小于或等于10的产品。

说明:按产品单价是否大于10分类。其结果分为两类,大于的是一类,小于及等于为另一类。

Exists/In/Any/All/Contains操作符

适用场景:用于判断集合中元素,进一步缩小范围。

Any

说明:用于判断集合中是否有元素满足某一条件;不延迟。(若条件为空,则集合只要不为空就返回True,否则为False)。有2种形式,分别为简单形式和带条件形式。

1.简单形式:

仅返回没有订单的客户:

var q =
    from c in db.Customers
    where !c.Orders.Any()
    select c;

生成SQL语句为:

SELECT [t0].[CustomerID], [t0].[CompanyName], [t0].[ContactName],
[t0].[ContactTitle], [t0].[Address], [t0].[City], [t0].[Region],
[t0].[PostalCode], [t0].[Country], [t0].[Phone], [t0].[Fax]
FROM [dbo].[Customers] AS [t0]
WHERE NOT (EXISTS(
    SELECT NULL AS [EMPTY] FROM [dbo].[Orders] AS [t1]
    WHERE [t1].[CustomerID] = [t0].[CustomerID]
   ))

2.带条件形式:

仅返回至少有一种产品断货的类别:

var q =
    from c in db.Categories
    where c.Products.Any(p => p.Discontinued)
    select c;

生成SQL语句为:

SELECT [t0].[CategoryID], [t0].[CategoryName], [t0].[Description],
[t0].[Picture] FROM [dbo].[Categories] AS [t0]
WHERE EXISTS(
    SELECT NULL AS [EMPTY] FROM [dbo].[Products] AS [t1]
    WHERE ([t1].[Discontinued] = 1) AND 
    ([t1].[CategoryID] = [t0].[CategoryID])
    )

All

说明:用于判断集合中所有元素是否都满足某一条件;不延迟

1.带条件形式

var q =
    from c in db.Customers
    where c.Orders.All(o => o.ShipCity == c.City)
    select c;

语句描述:这个例子返回所有订单都运往其所在城市的客户或未下订单的客户。

Contains

说明:用于判断集合中是否包含有某一元素;不延迟。它是对两个序列进行连接操作的。

string[] customerID_Set =
    new string[] { "AROUT", "BOLID", "FISSA" };
var q = (
    from o in db.Orders
    where customerID_Set.Contains(o.CustomerID)
    select o).ToList();

语句描述:查找"AROUT", "BOLID" 和 "FISSA" 这三个客户的订单。先定义了一个数组,在LINQ to SQL中使用Contains,数组中包含了所有的CustomerID,即返回结果中,所有的CustomerID都在这个集合内。也就是in。 你也可以把数组的定义放在LINQ to SQL语句里。比如:

var q = (
    from o in db.Orders
    where (
    new string[] { "AROUT", "BOLID", "FISSA" })
    .Contains(o.CustomerID)
    select o).ToList();

Not Contains则取反:

var q = (
    from o in db.Orders
    where !(
    new string[] { "AROUT", "BOLID", "FISSA" })
    .Contains(o.CustomerID)
    select o).ToList();

1.包含一个对象:

var order = (from o in db.Orders
             where o.OrderID == 10248
             select o).First();
var q = db.Customers.Where(p => p.Orders.Contains(order)).ToList();
foreach (var cust in q)
{
    foreach (var ord in cust.Orders)
    {
        //do something
    }
}

语句描述:这个例子使用Contain查找哪个客户包含OrderID为10248的订单。

2.包含多个值:

string[] cities = 
    new string[] { "Seattle", "London", "Vancouver", "Paris" };
var q = db.Customers.Where(p=>cities.Contains(p.City)).ToList();

语句描述:这个例子使用Contains查找其所在城市为西雅图、伦敦、巴黎或温哥华的客户。

总结一下这篇我们说明了以下语句:

Group By/Having
分组数据;延迟

Any
用于判断集合中是否有元素满足某一条件;不延迟

All
用于判断集合中所有元素是否都满足某一条件;不延迟

Contains
用于判断集合中是否包含有某一元素;不延迟

本系列链接:LINQ体验系列文章导航

LINQ推荐资源

LINQ专题:http://kb.cnblogs.com/zt/linq/ 关于LINQ方方面面的入门、进阶、深入的文章。
LINQ小组:http://space.cnblogs.com/group/linq/ 学习中遇到什么问题或者疑问提问的好地方。

作者:李永京YJingLee's Blog
出处:http://lyj.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

posted @ 2009-03-15 09:02  俩醒叁醉  阅读(714)  评论(0编辑  收藏  举报