[SQL]SQL Server中小心使用@@identity

mikel阅读(936)

@@identity的作用是返回最后插入的标识值,所以有很多朋友使用它来获取插入数据后的标识符。
但有一点是需要注意的,@@identity返回的是最后的标识符,所以,要想正确的返回插入后的标识符,那么就必须保证,你想要的结果是最后的标识符,否则就会隐藏bug。
仔细阅读@@identity的注释:

注释

在一条 Insert、Select INTO 或大容量复制语句完成后,@@IDENTITY 中包含此语句产生的最后的标识值。若此语句没有影响任何有标识列的表,则 @@IDENTITY 返回 NULL。若插入了多个行,则会产生多个标识值,@@IDENTITY 返回最后产生的标识值。如果此语句激发一个或多个执行产生标识值的插入操作的触发器,则语句执行后立即调用 @@IDENTITY 将返回由触发器产生的最后的标识值。若 Insert 或 Select INTO 语句失败或大容量复制失败,或事务被回滚,则 @@IDENTITY 值不会还原为以前的设置。

在返回插入到表的 @@IDENTITY 列的最后一个值方面,@@IDENTITY、SCOPE_IDENTITY 和 IDENT_CURRENT 函数类似。

@@IDENTITY 和 SCOPE_IDENTITY 将返回在当前会话的所有表中生成的最后一个标识值。但是,SCOPE_IDENTITY 只在当前作用域内返回值,而 @@IDENTITY 不限于特定的作用域。

例如:创建表t和t1

drop table t
drop table t1

create table t 
(
id 
int identity(1,1)primary key,
name 
char(10)
)
create table t1 
(
id 
int identity(10,1)primary key,
name 
char(10)
)

创建表t的触发器,作用是当有新的数据插入到表t时,t1也相应的插入一条数据。

触发器
create trigger trigger_insert on t
for insert
as
insert into t1(name) select name from inserted

然后,执行执行如下语句:

insert into t(name) values('me')
select @@identity

这时候,你期望得到的结果是1,但其实返回的结果却是10。
使用时,这就是你要注意的问题啦。
论坛支持:www.help-doc.com
相关知识可以参考:http://www.help-doc.com/17/ShowForum.aspx
SQL Server 2005的帮助中的内容:

SCOPE_IDENTITY、IDENT_CURRENT 和 @@IDENTITY 是相似的函数,因为它们都返回插入到标识列中的值。

IDENT_CURRENT 不受作用域和会话的限制,而受限于指定的表。IDENT_CURRENT 返回为任何会话和作用域中的特定表所生成的值。有关详细信息,请参阅 IDENT_CURRENT (Transact-SQL)

SCOPE_IDENTITY 和 @@IDENTITY 返回在当前会话中的任何表内所生成的最后一个标识值。但是,SCOPE_IDENTITY 只返回插入到当前作用域中的值;@@IDENTITY 不受限于特定的作用域。

例如,有两个表 T1 和 T2,并且在 T1 上定义了 Insert 触发器。当将某行插入 T1 时,触发器被激发,并在 T2 中插入一行。 该方案演示了两个作用域:在 T1 上的插入,以及在 T2 通过触发器的插入。

假设 T1 和 T2 都有标识列,@@IDENTITY 和 SCOPE_IDENTITY 将在 T1 上的 Insert 语句的最后返回不同的值。@@IDENTITY 将返回在当前会话中的任何作用域内插入的最后一个标识列的值。这是在 T2 中插入的值。SCOPE_IDENTITY() 将返回在 T1 中插入的 IDENTITY 值。这是在同一个作用域内发生的最后的插入。如果在任何 Insert 语句作用于作用域中的标识列之前调用 SCOPE_IDENTITY() 函数,则该函数将返回空值。

如果语句和事务失败,它们会更改表的当前标识,从而使标识列中的值出现不连贯现象。即使未提交试图向表中插入值的事务,也永远无法回滚标识值。例如,如果因 IGNORE_DUP_KEY 冲突而导致 Insert 语句失败,表的当前标识值仍然会增加。

[C#]ADO.Net执行存储过程

mikel阅读(719)

存储过程————————————————————————————————


Create PROCEDURE dbo.sptestList

@strOptions varchar(
200= NULL,
@intID 
int = NULL,
@strOut nvarchar(
50= NULL   OUTPUT

AS

SET NOCOUNT ON
不返回影响的行数
SET ANSI_WARNINGS OFF
不返警告

/* 信息列表 */
IF @strOptions
='LIST' BEGIN

Select
   id,
   name,
   subject,
   Source
FROM test 
Where ID 
<=@intID

SET @strOut 
= @strOut + 'out'
RETURN 
50
END
GO


————————————————————————-

//StoredProcedure 调用存储过程
    private void BindData2()
    
{
        SQLConnection MyConn 
= new SQLConnection("Server=.;Database=mine;User=sa;Pwd=123;");
        MyConn.Open();

        SQLCommand MyCmd 
= new SqlCommand();
        MyCmd.Connection 
= MyConn;
        MyCmd.CommandType 
= CommandType.StoredProcedure;
        MyCmd.CommandText 
= "sptestList";
        
string strOut = "in—";
        
int intReturn = 0;

        SqlParameter[] paras 
= 
            
{
                
new SqlParameter("@strOptions","LIST"),
                
new SqlParameter("@intID",100),
                
//长度一定需要
                new SqlParameter("@strOut",SqlDbType.VarChar,200),
                
//用来存返回值,ReturnValue随便写都可以,但类型一定是整型(因为数据库只能返回整型)
                new SqlParameter("ReturnValue",SqlDbType.Int)
            
            }
;
      
        paras[
2].Direction = ParameterDirection.InputOutput;//设置 传入并传出
        paras[2].Value = strOut;
        paras[
3].Direction = ParameterDirection.ReturnValue;//设置 返回值


        
foreach (SqlParameter par in paras)
        
{
            MyCmd.Parameters.Add(par);
        }


        SqlDataAdapter MySda 
= new SqlDataAdapter(MyCmd);
        DataTable MyDtb 
= new DataTable();
        MySda.Fill(MyDtb);

        strOut 
= paras[2].Value.ToString();//接收传出
        intReturn = (int)paras[3].Value;//接收返回值
        Response.Write("Out=" + strOut + "; Return=" + intReturn.ToString() + "<br>");

        
this.Repeater1.DataSource = MyDtb;
        
this.Repeater1.DataBind();

        MyConn.Close();

    }


    
//SqlDataAdapter 执行查询语句
    private void BindData()
    
{
        SqlConnection MyConn 
= new SqlConnection("Server=.;Database=mine;User=sa;Pwd=123;");

        SqlCommand MyCmd 
= new SqlCommand("Select TOP 100 * FROM Test", MyConn);
        SqlDataAdapter MySda 
= new SqlDataAdapter(MyCmd);
        DataTable MyDtb 
= new DataTable();
        MySda.Fill(MyDtb);

        
this.Repeater1.DataSource = MyDtb;
        
this.Repeater1.DataBind();

    }


    
//ExecuteNonQuery 执行插入语句
    protected void FInsert()
    
{
        SqlConnection MyConn 
= new SqlConnection("Server=.;DataBase=mine;Uid=sa;Pwd=123;");

        SqlCommand MyCmd 
= new SqlCommand("Insert INTO StudentInfo(StNo,StName) VALUES(124532,'A111ww')", MyConn);
        MyConn.Open();
        
int i = MyCmd.ExecuteNonQuery();
        Response.Write(i.ToString() 
+ "<br>");
        MyConn.Close();

    }


    
//SqlDataReader
    protected void FReader()
    
{
        SqlConnection MyConn 
= new SqlConnection("Server=.;Database=mine;Uid=sa;Pwd=123");
        MyConn.Open();
        SqlCommand MyCmd 
= new SqlCommand("Select Top 10 StNo,StName from StudentInfo", MyConn);

        SqlDataReader MyRead 
= MyCmd.ExecuteReader();

        
while (MyRead.Read())
        
{
            Response.Write(MyRead[
"StNo"].ToString() + "" + MyRead["StName"].ToString() + "<br>");
        }


        MyConn.Close();

    }


    
//ExecuteScalar
    protected void FScalar()
    
{

        
//<appSettings>
        
//<add key ="SqlConnStr" value="Server=.;DataBase=mine;Uid=sa;Pwd=123"/>
        
//</appSettings>
        
//SqlConnection MyConn = new SqlConnection(ConfigurationManager.AppSettings["SqlConnStr"]);
        SqlConnection MyConn = new SqlConnection("Server=.;Database=mine;Uid=sa;Pwd=123");
        MyConn.Open();
        SqlCommand MyCmd 
= new SqlCommand("Select Total=Count(1) from StudentInfo", MyConn);

        
string MyS = MyCmd.ExecuteScalar().ToString();

        Response.Write(MyS 
+ "<br>");

        MyConn.Close();

    }


//连接Access
    private void BindAccess()
    
{
        
//<add key="AccessConString" value="App_Data/db.mdb" />
        string strAccessPath = ConfigurationManager.AppSettings["AccessConString"].ToString();
        OleDbConnection con 
= new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + Server.MapPath(strAccessPath));
        con.Open();
        OleDbDataAdapter oda 
= new OleDbDataAdapter("Select * From Result", con);
        DataTable Dtb 
= new DataTable();
        oda.Fill(Dtb);

        
this.Repeater1.DataSource = Dtb;
        
this.Repeater1.DataBind();

        
//———————-二—————————–
        
//string constr = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + Server.MapPath("App_Data/db.mdb");
        
//OleDbConnection con = new OleDbConnection(constr);
        
//string cmdstr = "Select * FROM Result";
        
//con.Open();
        
//OleDbCommand cmd = new OleDbCommand(cmdstr, con);
        
//OleDbDataReader dr = cmd.ExecuteReader();
    }



//OleDbCommand 执行语句
    protected void Button1_Click(object sender, EventArgs e)
    
{
        OleDbConnection con 
= new OleDbConnection("Provider=Microsoft.Jet.OleDb.4.0;Data Source="
            
+ Server.MapPath(ConfigurationManager.AppSettings["OleDbConnPathStr"]));
        con.Open();

        OleDbCommand cmd 
= new OleDbCommand("Insert Into Products(Product_Id,Title,Spec,Content) Values('ww123','成功添加01','100*1','真的成功了')", con);

        cmd.ExecuteNonQuery();

        con.Close();
        con.Dispose();

        BindData();

    }


    
//OleDbDataAdapter 读取数据
    protected void Button2_Click(object sender, EventArgs e)
    
{
        OleDbConnection con 
= new OleDbConnection("Provider=Microsoft.Jet.OleDb.4.0;Data Source="
            
+ Server.MapPath(ConfigurationManager.AppSettings["OleDbConnPathStr"]));
        con.Open();

        OleDbDataAdapter odad 
= new OleDbDataAdapter("Select * From Products Where ID=123", con);

        DataTable dtb 
= new DataTable();
        odad.Fill(dtb);

        
if (dtb.Rows.Count > 0)
        
{
            DataRow row 
= dtb.Rows[0];

            
this.Label.Text = row["ID"].ToString() + "" + row["Title"].ToString();
        }


        con.Close();
        con.Dispose();
    }


    
//OleDbCommand 执行语句(参数化)
    protected void Button3_Click(object sender, EventArgs e)
    
{
        OleDbConnection con 
= new OleDbConnection("Provider=Microsoft.Jet.OleDb.4.0;Data Source="
            
+ Server.MapPath(ConfigurationManager.AppSettings["OleDbConnPathStr"]));
        con.Open();

        OleDbCommand cmd 
= new OleDbCommand();
        cmd.Connection 
= con;
        cmd.CommandType 
= CommandType.Text;
        cmd.CommandText 
= "Insert Into Products(Product_Id,Title,Spec,Content) Values(@Product_Id,@Title,@Spec,@Content)";

        OleDbParameter[] paras 
= {
            
new OleDbParameter("@Product_Id",OleDbType.VarChar),
            
new OleDbParameter("@Title",OleDbType.VarChar),
            
new OleDbParameter("@Spec",OleDbType.VarChar),
            
new OleDbParameter("@Content",OleDbType.VarChar)
        }
;

        paras[
0].Value = "qq123";
        paras[
1].Value = "qq成功添加";
        paras[
2].Value = "10*10";
        paras[
3].Value = "qq真的成功了";

        
foreach (OleDbParameter para in paras)
        
{
            cmd.Parameters.Add(para);
        }


        cmd.ExecuteNonQuery();

        con.Close();
        con.Dispose();

        BindData();
    }

[C#]SqlCommand.ExecuteNonQuery返回值

mikel阅读(899)

当执行Update、Insert 和 Delete时,SQLHelper的ExecuteNonQuery方法能正确的返回受影响的行数,但执行Select时返回值却总是-1,今天上 MSDN查了下SQLCommand.ExecuteNonQuery方法,上边的解释是:

引用内容 引用内容
对于 Update、Insert 和 Delete 语句,返回值为该命令所影响的行数。对于所有其他类型的语句,返回值为 -1。如果发生回滚,返回值也为 -1。

那上述现象的出现就是正常的了,呵呵。
MSDN地址:http://msdn2.microsoft.com/zh-cn/library/system.data.sqlclient.sqlcommand.executenonquery(VS.80).aspx

[JQuery]JQuery事件总结

mikel阅读(753)

  很少写这些,看了1.2.3版本的改进,确实佩服,很方便.
1.绑定事件
(1)

$("p").bind("click", function(e){});

(2)

$("p").click(function() {})

2.删除事件
(1)删除特定事件

$("div").unbind("click");

(2)删除所有事件

$("div").unbind();

3.触发事件
(1)trigger方法 触发特定元素事件

$("div").trigger('click');

(2)triggerHandler方法 与trigger方法相似,但不触发浏览器默认事件,如focus事件,使用此方法,将会阻止焦点到元素上

$("input").triggerHandler("focus");

4.特殊事件
(1)one(string event,function data)
此事件只执行一次则被删除

$("p").one("click", function(){
   alert(
"test");
}
);

(2)hover(over, out)
切换mouSEOver与mouSEOut事件

$("td").hover(
   function ()
{
     $(
this).addClass("hover");
   }
,
   function ()
{
     $(
this).removeClass("hover");
   }

);

可用unbind mouSEOver与mouseout方法来删除此事件
(3)toggle(oldclick,newclick)
切换执行click事件

     $("li").toggle(
       function ()
{
         $(
this).css("list-style-type", "disc")
                .css(
"color", "blue");
       }
,
       function ()
{
         $(
this).css({"list-style-type":"", "color":""});
       }

     );

可用unbind click方法来删除此事件
5.     1.2.3版本新增功能
(1)事件命名空间(便于管理)
实际使用方面:
1.当不需要全部事件,删除特定2个以上的事件.
示例:

   $("div").bind("click.plugin",function() {} );
   $(
"div").bind("mouseover.plugin", function(){});
   $(
"div").bind("dblclick", function(){});
   $(
"button").click(function() {$("div").unbind(".plugin");   })

在事件名称后面加命名空间,在删除事件时,只需要指定命名空间即可.以上代码执行以后,dbclick仍然存在.
(2)相同事件名称,不同命名的事件执行方法
示例:

$("div").bind("click", function(){ alert("hello"); });
   $(
"div").bind("click.plugin", function(){ alert("goodbye"); });
   $(
"div").trigger("click!"); // alert("hello") only

以上trigger方法则根据事件名称来执行事件.
简单的写几句.以上的几个方法还是非常实用方便的

[原创]重复获得验证码的问题

mikel阅读(873)

验证码的页面可能由于验证码不清楚,单击需要获得新的验证码
服务器端用C#实现如下:

/// <summary>
/// 验证码类,用于生成验证码
/// </summary>
public static class ValidateCode
{
private static string Cr&#101;ateRandomCode(int codeCount)
{
string allChar = "0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,W,X,Y,Z";
string[] allCharArray = allChar.Split(&#39;,&#39;);
string randomCode = "";
int temp = -1;
Random rand = new Random();
for (int i = 0; i < codeCount; i++)
{
if (temp != -1)
{
rand = new Random(i * temp * ((int)DateTime.Now.Ticks));
}
int t = rand.Next(35);
if (temp == t)
{
return Cr&#101;ateRandomCode(codeCount);
}
temp = t;
randomCode += allCharArray&#91;t&#93;;
}
return randomCode;
}
public static MemoryStream Cr&#101;ateImage(out string checkCode)
{
//生成随机数
checkCode = Cr&#101;ateRandomCode(4);
int iwidth = (int)(checkCode.Length * 13.5);
System.Drawing.Bitmap image = new System.Drawing.Bitmap(iwidth, 20);
Graphics g = Graphics.FromImage(image);
Font f = new System.Drawing.Font("Arial", 12, System.Drawing.FontStyle.Bold);
Brush b = new System.Drawing.SolidBrush(Color.Black);
//g.FillRectangle(new System.Drawing.SolidBrush(Color.Blue),0,0,image.Width, image.Height);
g.Clear(Color.White);
g.DrawString(checkCode, f, b, 3, 3);
Pen blackPen = new Pen(Color.Black, 0);
Random rand = new Random();
for (int i = 0; i < 3; i++)
{
int y = rand.Next(image.Height);
g.DrawLine(blackPen, 0, y, image.Width, y);
}
MemoryStream ms = new MemoryStream();
image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
g.Dispose();
image.Dispose();
return ms;
}
}
&#91;/code&#93;
使用Asp.net MVC实现的Controller调用验证码的Action如下:
没有生成中间gif,jpg文件
&#91;code&#93;
/// <summary>
/// 获得验证码
/// </summary>
public void GetValidateCode()
{
try
{
//生成验证码
string validateCode;
Session["ValidateCode"] = "";
//生成验证码图片
MemoryStream ms = ValidateCode.Cr&#101;ateImage(out validateCode);
ViewData["Code"] = ms;
//保存到Session
Session["ValidateCode"] = validateCode;
Response.ClearContent();
Response.ContentType = "image/Gif";
Response.BinaryWrite(ms.ToArray());
}
catch (Exception e)
{
Response.Write("验证码生成失败!错误消息:" + e.Message);
}
}

页面代码:

<script language="javascript" type="text/javascript">
//获得验证码
function GetCode()
{
//注意后面一定要加随机数,这样<img>才能更新为新的验证码
$("#validateImg").attr("src","/user/GetValidateCode?sd="+Math.random());
}
</script>
<a id="getCode" href="javascript:GetCode();"><img  id="validateImg"  src="/user/GetValidateCode"  alt="点击获得验证码" /></a>

[C#]C#中的序列化和反序列化

mikel阅读(833)

序列化和反序列化我们可能经常会听到,其实通俗一点的解释,序列化就是把一个对象保存到一个文件或数据库字段中去,反序列化就是在适当的时候把这个文件再转化成原来的对象使用。

  我想最主要的作用有:

  1、在进程下次启动时读取上次保存的对象的信息

  2、在不同的AppDomain或进程之间传递数据

  3、在分布式应用系统中传递数据

  ……

  在C#中常见的序列化的方法主要也有三个:BinaryFormatter、SoapFormatter、XML序列化

  本文就通过一个小例子主要说说这三种方法的具体使用和异同点

  这个例子就是使用三种不同的方式把一个Book对象进行序列化和反序列化,当然这个Book类首先是可以被序列化的。至于怎么使一个类可以序列化可以参见:C#强化系列文章一:ViewState使用兼谈序列化

  Book类

  using System;

  using System.Collections;

  using System.Text;

  namespace SerializableTest

  {

  [Serializable]

  public class Book

  {

  public Book()

  {

  alBookReader = new ArrayList();

  }

  public string strBookName;

  [NonSerialized]

  public string strBookPwd;

  private string _bookID;

  public string BookID

  {

  get { return _bookID; }

  set { _bookID = value; }

  }

  public ArrayList alBookReader;

  private string _bookPrice;

  public void SetBookPrice(string price)

  {

  _bookPrice = price;

  }

  public void Write()

  {

  Console.WriteLine("Book ID:" + BookID);

  Console.WriteLine("Book Name:" + strBookName);

  Console.WriteLine("Book Password:" + strBookPwd);

  Console.WriteLine("Book Price:" + _bookPrice);

  Console.WriteLine("Book Reader:");

  for (int i = 0; i < alBookReader.Count; i++)

  {

  Console.WriteLine(alBookReader[i]); [Page]

  }

  }

  }

  }

  这个类比较简单,就是定义了一些public字段和一个可读写的属性,一个private字段,一个标记为[NonSerialized]的字段,具体会在下面的例子中体现出来

  一、BinaryFormatter序列化方式

  1、序列化,就是给Book类赋值,然后进行序列化到一个文件中

  Book book = new Book();

  book.BookID = "1";

  book.alBookReader.Add("gspring");

  book.alBookReader.Add("永春");

  book.strBookName = "C#强化";

  book.strBookPwd = "*****";

  book.SetBookPrice("50.00");

  BinarySerialize serialize = new BinarySerialize();

  serialize.Serialize(book);2、反序列化

  BinarySerialize serialize = new BinarySerialize();

  Book book = serialize.DeSerialize();

  book.Write();3、测试用的

  BinarySerialize类

  using System;

  using System.Collections.Generic;

  using System.Text;

  using System.IO;

  using System.Runtime.Serialization.Formatters.Binary;

  namespace SerializableTest

  {

  public class BinarySerialize

  {

  string strFile = "c:\book.data";

  public void Serialize(Book book)

  {

  using (FileStream fs = new FileStream(strFile, FileMode.Create))

  {

  BinaryFormatter formatter = new BinaryFormatter();

  formatter.Serialize(fs, book);

  }

  }

  public Book DeSerialize()

  {

  Book book;

  using (FileStream fs = new FileStream(strFile, FileMode.Open))

  {

  BinaryFormatter formatter = new BinaryFormatter(); [Page]

  book = (Book)formatter.Deserialize(fs);

  }

  return book;

  }

  }

  }

  主要就是调用System.Runtime.Serialization.Formatters.Binary空间下的 BinaryFormatter类进行序列化和反序列化,以缩略型二进制格式写到一个文件中去,速度比较快,而且写入后的文件已二进制保存有一定的保密效 果。

  调用反序列化后的截图如下:

  也就是说除了标记为NonSerialized的其他所有成员都能序列化

  二、SoapFormatter序列化方式

  调用序列化和反序列化的方法和上面比较类似,我就不列出来了,主要就看看SoapSerialize类

  SoapSerialize类

  using System;

  using System.Collections.Generic;

  using System.Text;

  using System.IO;

  using System.Runtime.Serialization.Formatters.Soap;

  namespace SerializableTest

  {

  public class SoapSerialize

  {

  string strFile = "c:\book.soap";

  public void Serialize(Book book)

  {

  using (FileStream fs = new FileStream(strFile, FileMode.Create))

  {

  SoapFormatter formatter = new SoapFormatter();

  formatter.Serialize(fs, book);

  }

  }

  public Book DeSerialize()

  {

  Book book;

  using (FileStream fs = new FileStream(strFile, FileMode.Open))

  {

  SoapFormatter formatter = new SoapFormatter();

  book = (Book)formatter.Deserialize(fs);

  }

  return book;

  }

  }

  }

  主要就是调用System.Runtime.Serialization.Formatters.Soap空间下的SoapFormatter 类进行序列化和反序列化,使用之前需要应用 System.Runtime.Serialization.Formatters.Soap.dll(.net自带的)

  序列化之后的文件是Soap格式的文件(简单对象访问协议(Simple Object Access Protocol,SOAP),是一种轻量的、简单的、基于XML的协议,它被设计成在WEB上交换结构化的和固化的信息。 SOAP 可以和现存的许多因特网协议和格式结合使用,包括超文本传输协议(HTTP),简单邮件传输协议(SMTP),多用途网际邮件扩充协议(MIME)。它还 支持从消息系统到远程过程调用(RPC)等大量的应用程序。SOAP使用基于XML的数据结构和超文本传输协议(HTTP)的组合定义了一个标准的方法来 使用Internet上各种不同操作环境中的分布式对象。) [Page]

  调用反序列化之后的结果和方法一相同

  三、XML序列化方式

  调用序列化和反序列化的方法和上面比较类似,我就不列出来了,主要就看看XmlSerialize类

  XmlSerialize类

  using System;

  using System.Collections.Generic;

  using System.Text;

  using System.IO;

  using System.Xml.Serialization;

  namespace SerializableTest

  {

  public class XmlSerialize

  {

  string strFile = "c:\book.xml";

  public void Serialize(Book book)

  {

  using (FileStream fs = new FileStream(strFile, FileMode.Create))

  {

  XmlSerializer formatter = new XmlSerializer(typeof(Book));

  formatter.Serialize(fs, book);

  }

  }

  public Book DeSerialize()

  {

  Book book;

  using (FileStream fs = new FileStream(strFile, FileMode.Open))

  {

  XmlSerializer formatter = new XmlSerializer(typeof(Book));

  book = (Book)formatter.Deserialize(fs);

  }

  return book;

  }

  }

  }

  从这三个测试类我们可以看出来其实三种方法的调用方式都差不多,只是具体使用的类不同

  xml序列化之后的文件就是一般的一个xml文件:

  book.xml

  <?xml version="1.0"?>

  <Book xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

  <strBookName>C#强化</strBookName>

  <strBookPwd>*****</strBookPwd>

  <alBookReader>

  <anyType xsi:type="xsd:string">gspring</anyType>

  <anyType xsi:type="xsd:string">永春</anyType>

  </alBookReader>

  <BookID>1</BookID>

  </Book>输出截图如下:

  也就是说采用xml序列化的方式只能保存public的字段和可读写的属性,对于private等类型的字段不能进行序列化

  关于循环引用:

  比如在上面的例子Book类中加入如下一个属性:

  public Book relationBook;

  在调用序列化时使用如下方法:

  Book book = new Book();

  book.BookID = "1"; [Page]

  book.alBookReader.Add("gspring");

  book.alBookReader.Add("永春");

  book.strBookName = "C#强化";

  book.strBookPwd = "*****";

  book.SetBookPrice("50.00");

  Book book2 = new Book();

  book2.BookID = "2";

  book2.alBookReader.Add("gspring");

  book2.alBookReader.Add("永春");

  book2.strBookName = ".NET强化";

  book2.strBookPwd = "*****";

  book2.SetBookPrice("40.00");

  book.relationBook = book2;

  book2.relationBook = book;

  BinarySerialize serialize = new BinarySerialize();

  serialize.Serialize(book);这样就会出现循环引用的情况,对于BinarySerialize和 SoapSerialize可以正常序列化(.NET内部进行处理了),对于XmlSerialize出现这种情况会报错:"序列化类型 SerializableTest.Book 的对象时检测到循环引用。"

[C#]C#读取Json数据

mikel阅读(946)

# //先在项目中添加System.Web.Extensions引用
# //using System.Web.Script.Serialization;
# JavaScriptSerializer serializer = new JavaScriptSerializer();
# Dictionary<string, object> json = (Dictionary<string, object>)serializer.DeserializeObject(
#     "{name: &#39;zswang&#39;, forum: &#39;c#&#39;}");
# object value;
# if (json.TryGetValue("name", out value))
#     Console.WriteLine(value); // 输出:zswang

[JQuery]JQuery Selectors

mikel阅读(726)

$() function

 

$(selector) 等价于 JQuery(selector),用来选取一组DOM Elements。返回的是一组预定义的JavaScript 对象,这些对象不仅封装了DOM element而且提供了许多有用的方法,以作用于这些elements。

使用CSS Selectors

 1. 可以使用的selectors如下表所示:

 

Selector               Description
*                         所有元素
E                         所有标签名(tag name)称为E的元素
E F                      所有标签名为F,且为标签E的子元素的元素(含孙子元素…)
E>F                     所有标签名为F,且为标签E直接子元素的元素
E+F                     所有标签名为F,且相邻兄弟元素标签名为E的元素
E~F                     所有标签名为F,且兄弟元素标签名为E的元素
E:has(F)               所有标签名为E, 且包含至少一个标签名为F元素的元素
E.C                      所有标签名为E, 且包含类名称为C的元素
E#I                      所有标签名为E, 且id为I的元素
E[A]                     所有标签名为E,且拥有属性名为A的元素,属性值任意
E[A=V]                 所有标签名为E,且拥有属性名为A,属性值为V的元素
E[A^=V]              所有标签名为E, 且属性名为A,属性值以V开始的元素
E[A$=V]              所有标签名为E,且属性名为A,属性值以V结尾的元素

E[A*=V]              所有标签名为E,且属性名为A,属性值包含V的元素

2. 使用position过滤器

可以使用的position过滤器包括:

 

Selector                             Description
:first                                   页面中第一个得到满足的元素. 如:li a:first 返回第一个 li 项下的链接
:last                                   页面中最后一个得到满足的元素。如:li a:last 返回最后一个 li 项下的链接
:first-child                           第一个子元素 如:li:first-child 返回 所有作为子元素的li 项中的第一li 元素
:last-child                            最后一个子元素. 如: li:last-child 返回 作为子元素的li 项中的最后一个 li 元素
:only-child                           返回所有没有兄弟元素的元素(这个元素只作为其它元素的子元素存在)
:nth-child(n)                        返回第n个子元素. 如:li:nth-child(2) 返回 所有作为子元素的 li 项的第二个.
:nth-child(even|odd)             返回偶数(Even) 或奇数(Odd) 子元素. 如:li:nth-child(even) 返回所有作为子元素的li项的偶数元素.

:nth-child(Xn+Y)                  返回Xn+Y计算结果的第n个子元素.如果Y为0,则被忽略. 如:li:nth-child(3n) 返回所有作为子元素的li项的每第3n个元素.
:even and :odd                    返回偶数(Even)或奇数(odd)个子元素。不同于nth-child系列,这个匹配所有页面中的元素(而不仅仅是作为子元素的元素).
:eq(n)                                 返回序号等于n的元素(从0基数哦)
:gt(n)                                 返回序号大于n的元素,不包括第n个元素。
:lt(n)                                  返回序号小于n的元素,不包括第n个元素。

在应用上述表时注意:所有nth-child中都是从1开始计数的,如nth-child(3n)返回第3, 6, 9个元素。其他的还是从0计数。

3. 使用JQuery自定义的过滤器

 

Selector                                    Description
:animated                                   选择那些目前在动画效果控件中的元素
:button                                      选择所有button元素(input[type=submit], input[type=reset],
input[type=button], or button).
:checkbox                                  选择checkbox元素(input[type=checkbox]).
:checked                                    选择那些被checked的checkbox或radio button(supported by CSS).
:contains(foo)                            选择包含文字foo的元素(注意区分文字的大小写哦).
:disabled                                   选择form元素中被disabled的元素(supported by CSS).
:enabled                                    选择form元素中被enabled的元素 (supported by CSS).
:file                                           选择所有file元素(input[type=file]).
:header                                     选择所有header元素; 例如:从<h1>到<h6> 的元素.
:hidden                                     选择隐藏的元素.如:$("li:hidden").css("visibility", "visible");将隐藏的li显示出来
:image                                      选择所有image元素 (input[type=image]).
:input                                       选择所有form元素(input, select, textarea, button).
:not(filter)                                 使指定filter取反.如:$("li:not(hidden)").css("visibility", "hidden");将所有没有隐藏的 li 隐藏掉
:parent                                     选择所有包含子元素的元素(including text), 空元素不算(如包含空格的).
:password                                 选择password元素(input[type=password]).
:radio                                       选择radio元素 (input[type=radio]).

:reset                                       选择reset buttons (input[type=reset] or button[type=reset]).

注意:

1) 过滤器可以连接起来使用,如:

:checkbox:checked:enabled

选择那些处于enabled状态并被选中的checkbox。

2) :not(filter) 只能用于过滤选择器(filter selectors)而不能用于查找选择器(find selectors)。如:

div p:not(:hidden)是合法的,

而 div :not(p:hidden) 就不行。

简单区分的方法是,:not只能用在以:(冒号) ,[(中括号)开始的filter selectors,其他的都不行。

 

另外,可以使用XPath Selectors,这个要使用插件,可以从这里下载。

[JQuery]使用 jQuery,第 2 部分: 构建未来的 Web 应用程序

mikel阅读(658)

简介

这 6 个月以来,JQuery 受欢迎的指数迅速攀升,现已成为 Web 开发人员首选的 JavaScript 库。与此同时,人们对富 Internet 应用程序(Rich Internet Application,RIA)的应用和需求也在迅速增长,并期待用基于浏览器的应用程序代替桌面应用程序。无论是电子表格,还是薪水册和电子邮件应用 程序,现在都在浏览器中再现了类似于桌面的体验。随着这些应用程序数量的增多和功能的日益复杂,JavaScript 库将会变得越来越重要,因为它是构建这些应用程序的坚实基础。JQuery 将成为开发人员最佳选择。本系列文章深入探索了 JQuery,并提供了坚实的基础。开发人员借助这个基础就可以快速轻松地构建自己的 RIA。

上一篇文章 中,您了解了 jQuery 的基础知识,包括如何在开发环境中设置 jQuery,以及它的核心函数是如何工作的。您看到了 jQuery 如何通过选择和过滤方法来简化搜索和查找页面元素,以及如何才能找到所需的元素。接下来,您还体验了 jQuery 提供的遍历搜索结果的各种方法,而且其中的很多函数与您在其他编程语言中接触到的函数十分相似。最后,还介绍了一个示例小部件,即 Select All/Deselect All 复选框,并看到了 jQuery 如何通过几行代码来构建这个小部件。

在本篇本章,通过 更精彩的功能来进一步扩展您的 jQuery 知识,并向老的 Internet 应用程序添加一些真正的 “富” 特性,使这个演示应用程序成为富 Internet 应用程序。我先向您展示 jQuery 如何处理事件。所谓事件就是指鼠标单击、突出显示和拖动等。请注意,事件处理并不局限于按钮,还包括处理在任何 div、span 等上进行的鼠标单击。接下来,我将讨论如何获取和设置 Web 页面内的对象的属性。这包括如何从表单元素获得文本、如何从 div 获得 innerHTML,以及如何确定哪个类附加到哪个元素上。最后,我将讨论如何在无需重新加载页面或调整外部样式表的情况下修改页面元素的 CSS 属性。

示例应用程序在这个 Web 邮件应用程序的额外小部件中包含了各种东西,展示了如何创建一个客户端的富应用程序,并且根据与页面的交互来更改对象的颜色、大小和位置。(这些交互只限 于客户端 — 下一篇文章将会添加服务器端的交互)。通过本文,您将能够掌握创建 RIA 所需的 jQuery 工具,并借此打动您的客户。

事件

jQuery 内的 Events 模块是向 Web 应用程序添加交互性的第一步,因为事件通常是页面上发生的事情的触发器。正如我在简介中提到的,您不应该认为事件只发生在 Form 元素 — 实际上,任何元素都能触发事件,因此应该充分利用这一点来更轻松地构建定制的小部件,以及添加一些独特却又不局限于特定 Form 元素的交互。

众所周知,大多数事件 基于 Form 元素。演示这些方法最好的方式就是使用它们。在开始深入研究可用的函数之前,一定要注意:Events 模块针对每个函数都遵循一种模式。每个事件函数都包含两种形式:一个没有任何参数,一个包含一个函数作为参数。二者间的差异十分重要,而且这对各个函数都 是一致的。没有参数的函数将实际激发该事件。换而言之,调用 click() 将实际导致该按钮被单击。在实际单击该按钮,或其 click() 函数被调用时,将会调用 click(function)。是不是很困惑?这只是文字上的描述,举例说明之后,您就会清楚了。

清单 1. jQuery Event 方法

// make the "myButton" click.  This will cause the button to click and any actions
// tied to it will occur - for example, it could submit a form, or other
// jQuery actions could be tied to it.
$("#myButton").click();
// use jQuery to setup what will actually happen when the "myButton" is
// actually clicked.
$("#myButton").click(function(){
$("#myDiv").toggle();
});
// A common pattern in jQuery when setting up actions on a page is to trigger the
// action to occur initially when the page is loaded.  This occurs frequently
// with AJAX setups, where the values come from the server.
// In this example, the myDiv has its visibility toggled every button click.  When
// the page is loaded, we call click() immediately, which toggles the view
// as soon as the page views (not a practical example, but you should see the design)
$("#myButton").click(function(){
$("#myDiv").toggle();
}).click();

如下所列的事件 符合我在之前所介绍的设计模式,而且也都具有与其相关联的两个函数。为了简单起见,我只列举了第一个:

  • blur() – 在 Form 元素失去焦点时调用,例如,用 tab 键移出具有焦点的文本字段
  • change() – 在 Form 元素失去焦点,并且其值因获得焦点而更改时调用。Internet Explorer 和 Firefox 对此的处理稍微不同。
  • click() – 当在页面元素(不一定是 Form 元素)上单击时调用
  • dblclick() – 当在页面元素(不一定是 Form 元素)上双击时调用
  • error() – 当元素出现内部错误时调用,不同的浏览器对此的处理不同,可能很多人都亲自体验过
  • focus() – 当某个 Form 元素获得焦点时调用
  • keydown() – 当页面元素在其上/内发生一个 keypress 时调用
  • keyup() – 当页面元素在其上/内释放一个 keypress 时调用
  • keypress() – 当相同的页面元素相继发生 keydown 和 keypress 时调用
  • select() – 文本在文本字段内被选中时调用,而不是内容在组合框内被选中时(这时发生的是更改事件)调用。
  • submit() – 提交 Form 时调用

还有一些函数不遵守上文概括的模式,而且也只包含一个可调用的函数。我将这些例外也列于此,但它们不常用:

  • resize(fn) – 对象调整大小时调用
  • scroll(fn) – iframe 卷起时调用
  • load(fn)/unload(fn) – 对象在页面上加载/重载时发生

此 外,您可以想像得到,一些事件是与鼠标紧密相连的。由于这些事件常被误用,所以我将它们包括在第三节。认识到这一点后,jQuery 已经用特定的函数替代了其中的一些事件。我将它们列于此,只是为了直接与底层的 DOM 事件相匹配,但对于所有的实际使用,最好使用其他的方法。比如,当鼠标在某个元素上按下或释放时,就会调用 mousedown(fn)mouseup(fn) 方法。然而,更多时候,却应该调用 click() 方法,因为此方法也会作为事件抛出,而且它更符合预期的行为,更不容易出错。试想一下这样的情况:用户在某个按钮上按下鼠标,发现错了,立即松开鼠标而不是释放鼠标。如果用户用所定义的 mouseup(fn) 在另一个页面元素之上释放鼠标,那么应该发生什么行为呢?理想情况下,这两个函数的使用应该限于对界面的拖放,因为这种情况下单击不会有合适的替代。

Event 模块的最后两个方法 mouSEOver(fn)mouSEOut(fn) 目前在很多 Web 站点上都很常见。它们常被用来显示悬浮帮助、图片显示所需的相框和基于鼠标指针所在位置而发生的颜色改变。JQuery 认识到这两个函数还将很常用,但很多人都不能正确使用它们,这就导致很多错误。人们并不是有意要将 bug 引入其代码,而是自己不会编写嵌套组件或应对其他复杂情况的代码。因此,jQuery 向 Event 模块添加了一个新方法来替代这两个函数,这个方法就是 hover(fn1, fn2) 函数。

清单 2. jQuery 的 Hover 方法

// This demonstrates the hover() function as implemented by jQuery.  You define two
// functions:  what happens when the mouse moves over the specified element
// and what happens when the mouse moves off the element.
// In this example, each row in a table will get a red background when
// the mouse moves over it and a white background when the mouse leaves.
$("tr").hover(function(){
$(this).css("background","#0000ff");
},
function(){
$(this).css("background","#ffffff");
});

属性

页 面交互性的一个体现就是它从页面的某个区域获得信息并将信息传送到其他位置的能力。这可以很具体,比如从一个文本字段获得信息后将信息放入一个表内;也可 以很宽泛,比如从一个组合框获得信息后将信息传给服务器,然后将服务器的响应再放入另外一个不同的组合框内。交互性的核心就是页面信息的传递。

在 页面上保存信息有很多不同的方式,在页面的某个元素内存储信息的方法就更多样了。您可能会想,一个简单的 <p> 所包含的信息肯定没有一个文本字段那么多(这不一定正确),因而,访问信息也有很多不同的函数。同样地,您自己可能已经有了这样的结论:如果能从页面元素 获得信息,那么也应该可以在这些元素上放置信息。实际上,每个页面元素都是一个数据对象,其中包含由 getter/setter 方法封装的变量。JavaBean 模型和 jQuery 的实际差异是方法名称和某些元素不适合特定函数的限制。

在深入研究这些方法之前,让我们先来看看什么信息 存储到页面元素内。简单一些的,像 a <p>,可能只包含 CLASS 或 ID 信息。而像 <img> 则可能包含更多信息,比如 “src”、“alt”、“width” 和 “height”。而复杂一些的,像 < input type="password"> 则可能包含 “defaultValue”、“maxLength”、“readOnly” 或 “accessKey” 等信息。

这种潜在变量的多样性促使 jQuery 创建了一种广义函数来访问它们。这个函数是 attr(name),可用来访问来自任何页面元素的信息。我们将通过几个示例来了解其工作原理。

清单 3. jQuery attr() 函数

<img src="/images/space.gif" id="spacer" class="a b c" alt="blank">
// Calls to the attr() function will return the following
$("#spacer").attr("src"); // will return "/images/space.gif"
$("#spacer").attr("alt"); // will return "blank"
// Similarly, you can access the ID in the same way
$(img).each(function(){
$(this).attr("id"); // will return "spacer"
});

在试图向页面添加交互性时,此函数十分有用。实际上,在添加 data() 函数(如下所示)之前,通常都必须将所需信息压缩到一个可用变量内。例如,假设有一个页面具有两个框架,第一个框架显示选项卡,底部框架显示每个选项卡的内容,那么可以这样设置:

清单 4. 应用 attr()

<!-- This would appear in the top frame as a tab.  The CSS file would control how
the tab appears, and the only HTML code needed would be this -->
<td>
<div class="tab" id="/messages.jsp">Messages</div>
</td>
// This code would appear in the jQuery section.  Notice how we get the ID from the tab,
// and use that information to set the bottom frame, named 'content' with the content
// on the page "messages.jsp"
$(".tab").click( function() {
window.parent.frames['content'].location = $(this).attr("id");
});

除了获得 每个元素上的属性值外,还可以设置 这些值。其效果与以编程方式更改元素外观或行为相同。

清单 5. 利用 attr(str) 更改属性

// will change the image source, and the image displayed on the page will change
$("img").attr("src", "myimage.jpg");
// will change all the links on the page to go to one specific page
$("a").attr("href", "mypage.html");
// will change the maxLength on all password fields to 10 characters
$(":password").attr("maxLength", "10");

页面上的 Form 元素具有一个特殊的函数,该函数可以针对这些元素调用以获得附加到元素的值。在处理表单和验证时,这一点尤其便利,而且在用 Form 元素创建交互 Web 站点时更有可能会用到这些函数。

清单 6. Form 元素的 val() 函数

// will get the text contained in the text field and check that it's not blank
$(":textfield").each(function(){
// use the val() function to get the text inside the textfield
if ($(this).val() == "")
$(this).next().text("Error");
});
// on a new password page, this will compare the new one with the confirmation,
// to make sure they are equal
if ($("#newPassword").val() != $("#confirmPass").val())
$("#newPassword").next().text("Error");

还有其他一些函数,可用来获得包含在某些标记之内的信息。那么这有什么用途呢?比如说,您可以获得包含在某个 <td> 标记内的所有信息并进行替换,或者您也可以将所有 <p> 内的文本变成小写的。获得这些信息的方式有两种,但不能为此使用 attr() 函数。与所有其他的属性函数类似,这些函数也有相应的 setter 方法。第一个是 html() 函数,它能返回某个标记的所有 innerHTML。另一个是 text(),它能返回某个标记内的所有文本。那么二者有何区别呢?html() 函数能返回包括 HTML 标记在内的文本,而 text() 则会分离二者,只返回内含的文本。以下示例展示了它们的不同之处。

清单 7. html() 与 text() 的对比

// this will examine every <td> tag, and if the value is blank, it will insert
// a "-" into it, as a placeholder.
$("td").each(function(){
// check the text of the table cell
if ($(this).text() == "")
$(this).text("-");
});
// this will convert every paragraph's text to lowercase
$("p").each(function(){
var oldText = $(this).text();
var newText = oldText.toLowerCase();
$(this).text(newText);
});
<-- This shows the difference between text() and html() -->
<div id="sample"><b>This is the example</b></div>
$("#sample").html(); // will return "<b>This is the example</b>"
$("#sample").text(); // will return "This is an example"

此外,最近还向 jQuery 库添加了用于属性的 data() 函数。它源自 jQuery UI 项目并且已纳入 jQuery 的整体项目之中。起初,UI 项目开发人员只是觉得他们不想破坏某些页面元素的可用属性,于是就想到要找到一种方法,用来根据自己的需要创建能存储信息的属性。回顾上文提到过的选项卡 的例子。我其实 “破坏” 了此 DIV 的 ID 内的链接,而这显然不是最理想的方法。但是,受 jQuery 以前版本的限制,这在当时是惟一的选择。有了 data() 函数之后,这个问题就有了更好的解决方案。不妨将 data() 函数视为用来访问包含在每个页面元素的内部 Map 的一种方式。一个 Map 实际上就是键-值对的集合。这就让开发人员可以创建他们想要给页面元素提供的任何定制属性,并能给该属性附加任意值。最终的结果就是代码的编写更简单,而 且当项目规模不断增大时,代码的维护也更容易。接下来,让我们用新的 data() 函数重写上文提到的示例:

清单 8. 新的 data() 函数

// create the div like we did above, but without any specific information.  In this
// way we can create a generic HTML layout and customize it in our jQuery code.
<td>
<div class="tab"></div>
</td>
// Now customize each tab in the jQuery code.
$(".tab").eq(0).text("Messages");
$(".tab").eq(0).data("link", "messages.jsp");
$(".tab").click(function(){
window.parent.frames['content'].location = $(this).data("link");
});
// Taking this a step further, you can picture all this information coming from
// an external properties file via a Java array.  This would be the code on a JSP
// page.
<%
// array containing tab names
String[] tabNames;
// array containing tab links
String[] links;
for (int i=0; i<tabNames.length; i++) {
%>
$(".tab").eq(<%=i%>).text("<%=tabNames[i]%>");
$(".tab").eq(<%=i%>).data("link", "<%=links[i] %>");
<% } %>
$(".tab").click(function(){
window.parent.frames['content'].location = $(this).data("link");
});

CSS 处理

本 文最后的这个部分将要介绍如何在不调整样式表或重载此页面的情况下动态地处理页面的 CSS。我们将能够通过简单更改颜色、字体等向页面添加一些基本效果。jQuery 的 CSS 实际上是整个库最初的创意来源。其目标是让页面上的 CSS 编程更容易。正如您所见,此项目随后得到了充分的发展。但是项目的初衷并没有改变,jQuery 的确简化了 CSS 编程。不过,我还是先要说明一点,即 jQuery 为处理 CSS 所提供的那些传统函数实际上已经不能适应当今的 Web 环境。然后,我会介绍可以使用的其他函数(也是 jQuery 内的)。

有两个基本函数可用来处理页面上的 CSS。可以先以字符串传递单个属性,然后再以字符串传递单个值,也可以用字符串/字符串数组的形式一次传递。这两个函数的功能基本相同,并且可以很容易地更改页面的 CSS。

清单 9. css() 函数

// change the background of every div to red
$("div").css("backgroundColor", "#ff0000");
// - or -
$("div").css("backgroundColor", "red");
// - or -
$("div").css({backgroundColor: "#ff0000"}); // notice the braces and lack of quotes

可以看出这些函数非常简单直观,很容易理解和掌握。不过,考虑到目前 Web 页面设计的潮流,这些函数还存在一些问题。常规的 Web 页面都是从页面删除样式,然后在样式表中填入一个外部文件或代码片段。如果能采用其他办法,您肯定 希望将样式代码放入 JavaScript 代码中。否则,将来更改站点的外观将十分困难。

幸运的是,现在已经有了替代函数,它既能提供所需的代码分离,又能让 CSS 处理简单直观。这些函数允许从页面元素添加和删除类。通过将这些类的样式放入外部样式表,就能分离样式、数据和事件,这种分离对于复杂的页面至关重要。请看以下这些示例:

清单 10. 更佳的 CSS 处理 – addClass() 和 removeClass()

// will add the "input_error" class to any form elements that fail to validate
// you can picture the "input_error" class in the external CSS file defining
// a red border and red text
$(":textfield").each(function(){
if ($(this).val() == "")
{
$(this).next().text("Error");
// this will turn the text field's border/text red
$(this).addClass("input_error");
}
// this tests if the text field has the class attached already
else if ($(this).hasClass("input_error"))
{
$(this).next().text("");
// this will remove the class, restoring a normal border/text
$(this).removeClass("input_error");
}
});

如这个示例所示,通过引用在外部样式表内定义的类来调整 CSS 是一种更可取的处理 CSS 的方法。它让 Web 站点创建者通过更改样式表就能改变整个站点 错误消息的处理方式,而不再像采用 css() 方法时那样,必须追究代码的每个实例。虽然这些方法直观易用,但是不太适合大型 Web 应用程序,应该避免采用 addClass()removeClass() 方法。

综合学到的知识

要 综合使用以上知识,让我们再来看看这个示例应用程序。它是一个具有交互性的 Web 应用程序,试图创建一个 RIA 并给用户这样的感觉:他们处理电子邮件所用的这个 Web 应用程序非常类似于桌面应用程序。在本例中,将利用 Event、Attribute 和 CSS 模块来定义 Web 邮件应用程序将如何处理鼠标单击和双击。以下所示的屏幕截图显示了真实的效果。当用户在表的一个行上单击时,此行将会改变颜色以突出显示用户的当前选择。 当用户在消息上双击时,用户就能看到消息,但如果用户读的是条新消息,此行的背景颜色会改变以表明此消息不再是未读消息。

图 1. 在某行上单击
在某行上单击
图 2. 在某行上双击
在某行上双击
清单 11. 综合学到的知识

// First we add the rows to the table.  Each row is a member of the "messageRow" class.
//  We also give an ID to each row, and this ID is the message number itself, which is
// gotten from the Java data object. Keep in mind this sits in a for loop in a JSP file.
<%
for (int i=0; i<messages.size(); i++)
{
MessageData message = messages.get(i);
%>
<tr class="messageRow" id="<%=message.id %>">
// Now that the table has been laid out, we can define our jQuery code to capture single
// mouse clicks and double mouse clicks.
// Notice how we capture a single click on the table row with the click() function.  Next
// notice how we use addClass() and removeClass() instead of manipulating the CSS
// directly with a css() function.  This lets us change the stylesheet underneath
// the code without modifying our jQuery code.
$(".messageRow").click(function() {
$(".messageRow").removeClass("message_selected");
$(this).addClass("message_selected");
});
// Now we capture the double click on a table row.  Ignore the AJAX methods with the
// post() function, which we'll get to in the next article.
// We use the dblclick() function here to capture double clicks.
// Notice in the AJAX call, how we get the ID out of the table row that was double
// clicked.
// We pass this ID to the server in order to get the information about the message back
// from the server.  We defined the message number in the JSP code, so that the ID
// contained the message number.
$(".messageRow").dblclick(function() {
if ($(this).hasClass("mail_unread"))
{
$(this).removeClass("mail_unread");
}
$.post("<%=HtmlServlet.READ_MESSAGE%>.do",
{
messageId: $(this).attr("id"),
view: "<%=view %>"},
function(data){
// Do AJAX stuff here
});
});
});

结束语

随 着应用程序不断从桌面向浏览器转移,像 jQuery 这样的 JavaScript 库的将越来越重要。应用程序会越来越复杂,这就使跨浏览器的 jQuery 成为所有 Web 应用项目的必要工具。由于易于使用和功能完备,jQuery 逐渐从其他 JavaScript 库中脱颖而出,成为很多开发人员的最佳选择。

通过这个 jQuery 系列的第二篇文章,您实际体会到了 Web 页面上的交互、了解如何在客户端实现基本交互(无需从服务器获得信息),并借此扩展了自己的 jQuery 知识。您先是接触了 Event 模块,该模块定义页面元素如何响应各种交互,其中包括鼠标交互、键盘交互和焦点交互。事件是 Web 页面上的交互的最主要的驱动器,而且它们不必附加于 Form 元素。我随后讨论了属性以及如何恰当地从页面元素获得属性,如何在页面元素上设置属性。您看到了通用的 attr() 函数可用于每个元素,并且 Form 元素有获得其值的特殊函数。您还看到了新添加到 jQuery 的 data() 函数,此函数可充当每个页面元素的 HashMap,让程序员可以创建所需的任何属性。最后,您了解到如何修改页面元素的 CSS,而不需重新加载页面。您还体验了 css() 函数的简单和直观。但是为了分离页面的样式和 jQuery 代码,您和您的团队最好选择用 addClass()removeClass() 函数替代前面那些函数。

本 文的最后的一部分将您所学到的这三个模块综合起来,展示了示例邮件应用程序如何处理鼠标交互。通过突出显示单击的行以及在适当的时候对消息进行 “未读” 标记,可以区分鼠标单击和双击,然后为特定于消息的数据向服务器发送一个 Ajax 调用,将消息编号传递给服务器。

在本系列的下一篇文章中,我们将要深入研究 jQuery 内的 Ajax 函数,了解它如何消除处理 Ajax 所涉及到的大量复杂特性,而使其简单到像通常那样只需调用 JavaScript 函数。此外,我们还会谈到 jQuery 内的 Effects 模块,对于为用户创建额外的交互和视觉效果,这十分有用。下一篇文章中的最后部分将会总结整个演示邮件应用程序和我们的 jQuery 课程。到那时,希望您能自信地将这个库添加到自己的 Web 应用程序中。


回页首

下载

描述 名字 大小 下载方法
包含示例应用程序的 Zip 文件 jquery.zip 68KB HTTP
包含示例应用程序的 War 文件 jquery.war 68KB HTTP
关于下载方法的信息

参考资料

学习

讨论

关于作者

 

在 Michael Abernethy 的 10 年技术生涯中,他与各种不同的技术和客户机打交道。他目前是一家拍卖软件公司 Optimal Auctions 的产品开发经理。他现在专注于富 Internet 应用程序,试图同时实现应用程序的复杂性和简单性。他在空闲时常常带上自己最喜欢的书去墨西哥湾海滩度假。

[MVC]Asp.Net Mvc Beta新特性之自动绑定(1)-体验篇

mikel阅读(732)

   我们知道,ASP.NET Mvc Preview5中加入了全新的ModelBinder特性,虽然这个特性非常的强大,但是使用起来并不是那么的友好,因此,在最新的ASP.NET Mvc Beta,框架对这部分进行了进一步的加强,使得复杂参数的自动绑定得以实现,本文将分级部分完整探讨整个mvc框架中的modelbinder实现和完全挖掘系统自带的ModelBinder的能力,使得基于mvc框架的web开发脱离页面取值的苦海.

(参见: http://www.cnblogs.com/leven/archive/2008/08/31/1280481.html以及http://www.cnblogs.com/leven/archive/2008/09/01/1280862.html)

         首先我们稍微回顾下ModelBinder的使用方法.首先定义一个实体类,然后针对该类写一个ModelBinder,确定绑定关系,这样就可以在action的参数中直接使用了.

         然而,很多朋友都有体会,这个ModelBinder用起来太过复杂.有没有更好的解决方法呢?ASP.NET Mvc beta,这个答案是肯定的.那就是beta中提供的新特性,自动绑定.

         我们知道,preview5,系统也能对基本类型以及DateTimeNullable<DateTime>进行自动绑定,但是对于自定义类是无能为力的.但是想一想,自定义实体类也应该是由一系列简单类型构成的啊,也就是说,一个复杂的实体类都是有很多简单类型构成,是不是可以有一个通用的方法来做这个绑定呢?答案是肯定的,其实在我上篇关于preview5绑定的文章例子中就是提供一个相对简单的通用绑定方案,理所当然的,我们可以扩展这个方案,让它更加智能化一些,想来ASP.NET MVC开发团队也意识到这一点,于是在最新的beta版中,mvc框架就增强了DefaultModelBinder的功能,使得绑定工作尽可能的简化.

         在本篇文章中,我们会探讨新的ModelBinder如何使用,且它是如何工作的.

         首先,我们用最快的方式进行一次新版”ModelBinder的实践,建立一个Mvc工程.设定一个默认的routing.然后开始加入代码,这个实践的项目文件如下图:

工程监理完毕后,我们在NewModelBinderDemo.Library.Entities中加入一个SimpleArticle.cs.这是测试的一个简单实体,代码如下:

这是一个没有加任何修饰的简单实体.

然后修改BinderController,加入Action,先看看Controller中的全部代码:

然后是3aspx页面.我们看看关键的simpletest.aspx



这部分代码要注意下,标题和正文的表单命名,article.titlearticle.content,这是不是有什么规则了?暂时先不说明.有兴趣的朋友可以拿demo研究研究,接下来的部分我们会慢慢研究这儿这样命名的原因.

至于其他页面就不再详细说明其中的代码了,感兴趣的朋友可以下载附带的demo自行查看.完成上面的一切后,我们怀着有点忐忑的心情按下Crtl+F5….一步步进行:


Ok.这个页面没问题不过要是这儿也有问题,就说明mvc白学了,

点击下->

这儿也能进来不过好像这都不是关键.赶紧填点东西..

按下提交数据查看结果:

上天作证,我啥事都没做,居然获取到article….太激动了.这意味着我们在mvc框架下开发基本上可以告别繁琐的页面参数获取了,想想p5中让人无法忍受的modelbinder,beta中的是多么的和蔼可请啊.

先别急着兴奋,表单可不止文本域,而且传递的参数可不是只有字符串.这是肯定的,那么我们试试继续考验下DefaultModelBinder..

添加第二个实体. SimpleArticle,具体代码如下:

然后对应添加名为AdvanceTestAdvanceTestResultaction,代码如下:

对应添加advancetest.aspxadvancetestresult.aspx,样式和先前一致,此处就不再浪费地方了.

然后我们继续测试

填入合适的数据,提交..


非常的神奇
,我们仍然什么都没做,系统的ModelBinder已经完全识别了AdvanceArticle类并对其下的各种类型的属性赋值.不过,有的朋友可能担心了,我们刚才的表单中可是有时间和数字类型,如果用户不按常理出牌,添了个错误的信息,是否会出错了?我们可以试试:

继续提交查看结果:

看上去没啥问题啊,系统对错误的数据采取了使用默认值的方式.但是如果系统给出的默认值和我们需要的不同怎么办呢?比如这儿的提交时间显然是不行的.当时是有办法的,事实上我们只需要在实体的构造方法中对这些属性设定个初始值就万事大吉了,系统的ModelBinder发现数据无法填充进去自然会保持原样.

比如修改下AdvanceArticle:

这样之后我们再次提交刚才的表单,结果变化如下:

不错,自动变成了我们设定的初始值了.该问题解决..

         继续想想,好像目前为止我们都是取的web表单中的文本,其他的表单该怎么取呢?我们继续对其他常用表单进行一次测试,为了方便,我们直接修改了AdvanceArticle类来进行测试,修改后的类如下:

这儿自定义了一个enum类型来代表状态:

我们继续测试DefaultModelBinder的智商….

填写表单:

提交查看:

让人感觉十分惊讶的是,系统居然全部认出了并成功绑定了数据.接下来我们看看更高级的特性,自动绑定数组以及包含类,继续修改AdvanceArticle:

继续测试:

提交查看结果非常棒,系统认出了所有的表单信息并成功绑定.

本文到此相信大家都对系统的自动参数绑定的威力有了一定的了解吧,相信看到如此强大的能力之后你也想将手上的项目升级的ASP.NET MVC Beta上来脱离取值的苦海吧.

         在下一篇中,我们将详细研究系统这个威力强大的ModelBinder的实现原理,以及对默认绑定的细调设置,更深层次了解目前mvc框架中的参数绑定特性,最后附上演示Demo的全部源代码.
By Leven
2008-10-18
http://files.cnblogs.com/leven/NewModelBinderDemo.rar