[转载]C#.NET常用的小函数方法集

mikel阅读(1002)

[转载]C#.NET常用的小函数方法集 – 上天入地 – 博客园.

1、DateTime  数字型
System.DateTime currentTime=new System.DateTime();
1.1 取当前年月日时分秒
currentTime=System.DateTime.Now;
1.2 取当前年
int 年=currentTime.Year;
1.3 取当前月
int 月=currentTime.Month;
1.4 取当前日
int 日=currentTime.Day;
1.5 取当前时
int 时=currentTime.Hour;
1.6 取当前分
int 分=currentTime.Minute;
1.7 取当前秒
int 秒=currentTime.Second;
1.8 取当前毫秒
int 毫秒=currentTime.Millisecond;
(变量可用中文)

2、Int32.Parse(变量)      Int32.Parse(“常量”)
字符型转换 转为32位数字型

3、 变量.ToString()
字符型转换 转为字符串
12345.ToString(“n”);    //生成  12,345.00
12345.ToString(“C”);    //生成 ¥12,345.00
12345.ToString(“e”);    //生成 1.234500e+004
12345.ToString(“f4”);    //生成 12345.0000
12345.ToString(“x”);     //生成 3039 (16进制)
12345.ToString(“p”);     //生成 1,234,500.00%

4、变量.Length 数字型
取字串长度:
如: string str=”中国”;
int Len = str.Length ;  //Len是自定义变量, str是求测的字串的变量名

5、System.Text.Encoding.Default.GetBytes(变量)
字码转换 转为比特码
如:byte[] bytStr = System.Text.Encoding.Default.GetBytes(str);
然后可得到比特长度:
len = bytStr.Length;

6、System.Text.StringBuilder(“”)
字符串相加,(+号是不是也一样?)
如:System.Text.StringBuilder sb = new System.Text.StringBuilder(“”);
sb.Append(“中华”);
sb.Append(“人民”);
sb.Append(“共和国”);

7、变量.Substring(参数1,参数2);
截取字串的一部分,参数1为左起始位数,参数2为截取几位。
如:string s1 = str.Substring(0,2);

8、String user_IP=Request.ServerVariables[“REMOTE_ADDR”].ToString();
取远程用户IP地址

9、穿过代理服务器取远程用户真实IP地址:
if(Request.ServerVariables[“HTTP_VIA”]!=null){
string user_IP=Request.ServerVariables[“HTTP_X_FORWARDED_FOR”].ToString();
}else{
string user_IP=Request.ServerVariables[“REMOTE_ADDR”].ToString();
}

10、 Session[“变量”];
存取Session值;
如,赋值: Session[“username”]=”小布什”;

取值: Object objName=Session[“username”];
String strName=objName.ToString();
清空: Session.RemoveAll();

11、String str=Request.QueryString[“变量”];
用超链接传送变量。
如在任一页中建超链接:<a href=Edit.aspx?fbid=23>点击</a>
在Edit.aspx页中取值:String str=Request.QueryString[“fdid”];

12、DOC对象.CreateElement(“新建节点名”);
创建XML文档新节点

13、父节点.AppendChild(子节点);
将新建的子节点加到XML文档父节点下

14、 父节点.RemoveChild(节点);
删除节点

15、Response
Response.Write(“字串”);
Response.Write(变量);
向页面输出。

Response.Redirect(“URL地址”);
跳转到URL指定的页面

16、char.IsWhiteSpce(字串变量,位数)——逻辑型
查指定位置是否空字符;
如:
string str=”中国 人民”;
Response.Write(char.IsWhiteSpace(str,2)); //结果为:True, 第一个字符是0位,2是第三个字符。

17、char.IsPunctuation(‘字符’) –逻辑型
查字符是否是标点符号
如:Response.Write(char.IsPunctuation(‘A’));  //www.qichepeijian.com返回:False

18、(int)’字符’
把字符转为数字,查代码点,注意是单引号。
如:
Response.Write((int)’中’);  //结果为中字的代码:20013

19、(char)代码
把数字转为字符,查代码代表的字符。
如:
Response.Write((char)22269);  //返回“国”字。

20、 Trim()
清除字串前后空格

21 、字串变量.Replace(“子字串”,”替换为”)
字串替换
如:
string str=”中国”;
str=str.Replace(“国”,”央”); //www.qichepeijian.com将国字换为央字
Response.Write(str);   //输出结果为“中央”

再如:(这个非常实用)

string str=”这是<script>脚本”;
str=str.Replace(“<“,”<font><</font>”); //将左尖括号替换 为<font> 与 < 与 </font> (或换为<,但估计经XML存诸后,再提出仍会还原)
Response.Write(str); //显示为:“这是<script>脚本”

如果不替换,<script>将不显示,如果是一段脚本,将运行;而替换后,脚本将不运行。
这段代码的价值在于:你可以让一个文本中的所有HTML标签失效,全部显示出来,保护你的具有交互性的站点。
具体实现:将你的表单提交按钮脚本加上下面代码:
string strSubmit=label1.Text;  //label1是你让用户提交数据的控件ID。
strSubmit=strSubmit.Replace(“<“,”<font><</font>”);
然后保存或输出strSubmit。
用此方法还可以简单实现UBB代码。

22、Math.Max(i,j)
取i与j中的最大值
如 int x=Math.Max(5,10); // x将取值 10

[转载]使用ATL开发ActiveX控件

mikel阅读(1271)

[转载]使用ATL开发ActiveX控件 – {CODE @CODING完美世界 – 博客园.

本文描述了使用ATL开发一个ActiveX控件的完整过程。

一、创建项目

单击起始页中的“New Project…”,选择“ATL”分类下的“ATL Project”项目,项目名称为“Calculator”。在随后出现的项目向导中,使用默认配置即可。

image

二、添加控件

在解决方案管理器中的项目上右击,依次选择“Add”、“Class”,在添加类对话框中选择ATL分类下的ATL Control类型。单击“Add”按钮,将会出现添加ATL Control向导。

image

image

在向导的第二步中,将接口类型选择为“Dual”,为控件支持事件做为准备,在Support选项中,选中“Connection points”复选框。

随后出现选择控件要实现的接口的界面,除VS默认添加的实现外,再添加IObjectSafety接口,实现该接口可以避免控件在IE中使用时IE弹出运行的脚本不安全的提示。

image

三、为控件添加并实现方法

在Class View窗口中右击ICalc接口,依次选择“Add”、“Add Method…”,此处假定我们实现一个加法运算,将方法命名为“Add”,然后添加参数:

image

需要注意的是对返回值的处理。应将参数类型选定为DOUBLE*,并选中“retval”复选框。

向导结束后,VS自动在Calc.cpp中添加了该方法的空实现,略加修改后的方法代码为:

STDMETHODIMP CCalc::Add(DOUBLE a, DOUBLE b, DOUBLE* result)
{
	*result = a + b;

	return S_OK;
}

测试该方法:

由于只是调用该控件进行加法运算,并不需要该控件的界面展示,因此在测试控件之前,可以将VS自动生成的OnDraw方法中的其他代码删除,直接返回 S_OK 即可。

对VS自动生成的用于测试的htm略做修改来测试添加的方法。修改后的完整htm代码如下:

<HTML>
<HEAD>
<TITLE>ATL 8.0 test page for object Calc</TITLE>
</HEAD>
<BODY>

<OBJECT ID="Calc" CLASSID="CLSID:59443E6F-7B99-4F75-A7AF-6FEE5B8208CD"></OBJECT>

<input type="button" value="Add" onclick="add();" />

<script type="text/javascript">
    function add() {
        var calc = document.getElementById('Calc');
        var result = calc.Add(2, 3);
        alert(result);
    }
</script>

</BODY>
</HTML>

点击“Add”按钮后的运行效果:

image

四、为控件添加事件

假定控件进行的是一个非常复杂的运算,为了在调用运算时不阻塞调用者线程,可以使用异步方式完成运算。控件在完成运算时需要通知调用者,这时便需要事件。

首先按照步骤三中的方法,添加一个异步调用加法运算的方法AddAsync,然后为控件添加运算完成的事件AddCompleted。

在Class View窗口中右击_ICalcEvents接口,依次选择“Add”、“Add Method…”,根据添加方法向导添加AddCompleted方法,如下图所示:

image

然后在Class View窗口中右击CCalc类,依次选择“Add”、“Add Connection Point…”,在弹出的实现连接点窗口中实现_ICalcEvents接口。

image

完成向导后,VS会自动为我们生成基本框架,包括引发事件的方法Fire_AddCompleted。我们只需在AddAsync方法中添加运算并在运算结束时调用Fire_AddCompleted的代码:

STDMETHODIMP CCalc::AddAsync(DOUBLE a, DOUBLE b)
{
	double result;
	result = a + b;
	Fire_AddCompleted(&result);

	return S_OK;
}

在网页中添加异步计算的代码进行测试(添加的JavaScript代码如下),应该能够得到我们想要的效果。

<script type="text/javascript">
    function addAsync() {
        var calc = document.getElementById('Calc');
        calc.attachEvent("AddCompleted", OnAddCompleted);
        calc.AddAsync(3, 4);
    }

    function OnAddCompleted(result) {
        alert(result);
    }
</script>

五、ActiveX控件的事件与多线程

细心的读者一定会发现步骤四中所谓的“异步”是假的:虽然在运算结束后使用事件对调用者进行通知,但由于运算是在主线程上进行的,所以调用过程仍是同步的。步骤四其实只是展示了一下事件的简单用法,如果真正实现异步,则需要在控件中使用多线程。

在ActiveX控件中使用多线程时需要注意的是:引发事件(即调用Fire_XXXX)必须在窗口线程中进行,否则会导致事件不能被 ActiveX控件的容器处理。如果事件发生时执行代码的线程不是窗口线程。那么应该使用PostMessage或SendMessage来通知窗口线 程,并在消息处理函数中执行Fire_XXXX。为了使用控件的消息机制,还应该在CCalc的构造函数中将m_bWindowOnly字段设置为 TRUE。

以下是改为多线程后的部分示例代码:

STDMETHODIMP CCalc::AddAsync(DOUBLE a, DOUBLE b)
{
	m_a = a;
	m_b = b;

	_beginthreadex(NULL, NULL, AddMethod, this, NULL, NULL);

	return S_OK;
}

unsigned __stdcall CCalc::AddMethod(LPVOID arg)
{
	CCalc* pThis = (CCalc*)arg;
	pThis->m_result = pThis->m_a + pThis->m_b;

	pThis->SendMessage(WM_ADDCOMPLETED);

	return 0;
}

LRESULT CCalc::OnAddCompleted(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
	Fire_AddCompleted(&m_result);

	return 0;
}

至此,一个简单的ActiveX控件就开发完成了。关于ActiveX控件的打包部署等问题,请关注《使用ATL开发ActiveX控件 – 控件的打包部署》。

本文示例所使用的开发环境为Visual Studio 2010。

[转载]SQL Server时间算法总结

mikel阅读(1027)

[转载]SQL Server时间算法总结 – Face Code,Brain bloom – 博客园.

   1:  DECLARE @Date  DATETIME
   2:  SET @Date=GETDATE()
   3:  --前一天,给定日期的前一天
   4:  SELECT DATEADD(DAY,-1,@Date) AS '前一天'
   5:  --后一天,给定日期的后一天
   6:  SELECT DATEADD(DAY,1,@Date) AS '后一天'
   7:  GO
   8:  
   9:  
  10:  --月初,计算给定日期所在月的第一天
  11:  --这个计算的技巧是先计算当前日期到“1900-01-01”的时间间隔数,然后把它加到“1900-01-01”上来获得特殊的日期,这个技巧可以用---来计算很多不同的日期。
  12:  DECLARE @Date  DATETIME
  13:  SET @Date=GETDATE()
  14:  SELECT DATEADD(MONTH,DATEDIFF(MONTH,'1900-01-01',@Date),'1900-01-01') AS '所在月的第一天'
  15:  --精简算法,根据SQL Server的时间表示方式可知,'1900-01-01' 可以用0代替
  16:  SELECT DATEADD(MONTH,DATEDIFF(MONTH,0,@Date),0) AS '所在月的第一天'
  17:  --上面两种算法精确到天 时分秒均为00:00:00.000
  18:  --下面算法课以保留时分秒
  19:  --思路:用给定日期减去月第一天与给定日期差的天数
  20:  SELECT DATEADD(DAY,1-DATEPART(DAY,@Date),@Date)
  21:  GO
  22:  
  23:  --月末,计算给定日期所在月的最后一天
  24:  DECLARE @Date  DATETIME
  25:  SET @Date=GETDATE()
  26:  --思路:当前月的下一月1号在减1天
  27:  SELECT DATEADD(DAY,-1,DATEADD(MONTH,1+DATEDIFF(MONTH,'1900-01-01',@Date),'1900-01-01')) AS '所在月的最一天'
  28:  SELECT DATEADD(MONTH,1+DATEDIFF(MONTH,'1900-01-01',@Date),'1900-01-01')-1 AS '所在月的最一天'
  29:  --1900-01-01 用0代替
  30:  SELECT DATEADD(DAY,-1,DATEADD(MONTH,1+DATEDIFF(MONTH,0,@Date),0)) AS '所在月的最一天'
  31:  SELECT DATEADD(MONTH,1+DATEDIFF(MONTH,0,@Date),0)-1 AS '所在月的最一天'
  32:  --思路:与月初计算思路相同
  33:  SELECT DATEADD(MONTH,DATEDIFF(MONTH,'1989-12-31',@Date),'1989-12-31') AS '所在月的最一天'
  34:  --精简算法,'1989-12-31' 用-1代替
  35:  SELECT DATEADD(MONTH,DATEDIFF(MONTH,-1,@Date),-1) AS '所在月的最一天'
  36:  --保留时分秒的算法
  37:  SELECT DATEADD(DAY,-1,DATEADD(MONTH,1,DATEADD(DAY,1-DATEPART(DAY,@Date),@Date)))
  38:  GO
  39:  
  40:  --其他月计算
  41:  
  42:  --计算给定日期所在月的上月第一天
  43:  DECLARE @Date  DATETIME
  44:  SET @Date=GETDATE()
  45:  --当前月第一天减去一个月
  46:  SELECT DATEADD(MONTH,-1,DATEADD(MONTH,DATEDIFF(MONTH,0,@Date),0)) AS '上月第一天'
  47:  --简化
  48:  SELECT DATEADD(MONTH,DATEDIFF(MONTH,0,@Date)-1,0) AS '上月第一天'
  49:  --另一种当前月第一天算法
  50:  SELECT DATEADD(MONTH,-1,DATEADD(DAY,1-DATEPART(DAY,@Date),@Date)) '上月第一天'
  51:  GO
  52:  
  53:  --计算给定日期所在月的上月最后一天
  54:  DECLARE @Date  DATETIME
  55:  SET @Date=GETDATE()
  56:  --当前月第一天减去一天
  57:  SELECT DATEADD(DAY,-1,DATEADD(MONTH,DATEDIFF(MONTH,0,@Date),0)) AS '上月最后一天'
  58:  --另一种当前月第一天算法
  59:  SELECT DATEADD(DAY,-1,DATEADD(DAY,1-DATEPART(DAY,@Date),@Date)) '上月最后一天'
  60:  SELECT DATEADD(DAY,1-DATEPART(DAY,@Date),@Date)-1 '上月最后一天'
  61:  --另一种算法,不能用当前月的最后一天加一个月,因为当前月可能是30天。
  62:  --例如 SELECT DATEADD(MONTH,1,'2010-06-30') --结果是2010-07-30而不是2010-07-31,
  63:  --这也是月末算法采用下月第一天减1天计算的原因
  64:  --但是如果计算月是31天择无此问题
  65:  --例如 SELECT DATEADD(MONTH,1,'2010-05-31') --结果是2010-06-30
  66:  --因此下面算法是正确的,-1 表示'1899-12-31 00:00:00.000'-- SELECT CONVERT(DATETIME,-1)  
  67:  SELECT DATEADD(MONTH,DATEDIFF(MONTH,-1,@Date)-1,-1)
  68:  --另一种当前月算法
  69:  SELECT DATEADD(DAY,-1,DATEADD(DAY,1-DATEPART(DAY,@Date),@Date)) '上月最后一天'
  70:  --简化
  71:  SELECT DATEADD(DAY,0-DATEPART(DAY,@Date),@Date) '上月最后一天'
  72:  GO
  73:  
  74:  --计算给定日期所在月的下月第一天
  75:  DECLARE @Date  DATETIME
  76:  SET @Date=GETDATE()
  77:  --当前月第一天加一个月
  78:  SELECT DATEADD(MONTH,1,DATEADD(MONTH,DATEDIFF(MONTH,0,@Date),0)) AS '下月第一天'
  79:  --简化
  80:  SELECT DATEADD(MONTH,DATEDIFF(MONTH,0,@Date)+1,0) AS '下月第一天'
  81:  --另一种当前月第一天算法
  82:  SELECT DATEADD(MONTH,1,DATEADD(DAY,1-DATEPART(DAY,@Date),@Date)) '下月第一天'
  83:  GO
  84:  
  85:  --计算给定日期所在月的下月最后一天
  86:  DECLARE @Date  DATETIME
  87:  SET @Date=GETDATE()
  88:  --当前月第一天加2个月再减去1天
  89:  SELECT DATEADD(DAY,-1,DATEADD(MONTH,2,DATEADD(MONTH,DATEDIFF(MONTH,0,@Date),0))) AS '下月最后一天'
  90:  --简化
  91:  SELECT DATEADD(DAY,-1,DATEADD(MONTH,DATEDIFF(MONTH,0,@Date)+2,0)) AS '下月最后一天'
  92:  SELECT DATEADD(MONTH,DATEDIFF(MONTH,0,@Date)+2,0)-1 AS '下月最后一天'
  93:  --另一种算法
  94:  SELECT DATEADD(MONTH,DATEDIFF(MONTH,-1,@Date)+1,-1) '下月最后一天'
  95:  --另一种当前月第一天算法
  96:  SELECT DATEADD(DAY,-1,DATEADD(MONTH,2,DATEADD(DAY,1-DATEPART(DAY,@Date),@Date))) '下月最后一天'
  97:  GO
  98:  
  99:  --所在星期的第一天,计算给定日期所在星期的第1天(星期日为第一天)
 100:  DECLARE @Date  DATETIME
 101:  SET @Date= GETDATE()
 102:  --与SQL Server语言版本相关的算法
 103:  --思路:当前日期+星期日(每周的第1天)与当前日期的差的天数
 104:  --DATEPART(WEEKDAY,DATE)的返回值与@@DATEFIRST相关
 105:  SET DATEFIRST 7 -- 或者设置为美国英语SET LANGUAGE us_english; (星期日为第一天) 
 106:  SELECT DATEADD(WEEKDAY,1-DATEPART(WEEKDAY,@Date),@Date) AS '所在星期的第一天,星期日'
 107:  --星期日,与SQL Server语言版本或@@DATEFIRST无关
 108:  --'1989-12-31' 是星期日,'1989-12-31' 再加上(当前日期与1989-12-31差的星期数)个星期
 109:  SELECT DATEADD(WEEK,DATEDIFF(WEEK,-1,@Date),-1) AS '所在星期的星期日'
 110:  --或者
 111:  SELECT DATEADD(WEEK,DATEDIFF(WEEK,6,@Date),6) AS '所在星期的星期日'
 112:  GO
 113:  
 114:  
 115:  --所在星期的第二天,计算给定日期所在星期的第2天(星期日为第一天)
 116:  DECLARE @Date  DATETIME
 117:  SET @Date= GETDATE()
 118:  --思路:当前日期+星期一(每周的第2天)与当前日期的差的天数
 119:  --DATEPART(WEEKDAY,DATE)的返回值与@@DATEFIRST相关
 120:  SET DATEFIRST 7 -- 或者设置为美国英语SET LANGUAGE us_english; (星期日为第一天) 
 121:  SELECT DATEADD(DAY,2-DATEPART(WEEKDAY,@Date),@Date) AS '所在星期的第二天,星期一'
 122:  --星期一,与SQL Server语言版本或@@DATEFIRST无关
 123:  --'1900-01-01' 是星期一,'1900-01-01' 再加上(当前日期与1900-01-01差的星期数)个星期
 124:  SELECT DATEADD(WEEK,DATEDIFF(WEEK,0,@Date),0) AS '所在星期的星期一'
 125:  GO
 126:  
 127:  --上个星期第一天,计算给定日期所在星期的上一个星期日(星期日为第一天)
 128:  DECLARE @Date  DATETIME
 129:  SET @Date= GETDATE()
 130:  --思路:当前日志所在星期的星期日再减1周
 131:  --DATEPART(WEEKDAY,DATE)的返回值与@@DATEFIRST相关
 132:  SET DATEFIRST 7 -- 或者设置为美国英语SET LANGUAGE us_english; (星期日为第一天) 
 133:  SELECT DATEADD(WEEK,-1,DATEADD(DAY,1-DATEPART(WEEKDAY,@Date),@Date)) AS '上个星期第一天,星期日'
 134:  --一周等于7天
 135:  SELECT DATEADD(DAY,-7,DATEADD(DAY,1-DATEPART(WEEKDAY,@Date),@Date)) AS '上个星期第一天,星期日'
 136:  --简化
 137:  SELECT DATEADD(DAY,-6-DATEPART(WEEKDAY,@Date),@Date) AS '上个星期第一天,星期日'
 138:  --上个星期日,与SQL Server语言版本或@@DATEFIRST无关
 139:  SELECT DATEADD(WEEK,-1+DATEDIFF(WEEK,-1,@Date),-1) AS '上个星期日'
 140:  --或者
 141:  SELECT DATEADD(WEEK,DATEDIFF(WEEK,6,@Date),-1) AS '上个星期日'
 142:  GO
 143:  
 144:  
 145:  --下个星期第一天,计算给定日期所在星期的下一个星期日(星期日为第一天)
 146:  DECLARE @Date  DATETIME
 147:  SET @Date= GETDATE()
 148:  --思路:当前日志所在星期的星期日再加1周
 149:  --DATEPART(WEEKDAY,DATE)的返回值与@@DATEFIRST相关
 150:  SET DATEFIRST 7 -- 或者设置为美国英语SET LANGUAGE us_english; (星期日为第一天) 
 151:  SELECT DATEADD(WEEK,1,DATEADD(DAY,1-DATEPART(WEEKDAY,@Date),@Date)) AS '下个星期第一天,星期日'
 152:  --一周等于7天
 153:  SELECT DATEADD(DAY,7,DATEADD(DAY,1-DATEPART(WEEKDAY,@Date),@Date)) AS '下个星期第一天,星期日'
 154:  --简化
 155:  SELECT DATEADD(DAY,8-DATEPART(WEEKDAY,@Date),@Date) AS '下个星期第一天,星期日'
 156:  --下个星期日,与SQL Server语言版本或@@DATEFIRST无关
 157:  SELECT DATEADD(WEEK,1+DATEDIFF(WEEK,-1,@Date),-1) AS '下个星期日'
 158:  --或者
 159:  SELECT DATEADD(WEEK,DATEDIFF(WEEK,-1,@Date),6) AS '下个星期日'
 160:  GO
 161:  
 162:  --判断给定日期是星期几
 163:  DECLARE @Date  DATETIME
 164:  SET @Date= GETDATE()
 165:  --DATEPART(WEEKDAY,DATE)的返回值与@@DATEFIRST相关
 166:  SET DATEFIRST 7 -- 或者设置为美国英语SET LANGUAGE us_english; (星期日为第一天) 
 167:  SELECT DATEPART(WEEKDAY,@Date) --返回值 1-星期日,2-星期一,3-星期二......7-星期六
 168:  --上面算法与SQL 语言版本或 @@DATEFIRST 相关
 169:  --下面算法与SQL Server语言版本或@@DATEFIRST无关
 170:  SELECT DATENAME(WEEKDAY,@Date) '星期'
 171:  GO
 172:  
 173:  
 174:  --年度计算
 175:  DECLARE @Date  DATETIME
 176:  SET @Date=GETDATE()
 177:  --年初,计算给定日期所在年的第一天
 178:  SELECT DATEADD(YEAR,DATEDIFF(YEAR,0,@Date),0) AS '所在年的第一天'
 179:  --年末,计算给定日期所在年的最后一天
 180:  SELECT DATEADD(YEAR,DATEDIFF(YEAR,-1,@Date),-1) AS '所在年的最后一天'
 181:  --上一年年初,计算给定日期所在年的上一年的第一天
 182:  SELECT DATEADD(YEAR,DATEDIFF(YEAR,-0,@Date)-1,0) AS '所在年的上一年的第一天'
 183:  --上一年年末,计算给定日期所在年的上一年的最后一天
 184:  SELECT DATEADD(YEAR,DATEDIFF(YEAR,0,@Date),-1) AS '所在年的上一年的最后一天'
 185:  --下一年年初,计算给定日期所在年的下一年的第一天
 186:  SELECT DATEADD(YEAR,1+DATEDIFF(YEAR,0,@Date),0) AS '所在年的下一年的第一天'
 187:  --下一年年末,计算给定日期所在年的下一年的最后一天
 188:  SELECT DATEADD(YEAR,1+DATEDIFF(YEAR,-1,@Date),-1) AS '所在年的下一年的最后一天'
 189:  GO
 190:  
 191:  --季度计算
 192:  DECLARE @Date  DATETIME
 193:  SET @Date=GETDATE()
 194:  --季度初,计算给定日期所在季度的第一天
 195:  SELECT DATEADD(QUARTER,DATEDIFF(QUARTER,0,@Date),0) AS '当前季度的第一天'
 196:  --季度末,计算给定日期所在季度的最后一天
 197:  SELECT DATEADD(QUARTER,1+DATEDIFF(QUARTER,0,@Date),-1) AS '当前季度的最后一天'
 198:  --上个季度初
 199:  SELECT DATEADD(QUARTER,DATEDIFF(QUARTER,0,@Date)-1,0) AS '当前季度的上个季度初'
 200:  --上个季度末
 201:  SELECT DATEADD(QUARTER,DATEDIFF(QUARTER,0,@Date),-1) AS '当前季度的上个季度末'
 202:  --下个季度初
 203:  SELECT DATEADD(QUARTER,1+DATEDIFF(QUARTER,0,@Date),0) AS '当前季度的下个季度初'
 204:  --下个季度末
 205:  SELECT DATEADD(QUARTER,2+DATEDIFF(QUARTER,0,@Date),-1) AS '当前季度的下个季度末'
 206:  GO
 207:  
 208:  --计算给定日期所在月的天数
 209:  DECLARE @Date DATETIME;
 210:  SET @Date = GETDATE()
 211:  --本月度第一天与下月度第一天所差的天数
 212:  SELECT DATEDIFF(DAY,DATEADD(MONTH,DATEDIFF(MONTH,0,@Date),0),DATEADD(MONTH,1+DATEDIFF(MONTH,0,@Date),0))
 213:  --借助变量简化
 214:  SELECT @Date = DATEADD(MONTH,DATEDIFF(MONTH,0,@Date),0) --本月度第一天
 215:  SELECT DATEDIFF(DAY,@Date,DATEADD(MONTH,1,@Date))
 216:  --另一种思路:给定月最后一天的日期,记为本月天数
 217:  SELECT DAY(DATEADD(MONTH,DATEDIFF(MONTH,-1,@Date),-1))
 218:  GO
 219:  
 220:  --计算给定日期所在季度的天数
 221:  DECLARE @Date DATETIME;
 222:  SET @Date = GETDATE()
 223:  --本季度第一天与下季度第一天所差的天数
 224:  SELECT DATEDIFF(DAY,DATEADD(QUARTER,DATEDIFF(QUARTER,0,@Date),0),DATEADD(QUARTER,1+DATEDIFF(QUARTER,0,@Date),0))
 225:  --借助变量简化
 226:  SELECT @Date = DATEADD(QUARTER,DATEDIFF(QUARTER,0,@Date),0) --本季度第一天
 227:  SELECT DATEDIFF(DAY,@Date,DATEADD(QUARTER,1,@Date))
 228:  GO
 229:  
 230:  --计算给定日期所在年度的天数
 231:  DECLARE @Date DATETIME;
 232:  SET @Date = GETDATE()
 233:  --本年度第一天与下年度第一天所差的天数
 234:  SELECT DATEDIFF(DAY,DATEADD(YEAR,DATEDIFF(YEAR,0,@Date),0),DATEADD(YEAR,1+DATEDIFF(YEAR,0,@Date),0))
 235:  --借助变量简化
 236:  SELECT @Date = DATEADD(YEAR,DATEDIFF(YEAR,0,@Date),0) --本年度第一天
 237:  SELECT DATEDIFF(DAY,@Date,DATEADD(YEAR,1,@Date))
 238:  GO
 239:  
 240:  --判断给定日期所在年是否闰年
 241:  --根据全年总天数判断
 242:  DECLARE @Date DATETIME;
 243:  SET @Date = GETDATE()
 244:  SELECT CASE DATEDIFF(DAY,DATEADD(YEAR,DATEDIFF(YEAR,0,@Date),0),DATEADD(YEAR,1+DATEDIFF(YEAR,0,@Date),0))
 245:    WHEN 365 THEN '平年' ELSE '闰年' END
 246:  --根据二月天数判断
 247:  --给日期的上一年最后一天加2个月,即为当年2月最后一天
 248:  SELECT CASE DAY(DATEADD(MONTH,2,DATEADD(YEAR,DATEDIFF(YEAR,0,@Date),-1))) WHEN 28 THEN '平年' ELSE '闰年' END
 249:  GO
 250:  
 251:  --计算给定日期是当年的第几天
 252:  DECLARE @Date DATETIME;
 253:  SET @Date = GETDATE()
 254:  SELECT DATEPART(DAYOFYEAR,@Date) [DayOfYear];
 255:  SELECT DATENAME(DAYOFYEAR,@Date)  [DayOfYear];
 256:  --另一种思路:当前日期与上年最后一天差的天数
 257:  SELECT DATEDIFF(DAY,DATEADD(YEAR,DATEDIFF(YEAR,0,@Date),-1),@Date)[DayOfYear]
 258:  GO
 259:  
 260:  --计算给定日期是当年的第几周
 261:  DECLARE @Date DATETIME;
 262:  SET @Date = GETDATE()
 263:  SELECT DATEPART(WEEK,@Date) [WeekOfYear]; --返回int型
 264:  SELECT DATENAME(WEEK,@Date) [WeekOfYear]; --返回varchar型
 265:  GO
 266:  
 267:  --计算给定日期是当年的第几月
 268:  DECLARE @Date DATETIME;
 269:  SET @Date = GETDATE()
 270:  SELECT DATEPART(MONTH,@Date) [MonthOfYear]; --返回int型
 271:  SELECT DATENAME(MONTH,@Date) [MonthOfYear]; --返回varchar型
 272:  SELECT MONTH(@Date) [MonthOfYear];--返回int型
 273:  GO
 274:  
 275:  --计算给定日期是当年的第几季度
 276:  DECLARE @Date DATETIME;
 277:  SET @Date = GETDATE()
 278:  SELECT DATEPART(QUARTER,@Date) [QuarterOfYear]; --返回int型
 279:  SELECT DATENAME(QUARTER,@Date) [QuarterOfYear]; --返回varchar型
 280:  GO
 281:  
 282:  --计算给定日期是当月的第几周
 283:  DECLARE @Date DATETIME;
 284:  SET @Date = GETDATE()
 285:  --思路,给定日期是当年的第几周-给定日期所在月第一天是当年的第几周
 286:  SELECT DATEPART(WEEK,@Date)-DATEPART(WEEK,DATEADD(MONTH,DATEDIFF(MONTH,0,@Date),0))+1 [WeekOfMonth]
 287:  SELECT DATEPART(WEEK,@Date)-DATEPART(WEEK,DATEADD(DAY,1-DATEPART(DAY,@Date),@Date))+1 [WeekOfMonth]
 288:  GO
 289:  
 290:  --计算给定日期所在月的第一个星期一是哪天
 291:  DECLARE @Date DATETIME;
 292:  SET @Date = GETDATE()
 293:  --思路,1900-01-01(星期一)加上(给定日志所在月的月6号与1900-01-01差的周数)个周
 294:  --为什么不选7号?如果是7号,那么7好恰好是星期日的话,第一个周一就会算到8号。
 295:  --为什么不选5号?如果5号是星期六,那么周一就跑到上月了。小于5号与这个道理一样。
 296:  SELECT DATEADD(WEEK,DATEDIFF(WEEK,0,DATEADD(DAY,6-DATEPART(DAY,@Date),@Date)),0) '所在月的第一个星期一'
 297:  SELECT DATEADD(WEEK,DATEDIFF(WEEK,0,DATEADD(DAY,6-DATEPART(DAY,@Date),@Date)),7) '所在月的第二个星期一'
 298:  SELECT DATEADD(WEEK,DATEDIFF(WEEK,0,DATEADD(DAY,6-DATEPART(DAY,@Date),@Date)),1) '所在月的第一个星期二'
 299:  SELECT DATEADD(WEEK,DATEDIFF(WEEK,0,DATEADD(DAY,6-DATEPART(DAY,@Date),@Date)),8) '所在月的第二个星期二'
 300:  GO

[转载]SQL Server中约束的介绍

mikel阅读(891)

[转载]SQL Server中约束的介绍 – 编程点滴 – 博客园.

摘要

对于SQL Server中的约束,想必大家并不是很陌生。但是约束中真正的内涵是什么,并不是很多人都很清楚的。本文以详细的文字来介绍了什么是约束,以及如何在数据库编程中应用和使用这些约束,来达到更好的编程效果。(本文部分内容参考了SQL Server联机手册)

内容

数据完整性分类
实体完整性
域完整性
引用完整性
用户定义完整性
PRIMARY KEY约束
DEFAULT约束
CHECK约束
UNIQUE约束
FOREIGN KEY约束

正文

在数据库管理系统中,保证数据库中的数据完整性是非常重要的。所谓数据完整性,就是指存储在数据库中数据的一致性和正确性。约束定义关于列中允许值 的规则,是强制完整性的标准机制。使用约束优先于使用触发器、规则和默认值。查询优化器也使用约束定义生成高性能的查询执行计划。

SQL Server联机丛书中,将数据完整性解释如下:“存储在数据库中的所有数据值均正确的状态。如果数据库中存储有不正确的数据值,则该数据库称为已丧失数据完整性。”强制数据完整性可确保数据库中的数据质量。

例如,如果输入了 employee_id 值为 123 的职员,那么该数据库不应允许其他职员使用同一 ID 值。如果计划将 employee_rating 列的值范围设定为从 1 到 5,则数据库不应接受 6。如果表有一 dept_id 列,该列存储职员的部门编号,则数据库应只允许接受公司中的有效部门编号。

数据完整性分类

在SQL Server中,根据数据完整新措施所作用的数据库对象和范围不同,可以将数据完整性分为以下几种。

实体完整性
域完整性
引用完整性
用户定义完整性

SQL Server联机丛书中指明:“对表进行计划有两个重要步骤:标识列的有效值和确定如何强制列中的数据完整性。”

实体完整性

实体完整性简单的说,就是将表中的每一行看作一个实体。实体完整性要求表的标示符列或主键的完整性。可以通过建立唯一索引、PRIMARY KEY约束、UNIQUE约束,以及列的IDENTITY属性来实施实体完整性。

域完整性

域完整性是指给定列的输入有效性。要求表中指定列的数据具有正确的数据类型、格式和有效的数据范围。强制域有效性的方法有:限制类型(通过数据类 型)、格式(通过 CHECK 约束和规则)或可能值的范围。域完整性通过 FOREIGN KEY 约束、CHECK 约束、DEFAULT 定义、NOT NULL 定义和规则来实现。

引用完整性

引用完整性又称参照完整性。引用完整性维持被参照表和参照表之间的数据一致性,他通过主键(PRIMARY KEY)约束和外键(FOREIGN KEY)约束来实现。引用完整性确保键值在所有表中一致。这样的一致性要求不能引用不存在的值,如果键值更改了,那么在整个数据库中,对该键值的所有引用 要进行一致的更改。在被参照表中,当其主键值被其他表所参照时,该行不能被删除也不允许改变。在参照表中,不允许参照不存在的主键值。

强制引用完整性时,SQL Server 禁止用户进行下列操作:

当主表中没有关联的记录时,将记录添加到相关表中。
更改主表中的值并导致相关表中的记录孤立。
从主表中删除记录,但仍存在与该记录匹配的相关记录。

例如,对于 pubs 数据库中的 sales 和 titles 表,引用完整性基于 sales 表中的外键 (title_id) 与 titles 表中的主键 (title_id) 之间的关系。

用户定义完整性

用户定义完整性使您得以定义不属于其它任何完整性分类的特定业务规则。所有的完整性类型都支持用户定义完整性。

建立和使用约束的目的是保证数据的完整性,约束是SQL Server强制实行的应用规则,他能够限制用户存放到表中数据的格式和可能值。约束作为数据库定义的一部分在CREATE TABLE语句中声明,所以又称做声明完整性约束。约束独立于表结构,可以在不改变表结构情况下,通过ALTER TABLE语句来添加或者删除。在删除一个表时,该表所带的所有约束定义也被随之删除。

PRIMARY KEY约束

在数据库的每个表中,经常有通过一列或者多个列,唯一的标识表中的每一行。就好像我们平时使用的身份证,能够唯一的标识每个人一样。这样的一列或者多个列,被称为主键,通过主键,可以强制表的实体完整性。

每一个表中只有一个PRIMARY KEY约束,更简单的说,他是通过建立唯一索引保证指定列的实体完整性。在使用PRIMARY KEY约束时,该列的空值属性必须定义为NOT NULL,也就是说拥有主键的那一列,不能为空。

由于PRIMARY KEY约束确保唯一数据,所以经常用来定义标识列。标识列就是表中已经指派了标识属性的列。标识属性生成唯一数字。

有些刚刚开始接触SQL Server编程的技术爱好者通常会有这样的疑问,为什么非要在一个表里面建立主键?其实答案是很明显的,建立主键不仅可以保证表内数据的完整性,而且在为表建立主键的同时,Microsoft SQL Server能够通过为主键创建唯一索引强制数据的唯一性。

当在查询中使用主键时,也就是利用主键所在的列作为关键字进行查询,该所因还可以用来对数据进行快速访问。如果在PRIMARY KEY约束中未指定索引类型时,默认情况下所建立的索引为簇索引。该索引只能通过删除PRIMARY KEY约束或其相关表的方法来删除,而不能使用DROP INDEX语句删除。当PRIMARY KEY约束由另一张表的FOREIGN KEY约束引用时,不能删除PRIMARY KEY约束;要删除它,必须先删除FOREIGN KEY约束。

通常建立一列约束时,我们称之为列级PRIMARY KEY约束,应用于多列时,称之为表级PRIMARY KEY约束。

列级PRIMARY KEY约束的定义格式为:

[CONSTRAINT constraint_name]
PRIMARY KEY [CLUSTERED | NONCLUSTERED]
[WITH [FILLFACTOR = fillfactor]]
[ON {filegroup | DEFAULT}]

表级PRIMARY KEY约束定义风格为:

[CONSTRAINT constraint_name]
PRIMARY KEY [CLUSTERED | NONCLUSTERED]
{(column[,…n])}
[WITH [FILLFACTOR = fillfactor]]
[ON {filegroup | DEFAULT}]

在上面的PRIMARY KEY约束定义中,WITH子句设置为PRIMARY KEY约束所建立索引的页面填充度,ON子句指出存储索引的数据库文件组名称。将索引文件和表数据文件分寸到数据库中位于不同硬盘驱动器的数据文件中,有利于减轻单个硬盘的负载。

DEFAULT约束

使用DEFAULT约束,如果用户在插入新行是没有显示为列提供数据,系统会将默认支赋给该列。例如,在一个表的payterms列中,可以让数据 库服务器在用户没有输入时填上”???”或者”fill in later”。默认值约束所提供的默认值约束所提供的默认值可以为常量、函数、系统零进函数、空值(NULL)等等。零进函数包括 CURRENT_TIMESTAMP、SYSTEM_USER、CURRENT_USER、USER和SESSION_USER等。默认值约束的定义格式 为:

[CONSREAINT constraint_name]
DEFAULT constant_expression

其中,constraint_name参数指出所建立的默认值约束名称。Constant_expression表达式为列提供默认值。在使用默认约束是,还应该注意以下两点:

1. 每列只能有一个默认约束。
2. 约束表达式不能参照表中的其他列和其他表、视图或存储过程。

CHECK约束

CHECK约束的主要作用是限制输入到一列或多列中的可能值,从而保证SQL Server数据库中数据的域完整性。例如,可以在建立用户使用库时,强制用户的密码在10位以上。每个标允许建立多个CHECK约束。在CHECK约束中可以包含搜索条件,但不能包含子查询。

同样,我们可以为表中的每个列建立约束,每个列可以拥有多个CHECK约束,但是如果使用CREATE TABLE语句,只能为每个列建立一个CHECK约束。如果CHECK约束被应用于多列时,他必须被定义为表级CHECK约束。

在表达式中,可以输入搜索条件,条件中可以包括AND或者OR一类的连接词。列级CHECK约束只能参照被约束列,而表级CHECK约束则只能参照表中列,它不能参照其他表中列。

例如,我们使用下面的语句在TB_CHECK_CONSTRAINT表中新加入一列ZIP_CODE及其相应的CHECK约束:

ALTER Table TB_CHECK_CONSTRAINT
ADD
ZIP_CODE char(6) null
CONSTRAINT CH_ZIP_CODE check
(ZIP_CODE like ‘[0-9] [0-9] [0-9] [0-9] [0-9] [0-9]’)

同样,我们可以使用CHECK或NOCHECK来打开或者关闭某个约束。例如,下面的语句将关闭上面建立的CH_ZIP_CODE约束:

ALTER Table TB_CHECK_CONSTRAINT
NOCHECK CONSTRAINT CH_ZIP_CODE

如果希望使用编辑器来建立约束关系,需要在数据库关系图中,右击包含约束的表,然后从快捷菜单中选择“约束”命令。或者可以将包含约束的表打开表设计器,在表设计器中右击,然后选择“约束”命令。

UNIQUE约束

该约束应用于表中的非主键列,UNIQUE约束保证一列或者多列的试题完整性,确保这些猎不会输入重复的值。例如,表中UserName列为主键, 但是其中还包括身份证号码列,由于所有身份证号码不可能出现重复,所以可以在此列上建立UNIQUE约束,确保不会输入重复的身份证号码。

它与PRIMARY KEY约束的不同之处在于,UNIQUE约束可以建立在多个列之上,而PRIMARY KEY约束在一个表中只能有一个。

建立UNIQUE约束,可以使用如下办法:

1. 在数据库关系图中右击将包含约束的表,然后从快捷菜单中选择”属性”命令。
-或- 为将包含约束的表打开表设计器,在表设计器中右击,然后从快捷菜单中选择”属性”命令。
2. 选择”索引/键”选项卡。
3. 选择”新建”命令。系统分配的名称出现在”索引名”框中。
4. 在”列名”下展开列的列表,选择要将约束附加到的列。若要将约束附加到多个列,在后续行中选择其它的列。
5. 选择”创建 UNIQUE”复选框。
6. 选择”约束”选项。

当保存表或关系图时,唯一约束即创建在数据库中。

当希望删除UNIQUE索引时,可以使用如下步骤:

1. 在数据库关系图中,右击包含约束列的表,然后从快捷菜单中选择”索引/键”命令。
-或- 为包含约束的表打开表设计器,在表设计器中右击,然后从快捷菜单中选择”索引/键”命令。
2. 从”选定的索引”列表中选择唯一约束。
3. 选择”删除”按钮。

同样,对于一列的UNIQUE约束,我们称之为列级UNIQUE约束,对于多列的UNIQUE约束,我们称之为表级UNIQUE约束。下面给出列级UNIQUE约束的定义格式:

[CONSTRAINT constraint_name]
UNIQUE [CLUSTERED | NONCLUSTERED]
[WITH [FILLFACTOR = fillfactor]]
[ON {filegroup | DEFAULT}]

使用UNIQUE约束的过程中,还需要注意,如果要对允许空值的列强制唯一性。可以允许空值的列附加UNIQUE约束,而只能将主键的约束附加到不允许空值的列。但UNIQUE约束不允许表中受约束列有一行以上的值同时为空。

例如,下面语句为TB_UNIQUE_CONSTRAINT表添加UNIQUE约束:

ALTER Table TB_UNIQUE_CONSTRAINT
ADD
CONSTRAINT UN_PHONE UNIQUE (username, phone)

FOREIGN KEY约束

FOREIGN KEY约束为表中的一列或者多列数据提供数据完整性参照。通常是与PRIMARY KEY约束或者UNIQUE约束同时使用的。

例如,在BookStores表中的author_id列以及title_id列分别参照了Authors表中的author_id列以及 Titles表的title_id列。在向BookStores表中插入新行或修改其中的数据时,这两列的数据值必须在Authors表和Titles表 中已经存在,否则将不能执行插入或者修改操作。

在使用FOREIGN KEY约束是,需要注意以下几点:

1. 一个表最多只能参照253个不同的数据表,每个表也最多只能有253个FOREIGN KEY约束。
2. FOREIGN KEY约束不能应用于临时表。
3. 在实施FOREIGN KEY约束时,用户必须至少拥有被参照表中参照列的SELECT或者REFERENCES权限。
4. FOREIGN KEY约束同时也可以参照自身表中的其他列。
5. FOREIGN KEY约束,只能参照本身数据库中的某个表,而不能参照其他数据库中的表。跨数据库的参照只能通过触发器来实现。

[转载]jquery.simple.tree插件,更简单,兼容性更好的无限树插件!

mikel阅读(1036)

[转载]jquery.simple.tree插件,更简单,兼容性更好的无限树插件! – 我是一只鸟,想飞飞不高! – 博客园.

在这里介绍一款小巧,功能强大,能拖拽,支持异步,且兼容性更高的JQuery Tree插件:

效果如下:

选择:

拖拽:

JQuery.simple.tree.官网地址: http://news.kg/wp-content/uploads/tree/(貌似已经打不开),不过因为操作比较简单,所以我们暂且用之。

前面讲过jquery EasyUI Tree插件,简单易用,但经过测试仍有诸多缺点,

例如:

1、兼容IE8的AJAX有问题。

2、如果异步返回数据较慢,将可能导致加载失败。

3、我们只使用其中的Tree功能,但其体积实在有点庞大。…

而我们需要的是,兼容性好,异步,体积小(用Tree的场景实在比较少,所以还是专用的代码文件比较好。)

好了,我们开始JQuery.simple.tree之旅:

首先,要加载文件,一共三个:CSS、jQuery主文件、还有其本身的js文件;

然后,是定义Tree的代码;

最后,写出这根树的根节点HTML代码;

前台代码如下:

html代码

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml” >
<head runat=”server”>
<title>区域选择</title>
<link rel=”stylesheet” href=”/js/simpletree/jQuery.simple.tree.css” />
<script type=”text/JavaScript src=”/js/jquery1.4.2.min.js”></script>
<script type=”text/JavaScript src=”/js/simpletree/jquery.simple.tree.js”></script>
<script type=”text/JavaScript>
var simpleTreeCollection;
$(document).ready(function(){
simpleTreeCollection = $(.simpleTree).simpleTree({
autoclose: true,
afterClick:function(node){
alert(您选择了: + $(span:first,node).text() + id为: + $(span:first,node).attr(id).substr(2));//此处为何要“.substr(2)”,是因为特殊原因,稍后可以得到解释.如果你仅仅需要取文字,这里可以不取ID。
},
afterDblClick:function(node){
//alert(“text-“+$(‘span:first’,node).text());//双击事件
},
afterMove:function(destination, source, pos){
//alert(“destination-“+destination.attr(‘id’)+” source-“+source.attr(‘id’)+” pos-“+pos);//拖拽事件
},
afterAjax:function()
{
//alert(‘Loaded’);
},
animate:true
//,docToFolderConvert:true
});
});
</script>
</head>
<body>
<ul class=”simpleTree”>
<li class=”root”><span>区域选择</span>
<ul>
<li id=”root0″ class=”open”><span>中国</span>
<ul class=”ajax”>
<li id=’0′>{url:/common/GetGroupHtmlByPid.ashx?pid=0}</li>
</ul>
</li>
</ul>
</li>
</ul>
</body>
</html>

后台响应代码:

GetGroupHtmlByPid.ashx.cs

public class GetGroupHtmlByPid : IHttpHandler
{
GroupManager group;
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = text/plain;
int parentId = 1;
int type = 0;
string resultStr = string.Empty;
if (!context.Request.QueryString[pid].IsNullOrEmpty())
{
Int32.TryParse(context.Request.QueryString[pid], out parentId);
}
if (!context.Request.QueryString[type].IsNullOrEmpty())
{
Int32.TryParse(context.Request.QueryString[type], out type);
}

if (parentId >= 0)
{
try
{
group = new GroupManager((GroupType)type);
var subAg = group.AllGroups.Where(c => c.ParentId == parentId);
resultStr += <ul>;
foreach (Base_group item in subAg)
{
resultStr += <li id=\“” + item.GroupId + \><span id=\1_ + item.GroupId + \> + item.GroupName + </span>;//这里可以解释前台代码为何要.substr(2);
resultStr += <ul class=’ajax’><li>{url:/common/GetGroupHtmlByPid.ashx?pid= + item.GroupId + }</li></ul>;
resultStr += </li>;
}
resultStr += </ul>;
}
catch (Exception ex)
{
}
}
context.Response.Write(resultStr);
}

public bool IsReusable
{
get
{
return false;
}
}
}

后台看起来有点别扭,因为这个插件本身只支持HTML节点加载的,不过网上有人进行扩展了,用了JSON,不过个人感觉这对速度影响实在微乎其微,还是直接封装出HTML代码的。

总结一下jquery.simple.tree插件的优缺点:

优点:体积小,兼容性高,可异步,支持拖拽。

缺点:如果初始化的时候就需要异步加载,则需要手动更改它的几行代码。例如我的例子中。

本插件还有一个特别的功能,支持拖拽,可以用于后台维护无限分类,非常方便,有待读者自己去发掘,希望本文能够抛砖引玉,对你有所帮助!

源插件下载地址:http://plugins.jquery.com/project/SimpleTree

我的修改后的下载地址:simpletree.rar

我只修改了2行代码,以便在第一次初始化时就加载异步的内容。

[转载]Asp.net中文件的压缩与解压

mikel阅读(1050)

[转载]Asp.net中文件的压缩与解压 – 清风飘过 – 博客园.

这里笔者为大家介绍在ASP.NET中使用文件的压缩与解压。在ASP.NET中使用压缩给大家带来的好处是显而易见的,首先是减小了服务器端 文件存储的空间,其次下载时候下载的是压缩文件想必也会有效果吧,特别是比较大的文件。有的客户可能会很粗心上传的是文件,那么可以通过判断后缀名来判断 文件,不是压缩文件,就可以压缩文件,在存储。

这里笔者引用了一个DLL文件(ICSharpCode.SharpZipLib.dll)(包含在本文代码中),调用其中的函数,就可以对文件进行压缩及解压了。其中压缩笔者主要用到的函数是

1 /// <summary> 2 /// 压缩文件 3 /// </summary> 4 /// <param name="fileName">要压缩的所有文件(完全路径)</param> 5 /// <param name="name">压缩后文件路径</param> 6 /// <param name="Level">压缩级别</param> 7   public void ZipFileMain(string[] filenames, string name, int Level) 8 { 9 ZipOutputStream s = new ZipOutputStream(File.Create(name)); 10 Crc32 crc = new Crc32(); 11 //压缩级别 12 s.SetLevel(Level); // 0 - store only to 9 - means best compression 13 try 14 { 15 foreach (string file in filenames) 16 { 17 //打开压缩文件 18 FileStream fs = File.OpenRead(file); 19 20 byte[] buffer = new byte[fs.Length]; 21 fs.Read(buffer, 0, buffer.Length); 22 23 //建立压缩实体 24 ZipEntry entry = new ZipEntry(System.IO.Path.GetFileName(file)); 25 26 //时间 27 entry.DateTime = DateTime.Now; 28 29 // set Size and the crc, because the information 30 // about the size and crc should be stored in the header 31 // if it is not set it is automatically written in the footer. 32 // (in this case size == crc == -1 in the header) 33 // Some ZIP programs have problems with zip files that don't store 34 // the size and crc in the header. 35 //空间大小 36 entry.Size = fs.Length; 37 fs.Close(); 38 crc.Reset(); 39 crc.Update(buffer); 40 entry.Crc = crc.Value; 41 s.PutNextEntry(entry); 42 s.Write(buffer, 0, buffer.Length); 43 } 44 } 45 catch 46 { 47 throw; 48 } 49 finally 50 { 51 s.Finish(); 52 s.Close(); 53 } 54 55 }

解压缩的主要代码

1 /// <summary> 2 /// 解压文件 3 /// </summary> 4 /// <param name="ZipPath">被解压的文件路径</param> 5 /// <param name="Path">解压后文件的路径</param> 6 public void UnZip(string ZipPath,string Path) 7 { 8 ZipInputStream s = new ZipInputStream(File.OpenRead(ZipPath)); 9 10 ZipEntry theEntry; 11 try 12 { 13 while ((theEntry = s.GetNextEntry()) != null) 14 { 15 string fileName = System.IO.Path.GetFileName(theEntry.Name); 16 17 //生成解压目录 18 Directory.CreateDirectory(Path); 19 20 if (fileName != String.Empty) 21 { 22 //解压文件 23 FileStream streamWriter = File.Create(Path + fileName); 24 25 int size = 2048; 26 byte[] data = new byte[2048]; 27 while (true) 28 { 29 size = s.Read(data, 0, data.Length); 30 if (size > 0) 31 { 32 streamWriter.Write(data, 0, size); 33 } 34 else 35 { 36 37 streamWriter.Close(); 38 streamWriter.Dispose(); 39 break; 40 } 41 } 42 43 streamWriter.Close(); 44 streamWriter.Dispose(); 45 } 46 } 47 } 48 catch 49 { 50 throw; 51 } 52 finally 53 { 54 s.Close(); 55 s.Dispose(); 56 } 57 } 58 }

那么我这里做了个简单的测试程序(点击下载

这里已知道要被压缩文件,这里只需填入要被压缩到的路径(”D:\text\”)解压路径一样。这里解压级别越大,压缩的就越厉害。

可以看测试小程序,将解压/压缩引入到你的项目中

好了,如果本文对你有作用请您留个言语,让笔者知道 ^_^

[转载]QQ窗口抓取及如何进行自动化操作

mikel阅读(1026)

[转载]QQ窗口抓取及如何进行自动化操作 – wuhuacong(伍华聪)的专栏 – 博客园.

本文在文章开始,先介绍下窗口的抓取软件,Spy++及AccExplorer32.exe,前者是大名鼎鼎的微软出品,几乎可以抓取所有的Windows窗口及控件(其实也是一个窗口),另外一个也是类似,功能可以互补一下。

首先看看两者的界面,在抓取QQ的【查找联系人/群/企业】的窗口时候的情况:


Sp++的界面


AccExplorer32.exe界面

两者界面不同,不过基本功能有重叠,Spy++提供的功能可能会更多一些,这两个软件都可以对列出的窗口进行一系列的操作,如可以找到相关的窗口信息,窗口位置,以及对各种窗口操作的信息,包括鼠标、键盘等一系列的操作都可以模拟出来,非常强大。

为 了模拟抓取窗口以及对窗口的各种操作,我们可以通过FindWindow和FindWindowEx、SendMessage、PostMessage等 Windows消息来进行处理,便可实现基本的窗口、控件操作,另外按钮的操作,我们则可以模拟鼠标单击某个坐标点的方式实现按钮的单击操作模拟。 模拟的QQ界面窗口如下所示,是一个查找窗口的。

我们通过抓取窗口信息,我们看到该窗口下面只有两个可见窗口,分别对应两个输入控件,可以发现该窗口的一个输入(账号和昵称输入框中的任何一个)的Class 名称如下所示:

首先我们来创建一个界面,如下所示,用来模拟相关的操作。

我们在辅助类中定义几个函数用来实现窗口的操作

[DllImport(user32.dll)]

private static extern IntPtr FindWindowEx(IntPtr parent, IntPtr childAfter, string className, string windowName);

[DllImport(user32.dll, EntryPoint = FindWindow)]
private static extern IntPtr FindWindowWin32(string className, string windowName);

[DllImport(user32.dll )]
public static extern int GetClassName(IntPtr hWnd, [Out] StringBuilder className, int maxCount);

[DllImport(user32.dll)]
private static extern int SendMessage(IntPtr window, int message, int wparam, int lparam);

[DllImport(user32, CharSet = CharSet.Auto)]
private extern static int SendMessage(IntPtr hWnd, int wMsg, int wParam, string lpstring);

[DllImport(user32.dll)]
private static extern int PostMessage(IntPtr window, int message, int wparam, int lparam);

在实际的按钮操作代码中,我们简化了具体的操作,只需要调用辅助类就可以了

private void btnSearch_Click(object sender, EventArgs e)

{
Win32Window win
= Win32Window.FindWindow(null, this.txtWindowName.Text);
if (win != null)
{
ArrayList list
= win.Children;
foreach (Win32Window sub in list)
{
if (sub.Visible && sub.ClassName == ATL:30A4D1D8)
{
sub.SendMessage(WindowMessage.WM_SETTEXT,
0, this.txtInput.Text);
}
}
}
int x = 288;
int y = 328;
win.ClickWindow(
left, x, y, false);
}

其中位置信息时通过Spy++监控出来的信息。

最后结果如下所示,实现控件内容的修改,并执行了单击按钮的操作,弹出添加好友确认信息。

如果要进行进一步的操作,在继续对弹出的窗口进一步分析即可,其他所有的窗口操作,原理一样,这样就可以实现很多程序的自动模拟操作,是不是很方便呢。

[转载]从一个WEB请求说开去(三)

mikel阅读(1000)

[转载]从一个WEB请求说开去(三) – 大河 – 博客园.

由于最近一段时间忙的我晕头转向,所以一直没时间继续我的WEB请求之旅,深感抱歉。

开篇之前,我必须向大家道个歉,由于我的知识水平有限,对ASP.NET没有一个系统性的认知,所以不对的地方请朋友们不吝赐教。说真的,我特别怕由于我的认知不足而误导大家,请大家一定要带着脑袋以批判的角度来阅读拙作。砖头准备好了吗?开始。

上文我们主要描述了iis6.0的两个核心组件WAS和Worker Progress,而本文重点讲述一下WEB请求在工作进程中都经历了什么,下面我把描述工作进程的图示放大,如下:

我们知道,当一个有效的WEB请求到达HTTP.SYS后,发现没有相应有效的工作进程,则HTTP.SYS会告诉WAS(svchost.exe),以 为之创建并启动一个工作进程(w3wp.exe)。在启动工作进程的过程中加载ISAPI(非托管代码)以及CLR(托管代码),然后在工作进程中创建应 用程序域。其实如上一系列操作只是为WEB请求准备好其运行环境。

当一个WEB请求进入已经准备好的工作进程边界(工作进程从HTTP.SYS的应用程序池对应的消息队列中取出该WEB请求),那此时首先会经过 ISAPI FILTER的处理,比如修改http报头和URL等,具体功能参见上文。接下来就会将处理的WEB请求交给ISAPI EXTENSION。那么ISAPI EXTENSION会干什么呢?我们先看下图:

我们从上图可以看出,它就是一个应用程序扩展名的映射,即文件扩展名与处理该文件的应用程序的一个映射表,接下来我们看看具有aspx扩展名的文件是由哪个应用程序集处理(dll)的,如下图:

看到了吗?其实也就告诉我们对于aspx扩展名的文件,要交给aspnet_isapi.dll处理,其实大部分文件都映射到了 aspnet_isapi.dll,也就是说大部分动态的web请求文件都交由程序集aspnet_isapi.dll来处理。对于静态文件比如jpg、 js、以及css等都会直接将文件返回给客户端。注意:aspnet_isapi.dll是一个非托管的Win32动态库,里面封装了很多用于与web进 行交互的函数,它的处理速度那是相当的快。另外它被加载到了工作进程中,也就是说非托管的aspnet_isapi.dll与托管的web应用都处于一个 工作进程中,这显然会加快其处理速度。跨进程访问是要付出代价的,所以我们不必为此担心。那么如何才能调用aspnet_isapi.dll提供的一系列 服务呢,这就引出了ISAPIRuntime,它的主要功能就是负责ISAPI扩展的非托管代码与托管代码之间的沟通与交互。您只要记住这点就行了,具体 实现细节我认为没必要深究。如果您对此感兴趣可以借助reflector.exe等工具进行跟踪研判。

我们的WEB请求走到到哪儿了,没错,它经过ISAPI顺利的进入到了ASP.NET通道接下来他会一直走啊走,经过HttpApplication、httphandles等经过处理后将其响应返回给http.sys,最终到达客户端浏览器。

本来关于IIS6.0还有很多说不完的话题,比如ASP.NET application的生命周期,以及web page的生命周期、以及如何自定义httpmodules,如何自定义httphandles等等,网上这方面的资料已经很多了,我也不再赘述。

其实写到此我只大概介绍了IIS6.0的三个核心组件HTTP.SYS、WAS以及Worker Progress,另外两个(Inetinfo.exe和IIS MetaBase)只是轻描淡写,如果有时间我会继续说说关于这两个核心组件的内容,另外会顺带说说SSL。

为了给大家一个关于WEB请求之旅的整体印象,我会在下一篇做个总结。如有疏漏之处还望朋友们多多海涵。

[转载]简单但有用的SQL脚本Part6:特殊需要的行转列

mikel阅读(1071)

[转载]简单但有用的SQL脚本Part6:特殊需要的行转列 – 我帅故我在 – 博客园.

一、数据库SQL Server行转列

需求:原始表的数据的结构如图1所示,把相同的guidcode值转换为列值。


(图1

目标:我们希望达到的效果如图2所示,这里的guid变成唯一的了,这行的记录中包含了这个guid所对应的code字段值。


(图2

分析与实现:要实现图1到图2的转变,这就是所谓的行转列,下面我们来讲讲具体的实现:

1. 首先我们先创建一个测试表,方便后面的效果展现;

创建表
if exists (select * from sysobjects where id = OBJECT_ID([TempTable_Base]) and OBJECTPROPERTY(id, IsUserTable) = 1)
DROP TABLE [TempTable_Base]

CREATE TABLE [TempTable_Base] (
[id] [int] IDENTITY (1, 1) NOT NULL,
[guid] [varchar] (50) NULL,
[code] [varchar] (50) NULL)

SET IDENTITY_INSERT [TempTable_Base] ON

INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 1,91E92DCB-141A-30B2-E6CD-B59EABD21749,A)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 2,91E92DCB-141A-30B2-E6CD-B59EABD21749,C)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 3,91E92DCB-141A-30B2-E6CD-B59EABD21749,E)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 4,91E92DCB-141A-30B2-E6CD-B59EABD21749,O)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 5,91E92DCB-141A-30B2-E6CD-B59EABD21749,G)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 6,79DD7AB9-CE57-9431-B020-DF99731FC99D,A)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 7,79DD7AB9-CE57-9431-B020-DF99731FC99D,O)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 8,79DD7AB9-CE57-9431-B020-DF99731FC99D,E)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 9,79DD7AB9-CE57-9431-B020-DF99731FC99D,F)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 10,79DD7AB9-CE57-9431-B020-DF99731FC99D,O)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 11,79DD7AB9-CE57-9431-B020-DF99731FC99D,B)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 12,79DD7AB9-CE57-9431-B020-DF99731FC99D,D)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 13,79DD7AB9-CE57-9431-B020-DF99731FC99D,F)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 14,D61651D9-1B0A-0362-EE91-A805AA3E08F2,O)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 15,D61651D9-1B0A-0362-EE91-A805AA3E08F2,D)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 16,D61651D9-1B0A-0362-EE91-A805AA3E08F2,F)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 17,D61651D9-1B0A-0362-EE91-A805AA3E08F2,C)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 18,D61651D9-1B0A-0362-EE91-A805AA3E08F2,U)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 19,D61651D9-1B0A-0362-EE91-A805AA3E08F2,F)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 20,4802F0CD-B53F-A3F5-1C78-2D7424579C06,A)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 21,3CCBFF9F-827B-6639-4780-DA7215166728,O)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 22,3CCBFF9F-827B-6639-4780-DA7215166728,M)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 23,3CCBFF9F-827B-6639-4780-DA7215166728,C)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 24,3CCBFF9F-827B-6639-4780-DA7215166728,M)

SET IDENTITY_INSERT [TempTable_Base] OFF

SELECT * FROM [TempTable_Base]

2. 使用SQL Server2005row_number()函数来进行分组排名,把同一个guid的数据进行标识,这样就可以让不同的guid具有数字1以后的数值,这样就可以作为新的列名来进行行转列了,执行下面的SQL就可以达到图3所示的效果了。

对数据进行分组
select base.*,row_number() over (partition by guid order by ID) as depth
from [TempTable_Base] as base
order by id


(图3

3. 生成分组表,把上面的结构插入到一张新的表中,把数据保存为一个表是为了方便后面的统计使用。

生成分组表
select base.*,row_number() over (partition by guid order by ID) as depth
into [TempTable_Depth]
from [TempTable_Base] as base
order by id

SELECT * FROM [TempTable_Depth]

4. 动态行转列的SQL,因为你不知道列数据会有多少,所以我们使用下面的SQL来动态的生成列名,结果就如图2所示。

行转列
declare @s nvarchar(max)
set @s=
Select @s=@s+,+quotename([depth])+=max(case when [depth]=+quotename([depth],””)+ then code else null end)
from [TempTable_Depth] group by [depth] order by [depth]
exec(select guid +@s+ from [TempTable_Depth] group by guid order by guid)

二、数据库SQL Server生成矩阵数据

需求:我们回过头来看看图1,比如guid91E92DCB141A30B2E6CDB59EABD21749code值包括A,C,E,O,G这五个,我们可以想象guid为一个用户,这五个code就是这个用户访问网站页面的顺序,那如果我想看到一个从A->CC-> EE-> OO -> G这个矩阵中两两对应在数据库中出现了多少次?

目标:我们希望达到的效果如图4所示,这个图可以解读为A->A的个数是0A->C的个数是1D->F的个数是2,这些统计方法可能会在一些需要进行对比分析的过程中用到。


(图4

分析与实现:要实现图4的效果,这就需要我们对数据进行矩阵转换,下面我们来讲讲具体的实现:

1. 首先我们需要巧用left joindepth字段,depth就相当于用户访问的顺序,所以我们可以把之前有序的拷贝一份到右边去,效果如图5所示。

巧用左连接和depth字段进行处理
select a.id,a.guid,a.code as code_from,b.code as code_to
from [TempTable_Depth] as a
left join [TempTable_Depth] as b
on a.guid = b.guid and a.[depth] = b.[depth]1


(图5

2. 为了方便统计,把上面的成果保存到一个表中,之后就是为所有唯一的code值生成一个以code作为元素的二维矩阵的原始数据,它就相当于一个临时表一样,用来保存每一个code对应的个数,效果如图6所示。

生成From和To的对应关系
select a.id,a.guid,a.code as code_from,b.code as code_to
into [TempTable_FromTo]
from [TempTable_Depth] as a
left join [TempTable_Depth] as b
on a.guid = b.guid and a.[depth] = b.[depth]1

生成矩阵
select distinct code_from ,1 as num
into [TempTable_t1]
from [TempTable_FromTo]
order by code_from

select * from [TempTable_t1]

生成一个矩阵表
select a.code_from ,b.code_from as code_to,0 as counts
into [TempTable_t2]
from [TempTable_t1] as a
left join [TempTable_t1] as b
on a.num = b.num
order by a.code_from ,b.code_from

select * from [TempTable_t2]


(图6

3. 现在就需要把统计的A->A这样数据的个数,并把它放入图6中的表中,效果如图7所示。

统计
select code_from ,code_to, count(1) as counts
into [TempTable_t3]
from [TempTable_FromTo]
where code_to is not null
group by code_from ,code_to,guid
order by code_from ,code_to

select * from [TempTable_t3]

更新统计的数字
update a set a.counts = b.counts
from [TempTable_t2] as a,[TempTable_t3] as b
where a.code_from = b.code_from
and a.code_to = b.code_to
and b.counts is not null

select * from [TempTable_t2]


(图7

4. 现在需要做的就是把行转列了,这也没有违背我们的标题啊,呵呵,效果如图8所示。

查询矩阵
declare @s nvarchar(max)
set @s=
Select @s=@s+,+quotename([code_to])+=max(case when [code_to]=+quotename([code_to],””)+ then counts else null end)
from [TempTable_t2] group by [code_to] order by [code_to]
exec(select [code_from] +@s+ from [TempTable_t2] group by [code_from] order by [code_from])

(图8

总结:其实这篇文章我想表达正是这个矩阵的生成方法,在现实中也许并不常用到,但是还是有些技巧性的东西在里面,比如那个dept的用处;再比如a.[depth] = b.[depth]-1这个SQL的巧用;再比如行转列解决矩阵问题;还有动态生成行转列的SQL,其实这里还可以使用SQL Server 2005pivot来解决行转列的问题,这里就不列出来了。希望这篇文章能给你遇到的问题带来一些帮助和启示。

[转载]asp.net mvc 2.0+Silverlight播放器开发的TeamVideo视频播放网站--系列1

mikel阅读(1039)

[转载]asp.net mvc 2.0+Silverlight播放器开发的TeamVideo视频播放网站–系列1 – 爱因斯坦的小脑 – 博客园.

背景:经常有一些电影大家想一起分享,为了照顾到很多同事,以及大家来交流评论电影,我最近抽时间使用ASP.NET mvc2.0和Silverlight播放器来做个视频播放网站。今天就来这里和大家分享下。

播放界面展示:

,,,,ASP.NET mvc这个我知道大家都写了好多,当然我这里不会重点去说明ASP.NET MVC了。我主要想和大家分享的是如何在ASP.NET MVC中使用Silverlight来播放不同的视频。通过不同的id来播放不同的视频。

我使用的Silverlight团队开发的Silverlight Media Framework 2.0来作为播放器的。

smf_block_diagram.png

下载地址:http://smf.codeplex.com/

当然这里有提供了Smooth Streaming播放器,也就是视频直播的那种。结合Smooth Stream Client可以进行视频直播。参考文档:http://smf.codeplex.com/documentation

使用asp.net mvc来创建网站速度确实快。。。。。。我接下来就说明下如何在两天内抽空把整个网站给架好(很简单的网站,所以2,3天搞定)。

1.数据库模型的创建:

image

自己手绘了几下,思考着应该有哪些哪些字段和字段的类型,如上图。

a. Entity Data Model的创建:

数据模型有了,我们就来创建数据库,为了节省时间,我没使用POCO或是Code-First来创建Entity Data Model,直接使用的是系统自动生成edmx文件。

image

b.对Model的验证规则的创建:

没错,对于用户输入的数据我们需要来验证是否符合我们在数据库定义的长度和范围等,所以验证规则的定义是必要的。你当然可以使用JQuery的Validation来在客户验证。例如Video实体的验证如下:

1 [MetadataType(typeof(VideoMetaData))]
2 public partial class Video
3 {
4 // Validation rules for Video class
5
6 [Bind(Exclude = Id)]
7 public class VideoMetaData
8 {
9 [ScaffoldColumn(false)]
10 public object Id { get; set; }
11
12 [Required(ErrorMessage=An Title is required)]
13 [StringLength(255)]
14 public object Title { get; set; }
15
16 [DisplayName(Video URL)]
17 [Required(ErrorMessage=Url is required)]
18 [StringLength(255)]
19 public object Url { get; set; }
20
21 [DisplayName(Leading Actors)]
22 [Required(ErrorMessage=Leading Actors are required)]
23 [StringLength(100)]
24 public object Actors { get; set; }
25
26 [Required(ErrorMessage=Review information is required)]
27 public object Review { get; set; }
28
29 [Required(ErrorMessage=Year is required)]
30 [RegularExpression(@”^\d{4}$, ErrorMessage = Year is not valid)]
31 public object Year { get; set; }
32 }
33 }

需要注意的是这里有’Year’字段是个四位整数,所以我们需要用正则表达式来确定是否年份填写正确。

而在Rating实体的验证规则中需要注意Rating的范围1-5且只能是整数

1 [Required(ErrorMessage=Rating is required)]
2 [Range(1,5,ErrorMessage=Rating must be between 1 and 5)]
3 public object Rating { get; set; }

c.ViewModel部分的创建:

对于ViewModel的部分创建,主要是为了在controller对于view时能够更加容易的传递数据,所以我们定义了ViewModel部分。

例如在视频播放页面的布局如下:

image

所以我们需要给此页面的Model数据包含Video=>Comments=>Rating。它的ViewModel代码如下:

1 public class VideoBrowseViewModel
2 {
3 public Video Video { get; set; }
4
5 int Rating { get; set; }
6
7 public List<Comment> Comments { get; set; }
8 }

d.Controller部分的创建:

先贴上代码来看看:

1 public ActionResult Index()
2 {
3
4 // Retrieve Video from database
5 var VideoModel = mediaDB.Videos.Include(Comments).Include(Ratings).FirstOrDefault();
6
7 float sum = VideoModel.Ratings.Sum(r => r.Rating1);
8
9
10 var viewModel = new VideoBrowseViewModel()
11 {
12 Video = VideoModel,
13 rate=Convert.ToInt32(sum/VideoModel.Ratings.Count),
14 Comments = VideoModel.Comments.ToList()
15 };
16
17 return View(viewModel);
18
19 }

使用include属性来同时得到Video对应的Comments和Ratings。最后需要得到的rate是对于该video的所有rating的平均值,所以需要计算下来传递给view。

e.View界面的传值和Silverlight播放器的源文件选择

上面的传值传过来,在view界面直接绑定很简单,但是如何给Silverlight的播放器来传递数据源呢?

首先需要把xap文件包含在项目中,如下图:

image

接下来是使用JavaScript来为创建一个播放器的object:

1 <script type=text/JavaScript>
2 $(document).ready(function () {
3
4 // the media player
5 var obj = <object data=’data:application/x-silverlight-2,’ type=’application/x-silverlight-2′ width=’100%’ height=’320′>\n;
6 obj = obj + <param name=’source’ value=’ProgressiveDownloadPlayer.xap’ /> \n ;
7 obj = obj + <param name=’onError’ value=’onSilverlightError’ /> \n ;
8 obj = obj + <param name=’background’ value=’#3E344A’ /> \n ;
9 obj = obj + <param name=’minRuntimeVersion’ value=’4.0.50401.0′ /> \n ;
10 obj = obj + <param name=’autoUpgrade’ value=’true’ /> \n ;
11 obj = obj + <param name=’InitParams’ value=’mediaurl=<%=Model.Video.Url %>’ /> \n ;
12 obj = obj + <a href=’http://go.microsoft.com/fwlink/?LinkID=149156&v=4.0.50401.0′ style=’text-decoration:none’> <img src=’http://go.microsoft.com/fwlink/?LinkId=161376′ alt=’Get Microsoft Silverlight’ style=’border-style:none’/></a>;
13 obj = obj + </a>;
14
15 // set it as host control html ,and fade in slowly ^_^
16 $(#silverlightControlHost).html(obj).slideDown(slow);
17 });
18 </script>

这里注意‘mediaurl的是通过我们来绑定Model.Video.Url来得到的。比如传过去的Video信息如下:

image

传过来值后,我们把这些拼好的字符串作为div的html来显示,就可以播放视频了。

在下面的文章中我会给大家介绍电影的List展示盒分类的展示,以及其它Rating的ajax实现和评论的ajax方法实现。

最后一篇文章中是结合TinyMac编辑器来进行后台的维护以及权限的管理等等。。。。。。。

Cheers

BRs

Nic