[Lucene]多线程操作建议和[Lucene.Net] 分页显示

mikel阅读(727)

对于并发,Lucene.Net 遵循以下规则:
1. 允许任意多的读操作并发,即任意数量用户可同时对同一索引做检索操作。
2. 即便正在进行索引修改操作(索引优化、添加文档、删除文档),依然允许任意多的检索操作并发执行。
3. 不允许并发修改操作,也就是说同一时间只允许一个索引修改操作。
Lucene.Net 内部已经对多线程安全进行了处理,打开 IndexWrite.cs / IndexReade.csr 文件,会发现很多操作都使用了 lock 进行多线程同步锁定。只要遵循一定的规则,就可以在多线程环境下安全运行 Lucene.Net。
建议:
1. Directotry、Analyzer 都是多线程安全类型,只需建立一个 Singleton 对象即可。
2. 所有线程使用同一个 IndexModifier 对象进行索引修改操作。
3. IndexWriter/IndexReader/IndexModifier/IndexSearcher 最好使用同一个 Directory 对象,否则多线程并发读写时可能引发 FileNotFoundException。
IndexModifier 对象封装了 IndexWriter 和 IndexReader 的常用操作,其内部实现了多线程同步锁定。使用 IndexModifier 可避免同时使用 IndexWriter 和 IndexReader 时需要在多个对象之间进行同步的麻烦。等所有修改操作完成后,记住调用 Close() 方法关闭相关资源。并不是每次操作都需要调用 Optimize(),可以依据特定情况,定期执行优化操作。

[文字]苹果CEO乔布斯的九大法则

mikel阅读(726)

  法则一:网罗一流人才

  乔布斯说,他花了半辈子时间才充分意识到人才的价值。他在最近一次讲话中说:“我过去常常认为一位出色的人才能顶两名平庸的员工,现在我认为能 顶50名。”由于苹果公司需要有创意的人才,所以乔布斯说,他大约把四分之一的时间用于招募人才。高级管理人员往往能更有效地向人才介绍本公司的远景目 标。而对于新成立的富有活力的公司来说,其创建者通常在挑选职员时十分仔细,老板亲临招聘现场,则可使求职者以最快速度了解与适应公司的文化氛围和环境。

  法则二:一切要尽在掌控

  在乔布斯的哲学里,苹果始终是,也必须是一家能“全盘掌控”的公司。从硬件到软件,从设计到功能,从操作系统到应用软件,苹果的产品全部由自己 打造,我们随时可以改变,创新每天都在发生,我们关注产品中的每一项技术,只有这样,每一项创新才能顺利的变为产品。苹果的创新就在于我们能够掌握每一个 零件。

  法则三:没有B计划

  对于乔布斯来说:只有A计划,在进入一个新的领域时,只倾注全力打造一款产品或服务,没有备选方案,没有退路。这样才能将最好的创意、技术、设计倾注到一款产品上。如iPod、iPhone(手机上网)莫不如此。

  法则四:追求残忍的完美

  曾经有过这样的报道:新产品的一切工作都已完成,只待发布。乔布斯仅仅因为一个不起眼的细节(如:还有两颗螺丝暴露在表面)而要求一切推倒重来。正是这个残忍的标准成就了苹果一个个令人惊叹的产品。

  法则五:软件永远是核心技术

  乔布斯意识到,“对未来的消费类电子产品而言,软件都将是核心技术”。坚持做操作系统和那些悄无声息的后端软件,比如iTunes。

  这样的苹果才不至于像DELL、惠普或索尼那样,因为等待微软最新操作系统的发布而延迟推出硬件产品。这样的苹果不用看着微软干着急。而随意修改系统,还可以为iPhone和iPod制作特别的版本。这也是消费电子巨头索尼在随身听市场不敌苹果的原因。

  法则六:谨慎与第三方合作

  在乔布斯眼里,与其与平庸的公司合作不如不合作,那只会降低苹果的产品的品质。另外受他人制约是不可容忍的。

  法则七:秘而不宣

  乔布斯把苹果公司的新产品研发计划看成是这个星球的最高机密,保密程度足与FBI媲美。乔布斯在2005年6月的苹果全球开发者大会上宣布全面 转向英特尔CPU时,才透露早在5年前,苹果已将操作系统MACOSX的代码按X86的架构重写,之前没有任何风声。还有一例:作为iPhone的首个销 售商,AT&T旗下Cingular的高层也是在正是发布的两周前才看到iPhone的真实原型机,苹果甚至专门制作了几款假的iPhone原型 机以掩人耳目。

  法则八:产品必须带来可观利润

  乔布斯认为:又酷又新的产品不能带来可观利润,那不是创新,只是艺术。很显然,乔布斯在1997年重返苹果,第一件事就是砍掉经营了七年还在不 断亏损的牛顿(Newton)PDA业务。尽管这个产品极为创新、另人惊叹。而乔布斯在重返苹果后打造的iMac、iPod、iPhone都是又酷又赚钱 的产品。

  法则九:科技产品必须是令人惊叹且引导消费的

  在乔布斯眼里:满足客户需求是平庸公司所为,引导客户需求是高手之道。领先数步没有成为先烈,还为人疯狂喜爱并大掏腰包。乔布斯带领下的苹果做 到了,糖果设计师设计的iMac出现后,人们才认识到电脑外壳原来可以是彩色的、透明的。iPod的可人设计+在线购买的iTunes音乐商店打造了全程 的音乐体验。iPhone的发布让大家发现手机是可以没有键盘和触摸笔的,最好的操作工具是与生俱来、不会遗失、操作自如的手指。

  还有报道说,乔布斯在推新产品时从来不会请调研公司进行市场调研。乔布斯认为那只会看到表面现象,让新产品的研发误入歧途。

  当然,所有的法则都是为两个字服务——“创新”。

[MVC]ASP.NET MVC 1.0 RC的发布,

mikel阅读(677)

Scott Gu宣布了ASP.NET MVC 1.0 RC的发布, Scott Gu在blog上写了一篇ASP.NET MVC 1.0 Release Candidate Now Available,

RC版本有很多小的改进:

  • Visual Studio同 MVC的集成更成熟了,也就说有了更好用的脚手架- "Go to Controller" / "Go to View" / "Add View" 等等
  • AJAX 的改进
  • FileUpload / "Download" 改进,例如 FileResult映射到 Fileupload
  • Visual Studio T4 模板,这就意味着自己可以去定制MVC模板,顺便在这里介绍一个T4:Visual Studio 2008包含了一个文本模板转换工具箱,又称为T4,是领域特定语言工具的一部分,并可用于基于文本模板的方式来生成代码。中文的介绍可见InfoQ的《Visual Studio 2008的文本模板转换工具箱

如果你已经安装beta,必须先卸载Beta版,如果你还用到MVC Feature部分请到codeplex上下载一个新版本,具体参看Phil的 blog

发行说明中有详细的从beta升级到rc的详细清单,是升级的必读文件。

如果我想保留ASP.NET MVC 1.0 beta,想直接使用ASP.NET mvc 1.0 rc的二进制版本,可以通过命令行提取MSI文件中的内容,命令如下:

msiexec /a AspNetMVCRC-setup.msi

等待几秒钟后就可以在C:\Program Files\Microsoft ASP.NET\ASP.NET MVC RC 目录下获取到二进制版本,而不会影响到你的Visual Studio模板 和GAC。

[历史]《时代》杂志:苹果发展史上10大辉煌时刻

mikel阅读(885)

美国知名杂志《时代》近日评出了“苹果发展史上10大辉煌时刻”,其中包括创业之初、苹果I现身、Mac机诞生、iPod音乐播放器风潮、iPhone智能手机受追捧等等。以下为《时代》杂志所评出“苹果发展史上10大辉煌时刻”简介:

 

1、创业之初

在正式创建苹果之前,史蒂夫·乔布斯(Steve Jobs)刚刚21岁。当时乔布斯经常同他的两位好友史蒂夫·沃兹尼亚克(Steve Wozniak)、罗纳德·韦恩(Ronald Wayne)一起玩耍。或许这三人本来可组建一家摇滚乐队,只是这三位好友另有想法。

《时代》杂志:苹果发展史上10大辉煌时刻

当时乔布斯和韦恩同在一名为Atari的公司工作,而沃兹尼亚克在惠普工作。1976年4月 1,这三位好友创建了苹果电脑公司。虽然苹果的最初创始人为三位,但仅仅三个月之后,韦恩就以800美元的低廉价格将自己所持苹果股份出售。由此一来,人 们谈起苹果创始人时,多数情况下只提及乔布斯和沃兹尼亚克两人。

2、苹果I现身

如今回头一看,苹果生产的第一款电脑Apple I看上去就是老古董。Apple I由沃兹尼亚克亲自手工打造,并于1976年在加州一次展会上展出。Apple I硬件放在木盒子里边,外观上看上去是一台打字机。该产品并没有配备显示器,需外接电视机来作为显示设备。其售价为666.66美元(据说是沃兹尼亚克喜 欢重复输入某个数字)。

《时代》杂志:苹果发展史上10大辉煌时刻

Apple I共生产了200台,消费者需自己购买相应键盘、显示器等配套设备。目前Apple I价格已涨至数万美元,并成为古董收藏家最为青睐的对象之一。

3、1984年:Mac机的黎明

《时代》杂志:苹果发展史上10大辉煌时刻

Mac机是“Macintosh”品牌的简称。1984年1月24日,乔布斯首先在苹果股东 年度大会上展示这款机型。首款Mac机售价为2495美元。它是首款公众有能力购买、并采用了图形用户界面的个人电脑。为打开Macintosh机销路, 苹果还聘请了著名导演雷德利·斯科特(Ridley Scott,为著名科幻恐怖片《异形》导演)专门制作了广告。

4、PowerPC处理器

《时代》杂志:苹果发展史上10大辉煌时刻

1981年,美国科技巨头IBM正式进入个人电脑市场。随后数年中,苹果同IBM之间展开了 激烈市场竞争。6年之后,苹果同IBM(还有摩托罗拉参与)共同开发了PowerPC处理器。当时苹果同IBM结盟,主要是为了对付微软-英特尔联盟。在 2006年之前,所有苹果电脑都采用PowerPC处理器。2006年之后,苹果也投向英特尔阵营。

5、乔布斯归来

《时代》杂志:苹果发展史上10大辉煌时刻

1985年,乔布斯被苹果董事会“扫地出门”,他随后创办一家名为NeXT的软件开发公司。 上个世纪90年代,由于微软Windows操作系统不断蚕食苹果市场份额,1997年8月,苹果宣布收购NeXT。乔布斯由此而回到了苹果,并重新执掌该 公司。自那时以来,乔布斯已成了苹果的代名词。乔布斯今年1月14日宣布,自己将病休5个月。此消息一出,立即导致苹果股价当天下跌4%。

6、iMac发布

《时代》杂志:苹果发展史上10大辉煌时刻

1998年,苹果推出了首款iMac个人电脑,外观颜色为蓝色。后来该公司陆续推出了多种颜 色的iMac。这种颜色鲜艳的外观设计深受消费者欢迎。在iMac上市第一年期间,就成为美国市场销量最高的个人电脑。此外,iMac还开启了苹果在产品 名称前面中增加英文小写字母“i”的历史。

7、iPod风潮

《时代》杂志:苹果发展史上10大辉煌时刻

2001年10月,苹果推出了其iPod音乐播放器。自那时以来,该公司已推出了10款不同 型号的iPod,其中一些支持视频播放,另一些则体积更小,如iPod Nano就是如此。截止去年4月底,全球iPod总销量已突破1亿部。在2007年美国所有出售的汽车中,70%配备了iPod连接功能。

8、Mac OS X操作系统

《时代》杂志:苹果发展史上10大辉煌时刻

乔布斯创建NeXT后,曾积累了一些操作系统开发的经验。乔布斯重回苹果怀抱后,就在 NeXT技术基础上开发了Mac OS X(注:X是罗马字母“10”之意,而非英文字母X)操作系统。该产品于2001年3月发布。OS X的系统稳定性、高处理速度及华丽界面都因素,都成为苹果进行市场宣传的重点所在。

9、iTunes音乐商店

《时代》杂志:苹果发展史上10大辉煌时刻

在苹果于2001年推出其iPod音乐播放器的同时,还开通了与之相配套的网络音乐服务iTunes网上商店。到2003年时,iTunes音乐商店可供下载的歌曲数量已达500万首,电视剧和电影数量分别为350部和400部。目前iTunes已成为全球最为热门的网络音乐商店之一。

10、iPhone智能手机

《时代》杂志:苹果发展史上10大辉煌时刻

2007年夏季,美国乃至全球最关注的并不是好莱坞大片,而是苹果推出的iPhone智能手 机。该产品提供音乐播放、电子邮件收发、互联网接入等功能。去年7月,苹果又推出了3G版iPhone。在2G版和3G版iPhone首发期间,全球各国 都出现了消费者提前数天排队购买现象。

[C#]C#正则表达式整理备忘

mikel阅读(1055)

有一段时间,正则表达式学习很火热很潮流,当时在CSDN一天就能看到好几个正则表达式的帖子,那段时 间借助论坛以及Wrox Press出版的《C#字符串和正则表达式参考手册》学习了一些基础的知识,同时也为我在CSDN大概赚了1000分,今天想起来,去找《C#字符串和正 则表达式参考手册》时,已经不知所踪了。现在用到正则的时候也比较少,把以前的笔记等整理一下,以志不忘。
(1)“@”符号
符下两ows表研究室的火热,当晨在“@”虽然并非C#正则表达式的“成员”,但是它经常与C#正则表达式出双入对。“@”表示,跟在它后面的字符串是个“逐字字符串”,不是很好理解,举个例子,以下两个声明是等效的:
string x="D:\\My Huang\\My Doc";
string y = @"D:\My Huang\My Doc";
事实上,如果按如下声明,C#将会报错,因为“\”在C#中用于实现转义,如“\n”换行:
string x = "D:\My Huang\My Doc";

(2)基本的语法字符。
\d  0-9的数字
\D  \d的补集(以所以字符为全集,下同),即所有非数字的字符
\w  单词字符,指大小写字母、0-9的数字、下划线
\W  \w的补集
\s  空白字符,包括换行符\n、回车符\r、制表符\t、垂直制表符\v、换页符\f
\S  \s的补集
.  除换行符\n外的任意字符
[…]  匹配[]内所列出的所有字符
[^…]  匹配非[]内所列出的字符
下面提供一些简单的示例:


string i = "\n";
string m = "3";
Regex r 
= new Regex(@"\D");
//同Regex r = new Regex("\\D");
//r.IsMatch(i)结果:true
//r.IsMatch(m)结果:false

string i = "%";
string m = "3";
Regex r 
= new Regex("[a-z0-9]");
//匹配小写字母或数字字符
//r.IsMatch(i)结果:false
//r.IsMatch(m)结果:true

(3)定位字符
“定位字符”所代表的是一个虚的字符,它代表一个位置,你也可以直观地认为“定位字符”所代表的是某个字符与字符间的那个微小间隙。
^  表示其后的字符必须位于字符串的开始处
$  表示其前面的字符必须位于字符串的结束处
\b  匹配一个单词的边界
\B  匹配一个非单词的边界
另外,还包括:\A  前面的字符必须位于字符处的开始处,\z  前面的字符必须位于字符串的结束处,\Z  前面的字符必须位于字符串的结束处,或者位于换行符前
下面提供一些简单的示例:


string i = "Live for nothing,die for something";
Regex r1 
= new Regex("^Live for nothing,die for something$");
//r1.IsMatch(i) true
Regex r2 = new Regex("^Live for nothing,die for some$");
//r2.IsMatch(i) false
Regex r3 = new Regex("^Live for nothing,die for some");
//r3.IsMatch(i) true

string i = @"Live for nothing,
die for something
";//多行
Regex r1 = new Regex("^Live for nothing,die for something$");
Console.WriteLine(
"r1 match count:" + r1.Matches(i).Count);//0
Regex r2 = new Regex("^Live for nothing,die for something$", RegexOptions.Multiline);
Console.WriteLine(
"r2 match count:" + r2.Matches(i).Count);//0
Regex r3 = new Regex("^Live for nothing,\r\ndie for something$");
Console.WriteLine(
"r3 match count:" + r3.Matches(i).Count);//1
Regex r4 = new Regex("^Live for nothing,$");
Console.WriteLine(
"r4 match count:" + r4.Matches(i).Count);//0
Regex r5 = new Regex("^Live for nothing,$", RegexOptions.Multiline);
Console.WriteLine(
"r5 match count:" + r5.Matches(i).Count);//0
Regex r6 = new Regex("^Live for nothing,\r\n$");
Console.WriteLine(
"r6 match count:" + r6.Matches(i).Count);//0
Regex r7 = new Regex("^Live for nothing,\r\n$", RegexOptions.Multiline);
Console.WriteLine(
"r7 match count:" + r7.Matches(i).Count);//0
Regex r8 = new Regex("^Live for nothing,\r$");
Console.WriteLine(
"r8 match count:" + r8.Matches(i).Count);//0
Regex r9 = new Regex("^Live for nothing,\r$", RegexOptions.Multiline);
Console.WriteLine(
"r9 match count:" + r9.Matches(i).Count);//1
Regex r10 = new Regex("^die for something$");
Console.WriteLine(
"r10 match count:" + r10.Matches(i).Count);//0
Regex r11 = new Regex("^die for something$", RegexOptions.Multiline);
Console.WriteLine(
"r11 match count:" + r11.Matches(i).Count);//1
Regex r12 = new Regex("^");
Console.WriteLine(
"r12 match count:" + r12.Matches(i).Count);//1
Regex r13 = new Regex("$");
Console.WriteLine(
"r13 match count:" + r13.Matches(i).Count);//1
Regex r14 = new Regex("^", RegexOptions.Multiline);
Console.WriteLine(
"r14 match count:" + r14.Matches(i).Count);//2
Regex r15 = new Regex("$", RegexOptions.Multiline);
Console.WriteLine(
"r15 match count:" + r15.Matches(i).Count);//2
Regex r16 = new Regex("^Live for nothing,\r$\n^die for something$", RegexOptions.Multiline);
Console.WriteLine(
"r16 match count:" + r16.Matches(i).Count);//1
//对于一个多行字符串,在设置了Multiline选项之后,^和$将出现多次匹配。

string i = "Live for nothing,die for something";
string m = "Live for nothing,die for some thing";
Regex r1 
= new Regex(@"\bthing\b");
Console.WriteLine(
"r1 match count:" + r1.Matches(i).Count);//0
Regex r2 = new Regex(@"thing\b");
Console.WriteLine(
"r2 match count:" + r2.Matches(i).Count);//2
Regex r3 = new Regex(@"\bthing\b");
Console.WriteLine(
"r3 match count:" + r3.Matches(m).Count);//1
Regex r4 = new Regex(@"\bfor something\b");
Console.WriteLine(
"r4 match count:" + r4.Matches(i).Count);//1
//\b通常用于约束一个完整的单词

 (4)重复描述字符
“重复描述字符”是体现C#正则表达式“很好很强大”的地方之一:
{n}  匹配前面的字符n次
{n,}  匹配前面的字符n次或多于n次
{n,m}  匹配前面的字符n到m次
?  匹配前面的字符0或1次
+  匹配前面的字符1次或多于1次
*  匹配前面的字符0次或式于0次
以下提供一些简单的示例:


string x = "1024";
string y = "+1024";
string z = "1,024";
string a = "1";
string b="-1024";
string c = "10000";
Regex r 
= new Regex(@"^\+?[1-9],?\d{3}$");
Console.WriteLine(
"x match count:" + r.Matches(x).Count);//1
Console.WriteLine("y match count:" + r.Matches(y).Count);//1
Console.WriteLine("z match count:" + r.Matches(z).Count);//1
Console.WriteLine("a match count:" + r.Matches(a).Count);//0
Console.WriteLine("b match count:" + r.Matches(b).Count);//0
Console.WriteLine("c match count:" + r.Matches(c).Count);//0
//匹配1000到9999的整数。

 (5)择一匹配
C#正则表达式中的 (|) 符号似乎没有一个专门的称谓,姑且称之为“择一匹配”吧。事实上,像[a-z]也是一种择一匹配,只不过它只能匹配单个字符,而(|)则提供了更大的范 围,(ab|xy)表示匹配ab或匹配xy。注意“|”与“()”在此是一个整体。下面提供一些简单的示例:


string x = "0";
string y = "0.23";
string z = "100";
string a = "100.01";
string b = "9.9";
string c = "99.9";
string d = "99.";
string e = "00.1";
Regex r 
= new Regex(@"^\+?((100(.0+)*)|([1-9]?[0-9])(\.\d+)*)$");
Console.WriteLine(
"x match count:" + r.Matches(x).Count);//1
Console.WriteLine("y match count:" + r.Matches(y).Count);//1
Console.WriteLine("z match count:" + r.Matches(z).Count);//1
Console.WriteLine("a match count:" + r.Matches(a).Count);//0
Console.WriteLine("b match count:" + r.Matches(b).Count);//1
Console.WriteLine("c match count:" + r.Matches(c).Count);//1
Console.WriteLine("d match count:" + r.Matches(d).Count);//0
Console.WriteLine("e match count:" + r.Matches(e).Count);//0
//匹配0到100的数。最外层的括号内包含两部分“(100(.0+)*)”,“([1-9]?[0-9])(\.\d+)*”,这两部分是“OR”的关系,即正则表达式引擎会先尝试匹配100,如果失败,则尝试匹配后一个表达式(表示[0,100)范围中的数字)。

(6)特殊字符的匹配
下面提供一些简单的示例:


string x = "\\";
Regex r1 
= new Regex("^\\\\$");
Console.WriteLine(
"r1 match count:" + r1.Matches(x).Count);//1
Regex r2 = new Regex(@"^\\$");
Console.WriteLine(
"r2 match count:" + r2.Matches(x).Count);//1
Regex r3 = new Regex("^\\$");
Console.WriteLine(
"r3 match count:" + r3.Matches(x).Count);//0
//匹配“\”

string x = "\"";
Regex r1 = new Regex("^\"$");
Console.WriteLine("r1 match count:" + r1.Matches(x).Count);//1
Regex r2 = new Regex(@"^""$");
Console.WriteLine(
"r2 match count:" + r2.Matches(x).Count);//1
//匹配双引号

 (7)组与非捕获组
以下提供一些简单的示例:


string x = "Live for nothing,die for something";
string y = "Live for nothing,die for somebody";
Regex r 
= new Regex(@"^Live ([a-z]{3}) no([a-z]{5}),die \1 some\2$");
Console.WriteLine(
"x match count:" + r.Matches(x).Count);//1
Console.WriteLine("y match count:" + r.Matches(y).Count);//0
//正则表达式引擎会记忆“()”中匹配到的内容,作为一个“组”,并且可以通过索引的方式进行引用。表达式中的“\1”,用于反向引用表达式中出现的第一个组,即粗体标识的第一个括号内容,“\2”则依此类推。

string x = "Live for nothing,die for something";
Regex r 
= new Regex(@"^Live for no([a-z]{5}),die for some\1$");
if (r.IsMatch(x))
{
    Console.WriteLine(
"group1 value:" + r.Match(x).Groups[1].Value);//输出:thing
}

//获取组中的内容。注意,此处是Groups[1],因为Groups[0]是整个匹配的字符串,即整个变量x的内容。

string x = "Live for nothing,die for something";
Regex r 
= new Regex(@"^Live for no(?<g1>[a-z]{5}),die for some\1$");
if (r.IsMatch(x))
{
    Console.WriteLine(
"group1 value:" + r.Match(x).Groups["g1"].Value);//输出:thing
}

//可根据组名进行索引。使用以下格式为标识一个组的名称(?<groupname>…)。

string x = "Live for nothing nothing";
Regex r 
= new Regex(@"([a-z]+) \1");
if (r.IsMatch(x))
{
    x 
= r.Replace(x, "$1");
    Console.WriteLine(
"var x:" + x);//输出:Live for nothing
}

//删除原字符串中重复出现的“nothing”。在表达式之外,使用“$1”来引用第一个组,下面则是通过组名来引用:
string x = "Live for nothing nothing";
Regex r 
= new Regex(@"(?<g1>[a-z]+) \1");
if (r.IsMatch(x))
{
    x 
= r.Replace(x, "${g1}");
    Console.WriteLine(
"var x:" + x);//输出:Live for nothing
}


string x = "Live for nothing";
Regex r 
= new Regex(@"^Live for no(?:[a-z]{5})$");
if (r.IsMatch(x))
{
    Console.WriteLine(
"group1 value:" + r.Match(x).Groups[1].Value);//输出:(空)
}

//在组前加上“?:”表示这是个“非捕获组”,即引擎将不保存该组的内容。

 (8)贪婪与非贪婪
正则表达式的引擎是贪婪,只要模式允许,它将匹配尽可能多的字符。通过在“重复描述字符”(*,+)后面添加“?”,可以将匹配模式改成非贪婪。请看以下示例:


string x = "Live for nothing,die for something";
Regex r1 
= new Regex(@".*thing");
if (r1.IsMatch(x))
{
    Console.WriteLine(
"match:" + r1.Match(x).Value);//输出:Live for nothing,die for something
}

Regex r2 
= new Regex(@".*?thing");
if (r2.IsMatch(x))
{
    Console.WriteLine(
"match:" + r2.Match(x).Value);//输出:Live for nothing
}

(9)回溯与非回溯
使用“(?>…)”方式进行非回溯声明。由于正则表达式引擎的贪婪特性,导致它在某些情况下,将进行回溯以获得匹配,请看下面的示例:


string x = "Live for nothing,die for something";
Regex r1 
= new Regex(@".*thing,");
if (r1.IsMatch(x))
{
    Console.WriteLine(
"match:" + r1.Match(x).Value);//输出:Live for nothing,
}

Regex r2 
= new Regex(@"(?>.*)thing,");
if (r2.IsMatch(x))//不匹配
{
    Console.WriteLine(
"match:" + r2.Match(x).Value);
}

//在r1中,“.*”由于其贪婪特性,将一直匹配到字符串的最后,随后匹配“thing”,但在匹配“,”时失败,此时引擎将回溯,并在“thing,”处匹配成功。
在r2中,由于强制非回溯,所以整个表达式匹配失败。

(10)正向预搜索、反向预搜索
正向预搜索声明格式:正声明 “(?=…)”,负声明 “(?!…)” ,声明本身不作为最终匹配结果的一部分,请看下面的示例:


string x = "1024 used 2048 free";
Regex r1 
= new Regex(@"\d{4}(?= used)");
if (r1.Matches(x).Count==1)
{
    Console.WriteLine(
"r1 match:" + r1.Match(x).Value);//输出:1024
}

Regex r2 
= new Regex(@"\d{4}(?! used)");
if (r2.Matches(x).Count==1)
{
    Console.WriteLine(
"r2 match:" + r2.Match(x).Value); //输出:2048
}

//r1中的正声明表示必须保证在四位数字的后面必须紧跟着“ used”,r2中的负声明表示四位数字之后不能跟有“ used”。

反向预搜索声明格式:正声明“(?<=)”,负声明“(?<!)”,声明本身不作为最终匹配结果的一部分,请看下面的示例:


string x = "used:1024 free:2048";
Regex r1 
= new Regex(@"(?<=used:)\d{4}");
if (r1.Matches(x).Count==1)
{
    Console.WriteLine(
"r1 match:" + r1.Match(x).Value);//输出:1024
}

Regex r2 
= new Regex(@"(?<!used:)\d{4}");
if (r2.Matches(x).Count==1)
{
    Console.WriteLine(
"r2 match:" + r2.Match(x).Value);//输出:2048
}

//r1中的反向正声明表示在4位数字之前必须紧跟着“used:”,r2中的反向负声明表示在4位数字之前必须紧跟着除“used:”之外的字符串。

(11)十六进制字符范围
正则表达式中,可以使用 "\xXX" 和 "\uXXXX" 表示一个字符("X" 表示一个十六进制数)形式字符范围:
\xXX       编号在 0到255 范围的字符,比如:空格可以使用 "\x20" 表示。
\uXXXX   任何字符可以使用 "\u" 再加上其编号的4位十六进制数表示,比如:汉字可以使用“[\u4e00-\u9fa5]”表示。


(12)对[0,100]的比较完备的匹配
下面是一个比较综合的示例,对于匹配[0,100],需要特殊考虑的地方包括
*00合法,00.合法,00.00合法,001.100合法
*空字符串不合法,仅小数点不合法,大于100不合法
*数值是可带后缀的,如“1.07f”表示该值为一个float类型(未考虑)

Code

(13)精确匹配有时候是困难的
有些需求要做到精确匹配比较困难,例如:日期、Url、Email地址等,其中一些你甚至需要研究一些专门的文档写出精确完备的表达式,对于这种情况,只 能退而求其次,保证比较精确的匹配。例如对于日期,可以基于应用系统的实际情况考虑一段较短的时间,或者对于像Email的匹配,可以只考虑最常见的形 式。

[C#]CodeSmith生成SQL Server视图的实体类脚本

mikel阅读(1059)

第一个文件是businessobjctforView.cst,生成C#实体类,此脚本需要引用第二个文件CommonUtility.cs。需将两个文件放在同一目录中。

<%@ CodeTemplate Language="C#" TargetLanguage="T-SQL"
      Description
="Generates a update stored procedure." %>
<%@ Assembly Name="SchemaExplorer" %> 
<%@ Import Namespace="SchemaExplorer" %> 
<%@ Property Name="SourceTable" Type="SchemaExplorer.ViewSchema"
      Category
="Context"
      Description
="Table that the stored procedures should be based on." %>
<%@ Assembly Src="CommonUtility.cs" %>
<%@ Import Namespace="Common.Data" %>
<script runat="template">
    CommonUtility rule
=new CommonUtility();
</script>
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;                                                                                                                                                         
namespace SOA.Model
{
    
/// <summary>
    
/// <%= SourceTable.Name %> object for View table '<%= SourceTable.Name %>'.
    
/// </summary>
    [Serializable]
    
public class <%= SourceTable.Name %>
    {
    
#region Private Member
        
<% for (int i = 0; i < SourceTable.Columns.Count; i++) { %>
        
private <%= rule.GetCSharpVariableType(SourceTable.Columns[i]) %> _<%= SourceTable.Columns[i].Name %>;
    
<% } %>
    
#endregion
        
    
#region Constructor
        
public <%= SourceTable.Name %>() {}        
        
        
public <%= SourceTable.Name %>(
                
<% for (int i = 0; i < SourceTable.Columns.Count1; i++) { %>
        
<%= rule.GetCSharpVariableType(SourceTable.Columns[i]) %> <%= SourceTable.Columns[i].Name %>,    
    
<% } %>
    
<%= rule.GetCSharpVariableType(SourceTable.Columns[SourceTable.Columns.Count1]) %> <%= SourceTable.Columns[SourceTable.Columns.Count1].Name %>
        ) 
        {
        
<% for (int i = 0; i < SourceTable.Columns.Count; i++) { %>
         _
<%= SourceTable.Columns[i].Name %> = <%= SourceTable.Columns[i].Name %>;
    
<% } %>
        }
    
#endregion
    
    
#region Public Properties
    
<% for (int i = 0; i < SourceTable.Columns.Count; i++) { %>
        
public <%= rule.GetCSharpVariableType(SourceTable.Columns[i]) %> <%= rule.GetCamelCaseName(SourceTable.Columns[i].Name) %>
        {
            
get { return _<%= SourceTable.Columns[i].Name %>; }
            
set { _<%= SourceTable.Columns[i].Name %> = value; }
        }
    
<% } %>
    
#endregion
    }
}
 
第二个文件是CommonUtility.cs,此文件是包含C#的数据类型定义以及输出:

using System;
using System.Text;
using CodeSmith.Engine;
using SchemaExplorer;
using System.ComponentModel;
using System.Data;
namespace Common.Data
{
    
/**//// <summary>
    
/// TemplateRule
    
/// </summary>
    public class CommonUtility
    {
        
//get Columns info by TableName
        public ViewColumnSchemaCollection GetColumnCollectionByTable(ViewSchema table)
        {
            ViewColumnSchemaCollection columns 
= new ViewColumnSchemaCollection(table.Columns);
            
return columns;
        }
        
//Get camelcase name,such as Customer,
        public string GetCamelCaseName(string str)
        {
            
return str.Substring(0,1).ToUpper()+str.Substring(1);
        }
        
       
//Get ,user,private const String USER_FIELD = "User"
        public string GetMemberConstantDeclarationStatement(ColumnSchema column)
        {
            
return GetMemberConstantDeclarationStatement("public const String ",column);
        }
        
        
//such as public const String USER_TABLE = "User"
        public string GetTableConstantDeclarationStatement(ViewSchema table)
        {
            
return GetMemberConstantDeclarationStatement("public const String ",table);    
        }
        
//suck as USER_TABLE
        public string GetUpperStatement(ViewSchema table)
        {
            
return     table.Name.ToUpper()+"_TABLE";
       }
        
//suck as USER_FIELD
        public string GetUpperStatement(ColumnSchema column)
       {
           
return column.Name.ToUpper()+"_FIELD";
        }
        
// such as USER_TABLE = "User"
        public string GetMemberConstantDeclarationStatement(string protectionLevel, ViewSchema table)
        {
            
return protectionLevel+GetUpperStatement(table)+" = "+GetCamelCaseName(table.Name)+"";
        }
       
        
//such as USERID_FIELD = "Userid"
        public string GetMemberConstantDeclarationStatement(string protectionLevel,ColumnSchema column)
        {
            
return protectionLevel+GetUpperStatement(column)+" = "+GetCamelCaseName(column.Name)+"";
        }
        
public string GetCSharpVariableType(ViewColumnSchema column)
        {
            
switch(column.DataType)
            {
                
case DbType.AnsiString: return "string";
                
case DbType.AnsiStringFixedLength: return "string";
                
case DbType.Binary: return "byte[]";
                
case DbType.Boolean: return "bool";
                
case DbType.Byte: return "int";
                
case DbType.Currency: return "decimal";
                
case DbType.Date: return "DataTime";
                
case DbType.DateTime: return "DateTime";
                
case DbType.Decimal: return "decimal";
                
case DbType.Double: return "double";
                
case DbType.Guid: return "Guid";
                
case DbType.Int16: return "short";
                
case DbType.Int32: return "int";
                
case DbType.Int64: return "long";
                
case DbType.Object: return "object";
                
case DbType.SByte: return "sbyte";
                
case DbType.Single: return "float";
                
case DbType.String: return "string";
                
case DbType.StringFixedLength: return "string";
                
case DbType.Time: return "TimeSpan";
                
case DbType.UInt16: return "ushort";
                
case DbType.UInt32: return "uint";
                
case DbType.UInt64: return "ulong";
                
case DbType.VarNumeric: return "decimal";
            }
            
            
return null;
        }
        
        
public string GetCSharpBaseType(ViewColumnSchema column)
       {
            
switch(column.DataType)
           {
                
case DbType.AnsiString: return "System.String";
                
case DbType.AnsiStringFixedLength: return "System.String";
                
case DbType.Binary: return "System.Byte[]";
                
case DbType.Boolean: return "System.Boolean";
                
case DbType.Byte: return "System.Int32";
                
case DbType.Currency: return "System.Decimal";
                
case DbType.Date: return "System.DataTime";
                
case DbType.DateTime: return "System.DataTime";
                
case DbType.Decimal: return "System.Decimal";
                
case DbType.Double: return "System.Double";
                
case DbType.Guid: return "System.Guid";
                
case DbType.Int16: return "System.Int16";
                
case DbType.Int32: return "System.Int32";
                
case DbType.Int64: return "System.Int64";
                
case DbType.Object: return "System.Object";
                
case DbType.SByte: return "System.SByte";
                
case DbType.Single: return "System.Single";
                
case DbType.String: return "System.String";
                
case DbType.StringFixedLength: return "System.String";
                
case DbType.Time: return "System.TimeSpan";
                
case DbType.UInt16: return "System.UInt16";
                
case DbType.UInt32: return "System.UInt32";
                
case DbType.UInt64: return "System.UInt64";
                
case DbType.VarNumeric: return "System.Decimal";
            }
            
return null;
        }
    }
}
 

[C#]Windows Live Writer 插件开发入门

mikel阅读(898)

几个月前看过Channel9上的一个视频,Windows Live Writer的开发经理Charles Teague现场讲述如何开发Writer插件。昨天又看了徐晓卓同学的WebCast,感觉内容雷同,看完之后觉得食不尽兴,并且在一些细节地方我对该 同学有异议。其实我与徐晓卓同学素未谋面,更谈不上江湖过节,只不过是想综合他和Charles的内容,总结归档,给其他想要涉足Live Writer插件开发的同学一点儿入门级参考资料罢了。我希望晓卓同学看了我的文章不要生气,我不是说你代码写错了,只是有一个比较明显的地方,你既然在 MSDN WebCast上写代码,我觉得还是有必要遵守微软的编码规范,例如局部变量的声明,首字母应该小写,虽然你大写了并不影响编译。总而言之,我不提倡文人 相酸,只奉行共同进步。

言归正传,这篇文章里的代码量不大,但整个Solution我已经放到CodePlex上去了,大家可以直接到http://www.codeplex.com/WriterPlugin查看或下载所有源代码。

微软已经发布了Windows Live Writer SDK,其中主要分为三个部分:

  • Application API
    • 用于启动Live Writer应用程序以及编辑现有数据类型,例如:超链接、文本、图片等;
  • Content Source Plugin API
    • 用于扩展新数据类型的支持能力;
  • Provider Customization API
    • 用于自定义现有功能以及增添新的功能;

本文主要讲述Application API的开发练习,我相信大家只要明白了如何利用Application API做自己想要做的事情,那么其它两个API也就触类旁通了。

简单介绍一下应用场景:可能因为也许需要,某些人需要往Live Writer中插入一些文本内容,并且这些文本内容在插入的时候总是需要经过固定的处理流程,类似于给图片加水印一样,因此简单的复制粘贴就显得不够用 了,需要我们另外给他开发一个独立的应用程序来做处理工作吗?那我写这篇文章做啥!

首先打开Visual Studio 2008,新建一个Class Library类型的项目,创建好了以后要添加Application API的动态链接库文件的引用,不用到MSDN上去下载,安装了Live Writer之后即可在安装目录下找到这个WindowsLive.Writer.Api.dll文件。然后如果你的插件需要打开Windows窗口,那 么还需要添加System.Windows.Forms等引用。

根据我们假想场景的业务需要,我们需要有一个Windows窗口,用于接收用户需要插入的原始文本内容,然后进行处 理,也就是将字符串变成大写并在后面添加Autumoon Lab的标记。需要注意的是,我们往Live Writer中插入文本内容时要切记应该使用HTML标签,而不是C#的一些转义字符,例如要用"<br/>"而不是"\n"等。

代码将如何按照我们的想法来工作呢?我们首先声明一个类AutumoonPlugin,继承ContentSource类,并且重载其中的CreateContent用于实现我们自己的文本插入流程:

   1: [WriterPlugin("7c371eef-e350-4aae-af28-91613a9137e3", "Autumoon", PublisherUrl = "http://www.Autumoon.com", Description = "This is an Autumoon Lab plugin.", Name = "Autumoon")]
   2: [InsertableContentSource("iAutumoon", SidebarText = "iAutumoon")]
   3: public class AutumoonPlugin : ContentSource
   4: {
   5:     public override DialogResult CreateContent(IWin32Window dialogOwner, ref string content)
   6:     {
   7:         new ProcessForm().ShowDialog();
   8:  
   9:         content = ContentProcessor.ProcessedContent;
  10:  
  11:         return DialogResult.OK;
  12:     }
  13: }

需要给这个类添加两个特性:WriterPlugin和InsertableContentSource。并设置其 中属性的值。根据属性名大家就可以明白是什么意思,我就不再赘述了,强调一点,WriterPlugin第一个参数是id值,大家可以自行设置,我只是用 了一个Guid值而已,不要被迷惑了。

根据上面几行代码大家就可以看出来我们的流程:打开窗口接受用户的插入内容;从一个固定的地方去获取处理之后的文本,然后通过DialogResult.OK来告诉Live Writer插入content,这下明白content为啥是ref的了吧。

The process form.

我们的插入窗口其实一点儿也不华丽,但是却很实用。另外,我们还有一个工具类来专门进行内容处理:

   1: public static void Process(string originalContent)
   2: {
   3:     ProcessedContent = (!String.IsNullOrEmpty(originalContent)
   4:         ? String.Format("<p>{0}<br/><hr>-- Insert by <b>Autumoon Lab</b>.</p>", originalContent.ToUpper())
   5:         : String.Empty);
   6: }

这个方法对用户需要插入的文本进行了简单地处理,大家只要掌握了Live Writer插件的开发方式,就可以天马行空,自由发挥了。

然后我们编译代码,再将编译后的dll文件拷贝到Windows Live Writer安装目录下的Plugins文件夹里,然后打开运行Live Writer就可以看到侧边栏里已经有我们创建的插件了。

Autumoon Plugin

我衷心希望接下来不久的时间就可以看到有更多的同学开发出更多更好更强大的Live Writer插件,看到更多更好更精辟的技术文章!

[CSS]2009年海外Web设计风潮(上)

mikel阅读(946)

这是 Smashing Magazine 花费几个月的时间研究编写的 2009 年 Web 设计风格与潮流,Smashing Magazine 的编辑们对当前流行的大量 Web 设计风格进行分析,总结出那些可能在 2009年风行的潮流,包括新的设计元素,新的图形方式,并给出大量的漂亮的示例。这是第一部分10个潮流,第二部分15个潮流将于下周推出。

1. 凸版印刷风格
这种风格有些出人意料,可能因为之前很少有人使用。该风格在在各种主题的网站中都有,但主要用于产品设计或在线服务类网站





2. 富UI
现代 Web 中的 UI 变得越来越漂亮,越来越好用。过去的一年,Web 中的 UI 有了显著提高,有了一种接近桌面的感觉。Ajax 和 Flash 被广泛使用。
特别是我们比去年看到了更多留白区域,还看到很多现代的 UI 技术会显示用户同系统之间交流的视觉状态,比如,按钮在正常和被按下时显示不同的样子,用户同系统交互时能及时得到反馈,另外,越来越多的服务可以被用户定制。

这些设计显示 Web 设计师将更多精力放到了用户体验上。




3. 透明 PNG
使 用 PNG 实现透明虽然不被 IE6支持,却在过去的一年大行其道。设计师们似乎正在尝试将背景图片和内容融合并实现一些印刷媒体的风格。比如,将 PNG半透明图片放到整体背景的某个区域上,用来加亮显示这个区域,如标题或声明。一些 PNG 同名技术还用来实现灯箱框效果。
Smashing Magazine 去年曾有篇使用透明效果实现创意设计的文章,很多设计师在他们的作品中开始尝试这些技巧。有趣的是,透明效果常被用于页首和页尾部分,不过也有些例外





4. 巨大字体
以前文章中我们曾介绍过巨型字体设计,2009年,巨型字体设计还会风行,尤其是那些设计社,以及展示型,产品介绍型,或在线服务型网站,他们会使用巨型字体显示重要信息。
巨型字体设计中使用的字号往往超过36px,设计师们对字体编排注入了更多关注,以实现更漂亮,更连贯,更值得信赖的站点。


5. 代用字体
设计师们还把更多注意力放到字体上,虽然经典的 Web 字体,Helvetica, Arial, Georgia 以及 Verdana 等仍占主流,一些代用字体正浮出水面(如 sIFR)。
有趣的是,这些字体会和设计无缝地衔接,设计师们似乎并非为字体而字体,而是要将字体同他们的设计结合在一起实现更漂亮的效果。




6. 灯箱效果
灯箱框是第二代弹窗,它们比第一代基于 JavaScript 的弹窗更友好,可以让用户将注意力集中到最重要的部分。这些窗口一般由用户的某个行为激发,并显示在其它内容的上层,他们有时候是半透明的,并包含一个关闭按钮。



7. 媒体块
随 着宽带接入的普及,用户现在可以承担更丰富的内容,设计师们也借机提出更有吸引力的内容。越来越多产品网站使用媒体块显示视频,让用户更容易理解这些内 容。用户只需靠在椅子上看视频,不需要一步一步往下点,这些食品通常比较短,直奔主题,虽然很正规,但也包含一些娱乐性。
不过请注意,视频应当是你内容展示方式的次要选项,并不是所有人都有宽带接入,也不是所有人都喜欢有视频播放(他们可能正在后台听网络收音机或播放音乐),另外,也不是所有人都启用了 Flash 和 JavaScript


8. 杂志外观
传统印刷媒体设计中使用的编排技术也出现在 Blog 设计中,文章的编排,文字排版,图片甚至对其方式。基于网格的设计也很流行,但主要用于展示与产品页以及大型博客,极少用于公司网站或网店。


9. 滚动幻灯导航
幻灯片水平和垂直滚动,可以向不同方向滚动,当前项加大加亮。这种导航技术可以让用户快速直观地浏览站点中的内容。一般常用语娱乐性网站,另外,设计者还可以使用该技术展示他们的作品。

10. 在重点位置做形象展示
网站的左上方一般是一个站点最重要的区域,因为那是用户注意力最集中的地方。因此,在那个部位放上网站中最重要的信息是明智之举。
事 实上很多设计师正是这样做的,不管是 Web程序,公司网站,在线服务还是作品展示,设计师们将口号或简介性内容放在那里,并使用醒目的排版给用户以良好的第一印象。这些内容长短不一,不管哪 种方式,但它们都占据可观的空间,一般横跨整个幅面,高度在250到400之间。不过这些形象展示性区域一般并不用于博客或在线商店。



未完待续
本文国际来源:Web Design Trends For 2009
中文翻译来源:COMSHARP CMS 官方网站(35公里译)

[C#]C#中三种截屏方式总结

mikel阅读(973)

昨天写自动化测试的CASE的时候,碰到一个疑难杂症,调用截图的函数去截取一个Popup窗口,但是总是把背景程序给截下来,Popup窗口就跟 看不到一样。本来以为是同步的问题,也就是以为先截图再点击弹出Popup窗口了。后来加了N个Thread.Sleep来测试,发现根本不是因为这个原 因,而是截图的函数截不下来这个窗口。

这个为啥呢,只好把截图的函数代码翻出来看,以前是用这种方式的:
BitBlt(dcImage, 0, 0, (int)(rect.Width), (int)(rect.Height), dcScreen, (int)(rect.Left), (int)(rect.Top), TernaryRasterOperations.SRCCOPY);

凭直觉感觉应该是因为这种通过DC的方式对WPF程序支持有问题,但是又觉得奇怪就是截取其它的WPF组件和窗口都没有问题,偏偏Popup窗口不行。

前些天听说另外一种截屏的方法,这种方法连被遮挡的窗口都可以截,于是就Google一大把,找打了PrintWindow函数,于是就有了第二种解决方案,代码如下:

IntPtr hdc = Native.GetWindowDC(this.Handle);
if (hdc != IntPtr.Zero)
{
    IntPtr hdcMem = Native.CreateCompatibleDC(hdc);
    if (hdcMem != IntPtr.Zero)
    {
        IntPtr hbitmap = Native.CreateCompatibleBitmap(hdc, (int)(Rect.Width), (int)(Rect.Height));
        if (hbitmap != IntPtr.Zero)
        {
            Native.SelectObject(hdcMem, hbitmap);
            Native.PrintWindow(this.Handle, hdcMem, 0);

            Native.DeleteObject(hbitmap);
            Bitmap bmp = Bitmap.FromHbitmap(hbitmap);
            bmp.Save(sPath);
       }
        Native.DeleteObject(hdcMem);
    }
    Native.ReleaseDC(this.Handle, hdc);
}
就是拿到窗口的句柄,通过PrintWindow API来截取窗口。

但是更让人气愤的事情出现了,截出来的窗口中,只要是用到WPF组件的地方,全部是黑块儿,只有MFC的窗口框架和按钮可以正常被截取。

于是乎,就无奈的继续分析这个问题,我记得WPF是没有走GDI,而是通过Directx渲染的,那就是说DC的方式和PrintWindow的方式都不靠谱,但是截Directx的貌似还比较复杂。

突 然想起来,平常报bug的时候都是按PrintScreen,然后再处理一下的,那应该PrintScreen按键是管用的,看来只能曲线救国了。但是那 样就得走剪切板了,貌似会破坏剪切板的数据,不过如果我在截取前保存一下数据,在截取后再恢复一下剪切板数据,那就没有问题了。

于是就有了第三种解决方案(暂时还没有加恢复剪切板数据的代码):

const uint KEYEVENTF_EXTENDEDKEY = 0x1;
const uint KEYEVENTF_KEYUP = 0x2;
const byte VK_SNAPSHOT = 0x2C;
Native.keybd_event(VK_SNAPSHOT, 0x45, KEYEVENTF_EXTENDEDKEY, UIntPtr.Zero);
Native.keybd_event(VK_SNAPSHOT, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, UIntPtr.Zero);

IDataObject iObj = Clipboard.GetDataObject();
if (iObj.GetDataPresent(DataFormats.Bitmap, true))
{
    Bitmap bmpScreen = iObj.GetData(DataFormats.Bitmap, true) as Bitmap;
    Bitmap bmpOutput = new Bitmap((int)this.Rect.Width, (int)this.Rect.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
    Graphics g = Graphics.FromImage(bmpOutput);
    Rectangle destRectangle = new Rectangle(0, 0, (int)this.Rect.Width, (int)this.Rect.Height);
    g.DrawImage(bmpScreen,destRectangle,  (int)this.Rect.X, (int)this.Rect.Y, (int)this.Rect.Width, (int)this.Rect.Height, GraphicsUnit.Pixel);
    bmpOutput.Save(sPath, System.Drawing.Imaging.ImageFormat.Bmp);
}

测试可用,只好先用着了

不过还有几个问题,先写下来,留待以后解决:

1. 针对第三种方案,既然可以按PrintScreen键截图,那对应的API是什么,总觉得发键盘消息没有直接调API稳定

2. 针对WPF截图有没有更好的解决方案