[转载]分享Silverlight/WPF/Windows Phone一周学习导读(12月27日-1月2日)

mikel阅读(1078)

[转载]分享Silverlight/WPF/Windows Phone一周学习导读(12月27日-1月2日) – 专注Silverlight – 博客园.

上周看了“微软 2011 年重大会议概览”,作为微软开发人员,2011年还是有不少值得期待的东西,Silverlight 5是其中之一。如果想预先了解Silverlight 5的新功能,推荐阅读微软发布Silverlight 5 Beta新特性一文。

圣诞节和新年,一周时间基本没怎么阅读文章,随后的一周要补上。^_^

总结上周的Silverlight,WPF和Windows Phone的学习文章。

本周Silverlight学习资源更新:
Silverlight中如何实现虚线边框 银光中国
Silverlight Grid 边界线处理 duicky
SilverLight搭建WCF聊天室详细过程(四)好友上线 fugitiver
SilverLight搭建WCF聊天室详细过程(六)打开聊天窗口 fugitiver
SilverLight搭建WCF聊天室详细过程(八)发送文本消息 fugitiver
SilverLight搭建WCF聊天室详细过程(十)接收离线消息 fugitiver
SilverLight搭建WCF聊天室详细过程(十一)发送图片 fugitiver
SilverLight的List<T>、ObservableCollection<T>和INot 天神一
silverlight游戏设计(四)角色/精灵篇之 — 精灵的设计 姜萌
SilverLight搭建WCF聊天室详细过程(十三)发送文件邀请 fugitiver
SilverLight搭建WCF聊天室详细过程(十五)接收文件 fugitiver
Silverlight客户端实现图片的截取和压缩—-之上传头像 无名菜鸟
Silverlight杂记-自定义loading 撞破南墙
[SilverLight] DataGrid实现批量输入(like Excel) Silent Void
Silverlight开发-“慢”游美丽的分形世界(画分形2) 撞破南墙
Silverlight+WCF 实战-网络象棋最终篇之非线程阻塞倒计时窗口-应用篇(七) 路过秋天
SilverLight搭建WCF聊天室详细过程(十六)仿QQ消息提醒 fugitiver
Silverlight WriteableBitmap版-流体力学的演示 撞破南墙
SilverLight搭建WCF聊天室详细过程(十七)新用户注册并刷新所有在线好友列表 fugitiver
SilverLight搭建WCF聊天室详细过程(十八)视频 fugitiver
silverlight 清空所有文本框 汪立
如何在一个跨域环境中用Silverlight客户端使用自托管的WCF服务 微软Internet开发者
winform和silverlight交互 漫游者
Silverlight 自定义控件模板管理 (silverlight 学习笔记) Lvachel`
将 Silverlight 程序部署到 IIS (1) 炭炭
SilverLight使用javascrip几种方法 fugitiver
SilverLight中使用ASP.NET session fugitiver
让DIV悬浮在SilverLight之上 fugitiver
给SilverLight传值之–属性传值 fugitiver
SilverLight中DataGrid显示值转换 fugitiver
Silverlight C# 游戏开发:L7 HeightMap nowpaper
SilverLight搭建WCF聊天室详细过程(十九)WCF服务端变量以及对象设计思路 fugitiver
SilverLight搭建WCF聊天室详细过程(七)打开窗口后添加到任务栏 fugitiver
SilverLight搭建WCF聊天室详细过程(十四)发送文件 fugitiver
SilverLight搭建WCF聊天室详细过程(三)好友列表之 Accordion滑动分组动态绑定 fugitiver
SilverLight搭建WCF聊天室详细过程(九)接收文本消息 fugitiver
SilverLight搭建WCF聊天室详细过程(五)好友下线 fugitiver
Siverlight支持断点续传的多文件上传解决方案 .自.在.
SilverLight使用WCF RIA SERVICE实现对数据库的操作(查询) fugitiver
SilverLight使用WCF RIA SERVICE实现对数据库的操作 (添加,删除,更新) fugitiver
SilverLight使用WCF RIA SERVICE返回自定义类 fugitiver
Button中MouseLeftButtonDown和MouseLeftButtonUp事件无法触发的解决方案 giser2007
SilverLight搭建WCF聊天室详细过程(二十)WCF服务端用户列表字典的应用 fugitiver
SilverLight用DataContext显示数据 JerryT
SilverLight搭建WCF聊天室详细过程(二十一)关于聊天室项目错误排查 fugitiver
Silverlight实现DataGrid的Select All功能 Jason Li
silverlight DataBind 小Demo livewall
silverlight 4中datagrid列标题和列内容居中问题 guoyuanwei
Silverlight 自定义表格 duicky
在Silverlight中打开网页的几种方法 Windie Chai
Silverlight 之轻 佚名
Silverlight 应用程序中未处理的错误 InitializeError 解决方法 自由骑士笃志
Silverlight 3 + WCF 的例外處理 黄伟荣
silverlight 与 ASP.NET 会员系统 m a r c h23
Silverlight 4使用Domain Service做资料快速存取 黄伟荣
Silverlight利用DispatcherTimer做出"图片轮播"的功能 puma
Silverlight资料验证(Data Validation) eternaltung
Silverlight使用CircularPanel让ListBox的Items环状排列 eternaltung

本周WPF学习资源更新:

WPF动画(应用VisualBrush画刷) 2sws
WPF动画(监视动画进度) 2sws
WPF动画(图片渐变效果) 2sws
【WPF】自定义GridLineDecorator给ListView画网格 RMay
WPF动画(应用VisualBrush画刷Test) 2sws
使用elementhost将wpf内容移植到winform窗体 vpoint2009
WPF动画(关键帧动画) 2sws
WPF动画(离散关键帧动画) 2sws
ZAM 3D入门教程(1):初识ZAM 3D Alexis
ZAM 3D入门教程(2):场景编辑器 Alexis
ZAM 3D入门教程(3):Viewport Alexis
ZAM 3D入门教程(4):Extrusion编辑器 Alexis
ZAM 3D入门教程(5):Lathe编辑器 Alexis
ZAM 3D入门教程(6):导入AI和EPS格式的文件 Alexis
WPF的消息机制(一)- 让应用程序动起来 葡萄城控件技术团队
ListView 的三种数据绑定方式 xiaokang088
WPF下可编辑Header的Tab控件实现 葡萄城控件技术团队
WPF Image绑定中碰到的事 刘剑
WPF与混淆器 徐明璐
Microsoft Visual Studio 2010 编辑器增加背景图片插件[源码] 王文壮
WPF的消息机制(二)- WPF内部的5个窗口之隐藏消息窗口 葡萄城控件技术团队
WPF快速指导1:资源 luminji
在WPF中內嵌WindowsForm控制項 Ouch
Binding in WPF and Silverlight – (一)使用C# Ouch
Binding in WPF and Silverlight – (二)使用Visual Studio和Blend Ouch
WPF动画冰雪效果(可视化对象) 2sws
WinForm应用程序中嵌入WPF控件 Retrying
WPF检查滑鼠有没有点到物件 help

本周Windows Phone 7学习资源更新:

WP7 App性能优化(11):检测应用程序性能(Ⅳ) MagicBoy110
Windows Phone– Passing arguments between pages and Input Sc 永恒的记忆
Silverlight for Windows Phone 7–Popup 永恒的记忆
Operation not permitted on IsolatedStorageFileStream. 永恒的记忆
Windows Mobile设备常见任务开发(2)-个人信息管理 MagicBoy110
Windows Phone 7 XNA触控操作之Gestures 永恒的记忆
Windows Phone 7 For Silverlight 生命周期 永恒的记忆
分享你的Windows Phone 7应用程序 永恒的记忆
Windows Phone Marketplace注意事项 永恒的记忆
在你的Windows Phone 7 应用程序中植入广告(广告控件的使用) 永恒的记忆
Windows Phone 7 图表控件的使用 永恒的记忆
Windows Mobile设备常见开发任务(3)–语音呼叫与短消息 MagicBoy110
Windows Phone 7独立存储空间IsolatedStorage 永恒的记忆
Windows Phone 7中使用PhoneApplicationService类保存应用程序状态 永恒的记忆
Windows Mobile设备常见任务开发(4)–状态与通知 MagicBoy110
windows mobile网络设备-DMProcessConfigXML snow wolf
Windows Phone 7 不温不火学习之《独立存储空间》 Terry_龙
Windows Phone 7项目实战之记事本(一) 永恒的记忆
Windows Phone 7的多种使用技巧 gwalker
WP7 App性能优化(13):检测应用程序性能(Ⅵ) MagicBoy110
Windows Phone 7调用必应翻译服务 永恒的记忆
WP7 XNA 使用Guide输入文字、显示讯息与试用版测试 help
WP7 XNA ContentPipelen help
WP7 XNA触控与手势 help
Windows Phone 7 程式碼效能分析器 kylin
本周开源实例代码和作品展示:
本周推荐学习书籍:

Pro WPF and Silverlight MVVM,详细介绍MVVM设计模型在WPF和Silverlight中的应用。

该书是WPF和Silverlight专业设计书籍。

书籍下载

欢迎大家加入“专注Silverlight”QQ技术群,目前,1-8群都已经满员,新开200人九群,欢迎大家加入一起学习讨论Silverlight&WPF&Widnows Phone开发技术。
22308706(一群) 超级群500人
37891947(二群) 超级群500人
100844510(三群) 高级群200人
32679922(四群) 超级群500人
23413513(五群) 高级群200人
32679955(六群) 超级群500人

61267622(七群) 超级群500人

88585140(八群) 超级群500人

128043302(九群 企业应用开发推荐群) 高级群200人

未能初始化 AppDomain:/LM/W3SVC/1/Root,未能加载文件或程序集“System.Web.

mikel阅读(1241)

更新了dll后提示:

未能初始化 AppDomain:/LM/W3SVC/1/Root,未能加载文件或程序集“System.Web.

重启后IIS好了

开发的项目在vs2005开发环境下就可以运行,没有一点错,但是放到IIS浏览的时候就出错
页面错误提示如下:
服务器应用程序不可用
您试图在此 Web 服务器上访问的 Web 应用程序当前不可用。请点击 Web 浏览器中的“刷新”按钮重试您的请求。
查看系统事件日志,发现一个错误和一个警告
错误:
由于无法创建应用程序域,因此未能执行请求。错误: 0x80070005 拒绝访问。
警告:
未能初始化 AppDomain:/LM/W3SVC/…
Exception: System.IO.FileLoadException
Message: 未能加载文件或程序集“System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a”或它的某一个依赖项。拒绝访问。
在网上查找了一圈,发现好像无论是2003还是xp都会出现这种问题,产生问题的原因有:1、ASP.NET2.0没有正确地在IIS中注册 2、权限问题
如果是第一种情况,可以重新注册ASP.NET:系统盘\windows\microsoft.net\framework\v2.0.50727([color=#0080ff]此处为版本号[/color])\aspnet_regiis.exe -i
如果是权限问题,需要确保ASP.NET运行帐户(默认情况下,在win2003中是Network Service,在xp中是aspnet)对N个目录具有相应的访问权限,主要是系统目录(具体列表可以在网上很容易找到),还有一个容易忽略的目录:

[转载]更灵活,更易维护的WebHandler之通用webHandler编码方案(1)

mikel阅读(1013)

[转载]更灵活,更易维护的WebHandler之通用webHandler编码方案(1) – 刘铭.net-OPS.cc – 博客园.

一般处理程序(.ashx)比Web窗体文件(.aspx)性能更好,再不涉及到html的场景中经常用到!

通过VS创建的ashx文件包括代码后置文件,而实际上在ashx文件中定义只需要声明Web Handler并添加class

如: <%@ WebHandler Class=”Web.Handler” %>

我们可以在项目里面创建一个实现IHttpHandler接口的类,然后将ashx文件class设为该类的名称,这样维护起来是不是更方便?

大多数的同学可能就直接在IHttpHandler的ProccessRequest(HttpContext context)方法中添加自己的代码了,但如果网站包含50个ashx文件的话又会怎么样呢?下面我来阐述一个思路

我们是否可以将要请求的代码包含在一个个的类里,然后在ProccessRequest方法里利用反射技术执行代码就好了呢?

反射,程序员的快乐!

下面我们一步一步开始实现我们的想法:

首先我们需要为被执行代码添加授权,表明他能通过WebHandler执行,要不然就能通过WebHandler执行类库里的任何类!

1 代码:WebExecuteAttribute.cs
2 namespace HuiShi.Web
3 {
4 using System;
5 [AttributeUsage(AttributeTargets.Class,AllowMultiple=false,Inherited=true)]
6 public class WebExecuteAttribute : Attribute{}
7 }
8
9 }
东方网新,为您提供专业的网站建设,软件开发,网络营销SEO,网络推广服务,代理国外主机空间,域名注册,服务热线:(+86)18608275575,电子邮件:master#atnet.cc;欢迎您访问东方网新网站:www.atnet.cc

下面该是反射技术大展神手的时候了!先说明一下我们请求的URI格式如下:

http://localhost:11080/exc.ashx?cmd=IPQuery,GetNameByAddress,127.0.0.1

参数以”,”格开,IPQuery为类,GetNameByAddress为IPQuery的方法,GetNameByAddress后的为方法的参数

实际上执行的代码为:

01 namespace HuiShi.Web
02 {
03 using System;
04 using System.Web;
05
06 [WebExecute]
07 public class IPQuery
08 {
09 public string GetNameByAddress(string address)
10 {
11 return “newmin’s website www.atnet.cc“;
12 }
13 }
14 }

在代码中通过”,”来将参数传给方法,并判断方法的返回值是否可以输出到页面,可以的话就输出到页面!

01 代码:ExecuteHandler.cs
02
03 namespace HuiShi.Web
04 {
05 using System;
06 using System.Web;
07 using System.Reflection;
08 using System.Collections.Generic;
09
10 public class ExecuteHandler : IHttpHandler
11 {
12
13 #region IHttpHandler 成员
14 public bool IsReusable{ get; set; }
15 public void ProcessRequest(HttpContext context)
16 {
17 string cmd=context.Request["cmd"].Replace(“+”,” “); //将空格做为+号替换
18
19 string[] args = cmd.Split(‘,’);
20 if (args.Length > 2)
21 {
22 //获取执行当前代码的程序集并创建实例
23 Assembly ass = Assembly.GetAssembly(this.GetType());
24 object obj = ass.CreateInstance(this.GetType().Namespace+”.”+args[0], true);
25
26 //获取实例类型
27 Type type=obj.GetType();
28
29 //未添加WebExecuteAttribute特性的类将不被执行
30 object[] attrs= type.GetCustomAttributes(typeof(WebExecuteAttribute), false);
31 WebExecuteAttribute attr =attrs.Length>0?attrs[0] as WebExecuteAttribute:null;
32 if (attr == null) { context.Response.Write(“此模块不允许被执行!”); return; }
33
34 //获取方法并执行
35 MethodInfo method =type.GetMethod(args[1],BindingFlags.Instance|BindingFlags.Public|BindingFlags.IgnoreCase);
36 object returnObj=method.GetParameters() != null?method.Invoke(obj,cmd.Substring(args[0].Length + args[1].Length + 2).Split(‘,’))
37 :method.Invoke(obj, null);
38
39 //如国返回String类型或值类型则输出到页面
40 if (method.ReturnType == typeof(string) ||obj is ValueType)
41 context.Response.Write(returnObj.ToString());
42 }
43 }
44
45 #endregion
46 }
47 }
东方网新,为您提供专业的网站建设,软件开发,网络营销SEO,网络推广服务,代理国外主机空间,域名注册,服务热线:(+86)18608275575,电子邮件:master#atnet.cc;欢迎您访问东方网新网站:www.atnet.cc

然后我们创建1个WebHandler将其Class设为”HuiShi.Web.ExecuteHandler”,再在 ExecuteHandler命名空间下创建几个类,并用[WebExecute]特性修饰,这样我们只需要加代码而不用加文件就可以完成操作了!是不是 省了很多功夫,将使用WebHandler请求的类放到1个文件中集中管理,不是方便了代码组织管理吗?

想想上面的实现,没什么错误,但如果我们要将WebHandler封装成一个动态链接库,引用到其他项目的话呢?

[转载]更灵活,更易维护的WebHandler之通用webHandler编码方案(2)

mikel阅读(890)

[转载]更灵活,更易维护的WebHandler之通用webHandler编码方案(2) – 刘铭.net-OPS.cc – 博客园.

上一篇:更灵活,更易维护的WebHandler之通用webHandler编码方案(1) 中介绍了在同一个程序集中使用webHandler执行类的方法,

但在多数情况下,我们会将WebHandler封装进一个单独的动态链接库,我们需要将引用WebHandler DLL的程序集或程序集中的任意一个类的Type做为参数传递给WebHandler,

这样就可以在WebHandler中利用反射调用引用WebHandler类库的程序集中的代码!

实现代码如下:

01 /* *
02 * name     : ExecuteHandler.cs
03 * author   : newmin
04 * date     : 09/29 2010
05 * note     : 用来处理请求,请求的URI参数如:Exc.ashx?cmd=IP,GetIP,127.0.0.1
06 *
07 * 要执行操作的类必需要程序集名称命名空间下:
08 * 如要执行AtNet.Security下的User类,则User类的命名空间为:HuiShi.Security.User
09 * 调用方式**.ashx?cmd=User,GetScore,newmin
10 *
11 * */
12 namespace AtNet.Web
13 {
14 using System;
15 using System.Web;
16 using System.Reflection;
17 using System.Collections.Generic;
18
19 public abstract class ExecuteHandler : IHttpHandler
20 {
21 //绑定类型用于获取程序集,只能在子类的静态构造函数中赋值
22 protected static Type _type;
23 #region IHttpHandler 成员
24 public bool IsReusable{ get; set; }
25
26 public void ProcessRequest(HttpContext context)
27 {
28 string cmd=context.Request["cmd"].Replace("+"," "); //将空格做为+号替换
29
30 string[] args = cmd.Split(',');
31 if (args.Length > 2)
32 {
33 //获取执行当前代码的程序集并创建实例
34 Assembly ass = Assembly.GetAssembly(_type);
35 object obj = ass.CreateInstance(_type.Namespace+"."+args[0], true);
36
37 //获取实例类型
38 Type type=obj.GetType();
39
40 //未添加WebExecuteAttribute特性的类将不被执行
41 object[] attrs= type.GetCustomAttributes(typeof(WebExecuteAttribute), false);
42 WebExecuteAttribute attr =attrs.Length>0?attrs[0] as WebExecuteAttribute:null;
43 if (attr == null) { context.Response.Write("此模块不允许被执行!"); return; }
44
45 //获取方法并执行
46 MethodInfo method =type.GetMethod(args[1],BindingFlags.Instance|BindingFlags.Public|BindingFlags.IgnoreCase);
47 object returnObj=method.GetParameters() != null?method.Invoke(obj,cmd.Substring(args[0].Length + args[1].Length + 2).Split(','))
48 :method.Invoke(obj, null);
49
50 //如国返回String类型或值类型则输出到页面
51 if (method.ReturnType == typeof(string) ||obj is ValueType)
52 context.Response.Write(returnObj.ToString());
53 }
54 }
55
56 #endregion
57 }
58 }

我们需在继承ExecuteHandler的类的静态构造函数中对_type赋值:

01 namespace AtNet.Web.Tools
02 {
03 using System;
04 using System.Reflection;
05
06 public class WebHandler:AtNet.Web.ExecuteHandler
07 {
08 static WebHandler()
09 {
10 _type = typeof(WebHandler);
11 }
12 }
13 }

这样我们就能在将ExecuteHandler分离出来,被别的项目所引用

[转载]Lucene.Net:构造搜索表达式简化搜索

mikel阅读(1041)

[转载]Lucene.Net:构造搜索表达式简化搜索 – 努力,天赋,笑容,自信 – 博客园.

我们知道利用Lucene.Net的不同的Query(常见如BooleanQuery,RangeQuery等等),可以有针对性地进行各种不同 类型的搜索。利用QueryParser(或MultiFieldQueryParser),配合构造好的搜索关键字(搜索表达式),也可以实现不同类型 的搜索。本文重点就是简单介绍一下搜索表达式和不同类型的Query之间的简单对比。本文最后的demo,QueryApp工程下有文章里贴出的大部分示 例代码,代码自己会说话,有时候它可能更好地表达了文章作者的思路。您可以下载对照着本文进行阅读。

一、与或非

1、与

举例:搜索contents既包含“jeffreyzhao”,又有“ 老赵”的记录:

1 public static void NormalQueryParserTest(Analyzer analyzer, string field, string keyword)
2 {
3 QueryParser parser = new QueryParser(Version.LUCENE_29, field, analyzer);
4 Query query = parser.Parse(keyword);
5 ShowQueryExpression(analyzer, query, keyword);
6 SearchToShow(query);
7 Console.WriteLine();
8 }

调用的时候,我们构造一个搜索关键词“+jeffreyzhao +老赵”:

1 string field = "contents";//搜索的对应字段
2 keyword = "+jeffreyzhao +老赵";
3 LuceneSearch.NormalQueryParserTest(analyzer, field, keyword);//+contents:jeffreyzhao +contents:"老 赵"

搜索结果中我们可以看到,通过加号(+)可以表达与(AND)的关系(+contents:jeffreyzhao +contents:”老 赵” )。

特点:不同关键字越多,匹配的结果可能越少。

2、或

输入多个关键字,任何包含其中一个关键字的记录都被搜索出来:

1 string keyword = "jeffreyzhao 老赵";//搜索输入关键词
2 string field = "contents";//搜索的对应字段
3 LuceneSearch.NormalQueryParserTest(analyzer, field, keyword); //contents:jeffreyzhao contents:"老 赵"

特点:不同关键字越多,匹配的结果可能越多。

3、非(!)

1 keyword = "+jeffreyzhao -老赵";
2 LuceneSearch.NormalQueryParserTest(analyzer, field, keyword);//+contents:jeffreyzhao -contents:"老 赵"
3
4 keyword = "+jeffreyzhao !老赵";
5 LuceneSearch.NormalQueryParserTest(analyzer, field, keyword);//+contents:jeffreyzhao -contents:"老 赵"

上面的两种写法,转换成表达式都是+contents:jeffreyzhao -contents:”老 赵” 。

根据我们的测试结果,与或非的关系可以总结如下:

a & b  =>   +a +b
a || b  =>   a    b
a  !b   =>   +a  -b

这种与或非的关系,我们还可以通过BooleanQuery表达同样的搜索:

01 public static void BooleanQueryTest(Analyzer analyzer, string field, string keyword, BooleanClause.Occur[] flags)
02 {
03 Console.WriteLine("====BooleanQuery====");
04 string[] arrKeywords = keyword.Trim().Split(new char[] { ' ', ',', ',', '、' }, StringSplitOptions.RemoveEmptyEntries);
05 QueryParser parser = new QueryParser(Version.LUCENE_29, field, analyzer);
06 BooleanQuery bq = new BooleanQuery();
07 int counter = 0;
08 foreach (string item in arrKeywords)
09 {
10 Query query = parser.Parse(item);
11 bq.Add(query, flags[counter]);
12 counter++;
13 }
14 ShowQueryExpression(analyzer, bq, keyword);
15 SearchToShow(bq);
16 Console.WriteLine();
17 }

其中BooleanClause.Occur(MUST:+  MUST_NOT:-   SHOULD:无符号)的选择至关重要:

01 string field = "contents";//搜索的对应字段
02 IList<Analyzer> listAnalyzer =LuceneAnalyzer. BuildAnalyzers();
03 BooleanClause.Occur[] occurs = new BooleanClause.Occur[] { BooleanClause.Occur.MUST, BooleanClause.Occur.MUST };
04 foreach (Analyzer analyzer in listAnalyzer)
05 {
06
07 //NormalQueryTest(analyzer);
08 //LuceneSearch.NormalQueryParserTest(analyzer, field, keyword);//直接通过QueryParser配合构造好的查询表达式搜索
09
10 //LuceneSearch.TermQueryTest(analyzer, field, "高手");//contents:高手
11
12 LuceneSearch.BooleanQueryTest(analyzer, field, "jeffreyzhao 老赵", occurs);//+contents:jeffreyzhao +contents:"老 赵"
13
14 //LuceneSearch.RangeQueryTest(analyzer, rangeField, start, end); // createdate:[20101010 TO 20110101]  createdate:[20101010 TO 20110101}
15
16 //LuceneSearch.PrefixQueryTest(analyzer, field, "hell"); // contents:hell*  (可以找到hello world那一项)
17
18 //LuceneSearch.WildcardQueryTest(analyzer, field, "高手"); //contents:高手
19
20 //LuceneSearch.FuzzyQueryTest(analyzer, field, "牛"); //contents:牛~0.5
21
22 //LuceneSearch.PhraseQueryTest(analyzer, field, "hello world", 1); //contents:"hello world"~1
23
24 //LuceneSearch.MulFieldsSearchTest(analyzer, fieldArr, "博  园", occurs); //+(contents:博 contents:园) +(title:博 title:园)
25 }

二、范围

01 string rangeField = "createdate";//范围搜索对应字段
02 string start = "20101010";
03 string end = "20110101";
04 IList<Analyzer> listAnalyzer =LuceneAnalyzer. BuildAnalyzers();
05 foreach (Analyzer analyzer in listAnalyzer)
06 {
07
08 LuceneSearch.RangeQueryTest(analyzer, rangeField, start, end); // createdate:[20101010 TO 20110101]  createdate:[20101010 TO 20110101}
09
10 }

同样道理,RangeQuery(或者TermRangeQuery)也可以实现范围搜索。

三、多字段组合搜索

搜索时,对两个或多个字段进行匹配的时候,可以用下面的方法:

01 public static void MulFieldsSearchTest(Analyzer analyzer, string[] fields, string keyword, BooleanClause.Occur[] flags)
02 {
03 Console.WriteLine("====MultiFieldQueryParser====");
04 MultiFieldQueryParser parser = new MultiFieldQueryParser(Version.LUCENE_29, fields, analyzer);
05 //Query query = parser.Parse(keyword);
06 Query query = MultiFieldQueryParser.Parse(Version.LUCENE_29, keyword, fields, flags, analyzer);
07 ShowQueryExpression(analyzer, query, keyword);
08 SearchToShow(query);
09 Console.WriteLine();
10 }

简单调用如下:

1 string[] fieldArr = new string[] { field, "title" };//两个字段
2 IList<Analyzer> listAnalyzer =LuceneAnalyzer. BuildAnalyzers();
3 foreach (Analyzer analyzer in listAnalyzer)
4 {
5 LuceneSearch.MulFieldsSearchTest(analyzer, fieldArr, "博  园", occurs); //+(contents:博 contents:园) +(title:博 title:园)
6 }

如果我们把搜索关键字改为“博 -园”,则表达式就是“+(contents:博 -contents:园) +(title:博 -title:园)”,这也符合单个字段搜索。

注意:如你所知,与或非和范围不是搜索关系的全部。实际上,通过Lucene,你可以根据 +-!():^[]{}~*? 这几种符号,合理构造出表达真实意图的复杂表达式来代替不同类型的Query。我在示例代码中做了几个针对StandardAnalyzer的简单尝试,测试结果符合预期。

我在参考网上不少文章的时候,发现很多提到的问题都没有重现,再看他们的lucene的版本都低于2.0,我大胆猜测Lucene.Net的类库已经改进了不少,一开始还以为自己的测试不到位,囧。

四、分词效果

Analyzer选择不同,搜索结果也不同,尤其是对于中文。用下面的函数可以测试分词效果:

01 /// <summary>
02 /// 测试不同的Analyzer分词效果
03 /// </summary>
04 /// <param name="listAnalyzer"></param>
05 /// <param name="input"></param>
06 public static void TestAnalyzer(IList<Analyzer> listAnalyzer, string input)
07 {
08 foreach (Analyzer analyzer in listAnalyzer)
09 {
10 Console.WriteLine(string.Format("{0}:", analyzer.ToString()));
11
12 using (TextReader reader = new StringReader(input))
13 {
14 TokenStream stream = analyzer.ReusableTokenStream(string.Empty, reader);
15 Lucene.Net.Analysis.Token token = null;
16 while ((token = stream.Next()) != null)
17 {
18 Console.WriteLine(token.TermText());
19 }
20 }
21
22 Console.WriteLine();
23 }
24 }

不同的Analyzer,分词效果可以总结如下:

StandardAnalyzer       对中文单字拆分;

WhitespaceAnalyzer  按空格拆分,对中文的支持不好;

KeywordAnalyzer       输入什么,分词就是什么;

SimpleAnalyzer           按标点和空格拆分,对中文的支持不好

StopAnalyzer               和SimpleAnalyzer类似;

选来选去,StandardAnalyzer 的效果还是很不错的,一般的应用差不多就够用了。 您可以使用不同的Analyzer,然后对比它们的搜索表达式并找出它们的不同之处。

demo下载:LuceneNetApp

[转载]ASP.NET MVC中的扩展点(五)方法选择器

mikel阅读(978)

[转载]MVC中的扩展点(五)方法选择器 – xfrog – 博客园.

前一篇中我们介绍了过滤器,通过方法和结果过滤器我们可以在MVC执行方法及结果的前后注入自己的功能,通过授权过滤器可以执行一些权限检查,阻止无权用 户调用方法,通过异常过滤器处理方法执行过程中产生的异常。那么在执行方法之前,MVC又是如何确定使用何种控制器及其方法的呢?

我们已经知道,MVC使用DefaultControllerFactory控制器工厂来实例化控制器,其大致过程如下:

1、默认Route类的GetRouteData方法将按我们设定的Url规则解析当前请求的Url,并将Url规则中的给个参数存入RouteData.Values集合中。我们知道Mvc添加了一个默认的Route项:

routes.MapRoute(
    "Default", // Route name
    "{controller}/{action}/{id}", // URL with parameters
    new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
 );

.codearea { color: black; background-color: white; line-height: 18px; border: 1px solid rgb(79, 129, 189); margin: 0pt; width: auto ! important; overflow: auto; text-align: left; font-size: 12px; font-family: “Courier New”,”Consolas”,”Fixedsys”,”BitStream Vera Sans Mono”,courier,monospace,serif; }.codearea pre { color: black; line-height: 18px; padding: 0pt 0pt 0pt 12px ! important; margin: 0em; background-color: rgb(255, 255, 255) ! important; }.linewrap pre { white-space: pre-wrap; word-wrap: break-word; }.codearea pre.alt { background-color: rgb(247, 247, 255) ! important; }.codearea .lnum { color: rgb(79, 129, 189); line-height: 18px; }

按以上规则,如果我们请求的Url为:

http://localhost/News/GetNewsList

则对应的RouteData.Values[“controller”] = “News”;  RouteData.Values[“action”] = “NewsList”

2、DefaultControllerFactory根据Route.Values[“controller”]确定实际的控制器类型,并实例化,如上例控制器工厂知道应实例化的控制器类型为NewsController。

3、通过控制器工厂返回的Controller对象的 Execute方法,控制器通过一个实现了IActionInvoker接口的类(默认为ControllerActionInvoker类)使用 RouteData.Values[“action”]值,确定具体运行控制器中的那一个方法。

4、执行控制器中的方法生成ActionResult

5、执行ActionResult.ExecuteActionResult生成最终应答内容。

在4、5步骤中涉及到我们上一章中介绍的过滤器,而方法选择器是在第3步骤中使用的,ControllerActionInvoker类中使用ActionMethodSelector类来获取与路由信息匹配的方法,具体执行过程如下图所示:

SelectorActivity

图中红色终点表示异常。ActionMethodSelector首先从控制器中非静态方法中获取方法名称等于 RouteData.Values[“action”]或通过ActionName特性指定的名称等于 RouteData.Values[“action”]的方法列表,其次依次调用方法列表中的每个方法上的选择器,去掉选择器返回为false的部分,如 果最终由一个方法匹配则使用这个方法,如果没有方法匹配,则再检查方法列表中没有选择器的方法,如果存在一个,选中它,如果没有,则直接调用控制器的 HandleUnknownAction方法,Controller中此方法默认返回一个404的HTTP错误。

下面我们来看MVC中实现的默认选择器类型:

SelectorClass

ActionNameAttribute用于声明方法的别名,通常情况下使用ActionName将控制器中不同的方法映射为相同的控制器方法(相同的 Url访问不同的方法)。它从抽象类ActionNameSelectorAttribute继承,你也可以从此类中继承实现自己的ActionName 特性(不过似乎用处不大)。

ActionMethodSelectorAttribute抽象类是一些列选择器的基类,ActionMethodSelector选择方法时,会调用 IsValidForRequest方法来检查当前方法是否有效。MVC实现了几个默认的选择器:HttpGet、HttpPost、 HttpDelete、HttpPut以及AcceptVerbs用于检查当前请求的方式(匹配GET方法、POST方法等,AcceptVerbs用于 匹配多个方法),事实上HttpGet等选择器是对AcceptVerbs的封装。另外一个选择器:NonAction表示当前方法不对外部请求公开(它 的IsValidForRequest始终返回false)。如果我们需要实现自己的选择逻辑,则应从 ActionMethodSelectorAttribute类继承。

以下示例实现一个选择器,将根据浏览器类型将相同的Url映射到不同的控制器方法:

1、创建一个空的MVC项目

2、实现BrowseSelectorAttribute

显示行号 复制代码 BrowseSelectorAttribute
  1. public class BrowseSelectorAttribute : ActionMethodSelectorAttribute
    
  2. {
    
  3.     private string _userAgent = String.Empty;
    
  4.     public BrowseSelectorAttribute(string userAgent)
    
  5.     {
    
  6.         _userAgent = userAgent;
    
  7.     }
    
  8.     public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
    
  9.     {
    
  10.         return controllerContext.HttpContext.Request.UserAgent.Contains(_userAgent);
    
  11.     }
    
  12. }
    

.src_container { background-color: rgb(231, 229, 220); width: 99%; overflow: hidden; margin: 12px 0pt ! important; padding: 0px 3px 3px 0px; }.src_container .titlebar { background-color: rgb(212, 223, 255); border-width: 1px 1px 0pt; border-style: solid solid none; border-color: rgb(79, 129, 189) rgb(79, 129, 189) -moz-use-text-color; padding: 3px 24px; margin: 0pt; width: auto; line-height: 120%; overflow: hidden; text-align: left; font-size: 12px; }.src_container .toolbar { display: inline; font-weight: normal; font-size: 100%; float: right; color: rgb(0, 0, 255); text-align: left; overflow: hidden; }.toolbar span.button { display: inline; font-weight: normal; font-size: 100%; color: rgb(0, 0, 255); text-align: left; overflow: hidden; cursor: pointer; }.src_container div.clientarea { background-color: white; border: 1px solid rgb(79, 129, 189); margin: 0pt; width: auto ! important; height: auto; overflow: auto; text-align: left; font-size: 12px; font-family: “Courier New”,”Consolas”,”Fixedsys”,courier,monospace,serif; }.src_container ol.mainarea { padding: 0pt 0pt 0pt 52px; margin: 0pt; background-color: rgb(247, 247, 255) ! important; }.number_show { padding-left: 52px ! important; list-style: decimal outside none ! important; }.number_show li { list-style: decimal outside none ! important; border-left: 1px dotted rgb(79, 129, 189); }.number_hide { padding-left: 0px ! important; list-style-type: none ! important; }.number_hide li { list-style-type: none ! important; border-left: 0px none; }ol.mainarea li { display: list-item ! important; font-size: 12px ! important; margin: 0pt ! important; line-height: 18px ! important; padding: 0pt 0pt 0pt 0px ! important; background-color: rgb(247, 247, 255) ! important; color: rgb(79, 129, 189); }ol.mainarea li pre { color: black; line-height: 18px; padding: 0pt 0pt 0pt 12px ! important; margin: 0em; background-color: rgb(255, 255, 255) ! important; }.linewrap ol.mainarea li pre { white-space: pre-wrap; word-wrap: break-word; }ol.mainarea li pre.alt { background-color: rgb(247, 247, 255) ! important; }3、创建HomeController控制器

显示行号 复制代码 HomeController
  1. public class HomeController : Controller
    
  2. {
    
  3.     [ActionName("Index")]
    
  4.     [BrowseSelector("MSIE")]
    
  5.     public ActionResult IEIndex()
    
  6.     {
    
  7.         return Content("通过IE浏览器访问");
    
  8.     }
    
  9.     [ActionName("Index")]
    
  10.     [BrowseSelector("Chrome")]
    
  11.     public ActionResult ChromeIndex()
    
  12.     {
    
  13.         return Content("通过Chrome浏览器访问");
    
  14.     }
    
  15.     [ActionName("Index")]
    
  16.     public ActionResult OtherIndex()
    
  17.     {
    
  18.         return Content("通过其他浏览器访问");
    
  19.     }
    
  20. }
    

.src_container { background-color: rgb(231, 229, 220); width: 99%; overflow: hidden; margin: 12px 0pt ! important; padding: 0px 3px 3px 0px; }.src_container .titlebar { background-color: rgb(212, 223, 255); border-width: 1px 1px 0pt; border-style: solid solid none; border-color: rgb(79, 129, 189) rgb(79, 129, 189) -moz-use-text-color; padding: 3px 24px; margin: 0pt; width: auto; line-height: 120%; overflow: hidden; text-align: left; font-size: 12px; }.src_container .toolbar { display: inline; font-weight: normal; font-size: 100%; float: right; color: rgb(0, 0, 255); text-align: left; overflow: hidden; }.toolbar span.button { display: inline; font-weight: normal; font-size: 100%; color: rgb(0, 0, 255); text-align: left; overflow: hidden; cursor: pointer; }.src_container div.clientarea { background-color: white; border: 1px solid rgb(79, 129, 189); margin: 0pt; width: auto ! important; height: auto; overflow: auto; text-align: left; font-size: 12px; font-family: “Courier New”,”Consolas”,”Fixedsys”,courier,monospace,serif; }.src_container ol.mainarea { padding: 0pt 0pt 0pt 52px; margin: 0pt; background-color: rgb(247, 247, 255) ! important; }.number_show { padding-left: 52px ! important; list-style: decimal outside none ! important; }.number_show li { list-style: decimal outside none ! important; border-left: 1px dotted rgb(79, 129, 189); }.number_hide { padding-left: 0px ! important; list-style-type: none ! important; }.number_hide li { list-style-type: none ! important; border-left: 0px none; }ol.mainarea li { display: list-item ! important; font-size: 12px ! important; margin: 0pt ! important; line-height: 18px ! important; padding: 0pt 0pt 0pt 0px ! important; background-color: rgb(247, 247, 255) ! important; color: rgb(79, 129, 189); }ol.mainarea li pre { color: black; line-height: 18px; padding: 0pt 0pt 0pt 12px ! important; margin: 0em; background-color: rgb(255, 255, 255) ! important; }.linewrap ol.mainarea li pre { white-space: pre-wrap; word-wrap: break-word; }ol.mainarea li pre.alt { background-color: rgb(247, 247, 255) ! important; }

最后,选择器的功能似乎与授权过滤器类似:都可以”过滤”掉控制器方法,但是他们本质上是不同的:执行授权过滤器时,MVC已经确定调用哪个控制器方法, 而选择器是在MVC选择控制器方法时得一组过滤条件。如果通过选择器过滤后没有匹配方法,默认下会返回404错误,如果通过授权过滤器终止执行某个方法, 则返回的是你在通过授权过滤器上下文参数中指定的Result。

源代码下载

[转载]android 游戏导引(1. 建立 OpenGL 项目)

mikel阅读(1056)

[转载]android 游戏导引(1. 建立 OpenGL 项目) – 圣斗士 – 博客园.

Android 游戏导引(1. 建立 OpenGL 项目)

1 搭建环境

我的环境是 mac, 鉴于 windows 下搭建的教程网上很多,大家可以 google 之。说一下 mac 下的环境搭建过程。

  1. 下载 mac 版本的 Android SDK。天朝墙很坚固,贴下 2.3 下载地址,可以用超强盗链功能的迅雷下载。
    Platform Package Size MD5 Checksum
    Mac OS X (intel) android-sdk_r08-mac_86.zip 28797617 bytes d2e392c4e4680cbf2dfd6dbf82b662c7
    Linux (i386) android-sdk_r08-linux_86.tgz 26817291 bytes 3b626645b223d137d27beefbda0c94bc
  2. 解压文件。点击 tool 目录下的 android 文件。选择要下载的相应版本的 SDK, 文档,工具等。
  3. android 要求 jdk 版本大于 1.5, mac os x上预装的是 1.6 的版本。(java -version查看)。所以不必再下 jdk 了(想下官网也没提供mac版本)。
  4. 下载 Eclipse, 版本是 for Java Developers 的就可以。解压到某个文件夹下,直接运行其中的eclipse 就使用。
  5. 安装 adt。 Eclipse 的 Help菜单下的 Install new Software…. 点击 add 按钮, 在弹出的对话框 Location 中,输入 http://dl-ssl.google.com/android/eclipse/, OK, 省略。。。
  6. 配置 Eclipse 的android 环境。重启 Eclipse, 点击Eclipse 菜单下的 Preferences, 打开设置界面。找到android 项, 设置好 android sdk 目录,点 apply, 会显示你所有的 sdk 版本。OK。
  7. 建立一个 avd。 打开 Eclipse 的 Windows 菜单下的 “Android SDK and AVD”,创建好一个 avd。就正式配置成功了。

2 创建一个 android 项目

“File” -> “New”-> “Project”: 选择 android 工程:

设置好项目的信息和sdk版本:

好了一个项目就创建完了。

3 建立 OpenGL 程序框架

默认的,建立的程序中,一个 activity 的源码如下:

public class GlGame extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}

OpenGL 有自己的Surface: GLSurfaceView, 它内部提供了一个 Renderer 接口,我们所要做的就是注册一个自己的 Renderer。好了,先看我们的 activity:

import android.app.Activity;
import android.opengl.GLSurfaceView;
import android.opengl.GLSurfaceView.Renderer;
import android.os.Bundle;
public class GlGame extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.main);
Renderer render = new MyRenderer();//要实现的 Renderer
GLSurfaceView glView = new GLSurfaceView(this);
glView.setRenderer(render);
setContentView(glView);
}
}

Renderer 必须要实现3个抽象方法:

  • public void onDrawFrame(GL10 gl) 绘制
  • public void onSurfaceChanged(GL10 gl, int width, int height) 窗口大小改变
  • public void onSurfaceCreated(GL10 gl, EGLConfig config) 窗口建立

添加类 MyRenderer:

01 import javax.microedition.khronos.egl.EGLConfig;
02 import javax.microedition.khronos.opengles.GL10;
03
04 import android.opengl.GLSurfaceView.Renderer;
05
06 public class MyRenderer implements Renderer{
07
08 public void onDrawFrame(GL10 gl) {
09 gl.glClearColor(1, 0, 0, 0);
10 // 清除屏幕和深度缓存
11 gl.glClear(GL10.GL_COLOR_BUFFER_BIT) | GL10.GL_DEPTH_BUFFER_BIT);
12 }
13
14 public void onSurfaceChanged(GL10 gl, int width, int height) {
15 // 设置 OpenGL 场景的大小
16 gl.glViewport(0, 0, width, height);
17 }
18
19 public void onSurfaceCreated(GL10 gl, EGLConfig config) {
20 // TODO Auto-generated method stub
21
22 }
23
24 }

好了一个 OpenGL 框架就搭好了。接下来我们就进行可爱地屏幕绘制相关地东西了。下次再说吧。

[转载]VS2010设置断点无效的解决方法

mikel阅读(1217)

[转载]VS2010设置断点无效的解决方法 – giser2007 – 博客园.

当前不会命中断点,还没有为该文档加载任何符号”这个提示可能很多人都遇到过,首先我列几条网上常见的解决方案。

1、生成方式是Realse不是Debug

2、调试时到“附加到进程”菜单里看有没有“aspnet_wp.exe”的进程,如果没有,添加。

3、控件的事件丢失。

4、右键解决方案的属性里,看生成项里的“生成调试信息”那里是不是FALSE,如果是,改成TRUE。

5、想要调试的代码行根本不能调试。

可是我不属于其中任何一种。。但以上总结的5种的确也是原因,暂且写上。

后来突然灵光乍现,会不会是浏览器的问题,很多朋友可能默认浏览器不是IE,以前用VS2005时,都是会用IE打开页面,而到了VS2010,会 用电脑设置的默认浏览器打开,当然你把电脑的默认浏览器换成IE就可以解决,不过这样总感觉有点不爽,不过你不用担心,有解决方案。我现在是用 silverlight做开发,所以就以silverlight为例。

右键点击sampleTestPage.aspx(sample是解决方案名称)——浏览方式——把IE设置为默认——OK

[转载]android 游戏导引(2. 游戏的基础设置)

mikel阅读(1035)

[转载]android 游戏导引(2. 游戏的基础设置) – 圣斗士 – 博客园.

Android 游戏导引(2. 游戏的基础设置)

上一节已经学习了一个基本的 OpenGL 框架了,今天这一节就进一步设置一下 2D 游戏相关的东西了。对 2D 游戏的喜爱甚于 3D。 相信大多数人也是吧。

1 游戏全屏显示

2行代码搞定,一个让应用去掉自己的标题栏,一个设置全屏,放在应用的创建函数 OnCreate 中:

public class GlGame extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams. FLAG_FULLSCREEN ,
WindowManager.LayoutParams. FLAG_FULLSCREEN);
// ... 其他略
}
}

2 设置 OpenGL 的 2D 环境

我们先要设计好要建立的世界定位方式,就是坐标系,一般的 opengl 程序是标准的笛卡尔坐标系,即左下角为原点,x横向右延伸,y纵向上延伸。像著名的 cocos2d 引擎就是此种方式。我比较偏好另一套就是左上角为原点的描述方式,所以采用了此套坐标系:

GLSurfaceView 的 Renderer,给出了三个接口:创建时,大小改变时,绘制。我们在三个函数中采取的操作如下:

  • 创建时, onSurfaceCreated, 进行 OpenGL 的基本设置,如阴影平滑,深度测试啊神马的。
  • 大小改变时,onSurfaceChanged, 进行投影,视口等设置。
  • 绘制,onDrawFrame, 我们后续的游戏绘制主要在这个函数了。

2.1 onSurfaceCreated

不多说,都是基本设置。

public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// 告诉系统对透视进行修正
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
// 背景黑色
gl.glClearColor(0, 0, 0, 1);
// 启用阴影平滑
gl.glShadeModel(GL10.GL_SMOOTH);
// 设置深度缓存
gl.glClearDepthf(1.0f);
// 启用深度测试
gl.glEnable(GL10.GL_DEPTH_TEST);
// 所做深度测试的类型
gl.glDepthFunc(GL10.GL_LEQUAL);
}

2.2 onSurfaceChanged

public void onSurfaceChanged(GL10 gl, int width, int height) {
// 设置 OpenGL 场景的大小
gl.glViewport(0, 0, width, height);
// 设置投影矩阵
gl.glMatrixMode(GL10.GL_PROJECTION);
// 重置投影矩阵
gl.glLoadIdentity();
// 设置视口的大小
// gl.glOrthof(0, width, height, 0, -1000, 1000);
GLU.gluOrtho2D(gl, 0, width, height, 0);
// 重置模型矩阵
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
}

代码中先用 glViewPort 设定了场景的大小,我们所有的opengl世界都被投射到这个场景中,在这里,我们将场景的大小设置为窗口 Surface 的大小。

继而设置了投影矩阵,投影矩阵定义了 opengl 世界怎样反应在你的场景中,在 OpenGL 中又两种投影方式: 透视和正交。透视比较接近我们现实的方式了,你的眼睛发出的光形成一个夹角,离你的眼睛越近,东西越大,范围越小;反之离眼睛越远,东西越小,视野越开 阔。因此多用于 3D 中。 而正交却是世界中的物体按照平行的光线投射到一张纸上(你的画布),仿佛被压缩在上面,无论这个物体在世界中多远,投射结果还是原来的大小, 2d 游戏多用此种投影。

设置透视投影有 glFrustum 和 glu 库的 gluPerspective, 都可以设置上面透视投影中的角度,远近等参数。还可以 gluLookAt 来设置眼睛(相机)的位置。

设置正交投影有 glOrtho 和 glu 库的 gluOrth2D :

glOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far);
gluOrth2D(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top);

glu版本的y轴参数不用我们设置了,因为不会用到。由于我们的坐标系以左上角为原点,所以 left 和 top 参数为 0。

glMatrixMode() 函数指定了其下面的代码操作的是何种矩阵。 我们这里用到两类矩阵变换:投影变换和模型视图变换。投影变换中我们更改了世界空间的裁切范围,在模型视图变换中,我们可以移动和旋转世界中的物体,所以 我们在绘制的时候就是在模型视图矩阵变换中。 glLoadIdentity() 用于重置矩阵,清除上次的残留信息。

代码最后设定为模型视图变换,便于我们在绘制函数中移动和变换物体模型了。

2.3 onDrawFrame

先说明一下 GLSurfaceView 的 Renderer 绘制是在独立的线程中完成的,这个函数被不断的循环调用。

前面已经设置为模型视图矩阵了,每次 onDrawFrame 的时候,我们都要 glLoadIdentity 重置一次,清除上次绘制造成的残留信息。

public void onDrawFrame(GL10 gl) {
// 清除屏幕和深度缓存
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// 重置模型矩阵
gl.glLoadIdentity();
//... 要添加的具体绘制代码
}

3 三角形-测试

好了,上面已经设置好了,我们先来个简单的测试吧,在你的窗口中绘制一个红色三角形。先定义好三角形的三个角度,左上角为 (60,200), 右上角为 (180, 200), 下角为 (120,300)。

01 private FloatBuffer triggerBuffer = FloatBuffer.wrap(new float[]{
02 60,200, // 左上角
03 180, 200, // 右上角
04 120,300, // 下顶角
05 });
06
07 public void onDrawFrame(GL10 gl) {
08 // 清除屏幕和深度缓存
09 gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
10 // 重置模型矩阵
11 gl.glLoadIdentity();
12
13
14 gl.glPushMatrix();
15 gl.glColor4f(1, 0, 0, 0);
16 // 允许设置顶点
17 gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
18 gl.glVertexPointer(2, GL10.GL_FLOAT, 0, triggerBuffer);
19 gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);
20 // 取消设置顶点
21 gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
22 gl.glPopMatrix();
23 }

主要代码包围在了 glPushMatrix() 和 glPopMatrix() 中,OpenGL内部维护了各种矩阵栈,栈的操作就是 push 和 pop 了。这里我们的操作是在模型视图矩阵变换中进行的,所以操作的是模型视图栈。之所以压栈,我们不想绘制三角形的矩阵信息污染到外层的矩阵中,比如颜色设置 等。所以大家在绘制一个单位体的时候尽量使用 push 和 pop 操作。

先用 glColor4f 设置绘制颜色为红色。opengles 中少了 glBegin, glEnd 类标准函数,采用了数组顶点来设坐标方式,主要还是性能考虑吧。默认是关掉这个选项的,所以先开启,不用了再关闭: glEnableClientState(GL10.GLVERTEXARRAY), glDisableClientState(GL10.GLVERTEXARRAY).

指定数组顶点用 glVertexPointer, 指定完了就可以用 glDrawArray() 来将指定的数组中的顶点绘制出来了。这里有必要罗嗦一下这两个函数了,因为这两个函数用到的太多了。先看第一个:

void glVertexPointer (int size, int type, int stride, Buffer pointer)

参数:

size
每个顶点有几个数值描述。必须取值2,3,4之一。初始值是 4.
type
数组中每个顶点坐标的类型。取值:GLBYTE, GLSHORT, GLFIXED, GLFLOAT。初始值为 GLFLOAT。
stride
数组中每个顶点间的间隔,步长(字节位移)。取值若为 0 表示数组是连续的。初始值为 0。
pointer
就是你的数组了,存储着每个顶点的坐标值。初始值为 0。

注意了, type 中告诉 opengl 你的数组类型。 GLBYTE, GLSHORT, GLFLOAT 对应 byte[], short[], float[]. GLFIXED 对应 int[]. 有一个特别的地方, GLFIXED 描述的时候,大家的点坐标单位是 0x10000, 比如一个点是 (60, 120), 用 GLFIXED 的时候,需要设置为 (60 * 0x10000, 120 * 0x10000), 所以经常看到 int one = 0x10000 的编程语句, 这个数值就是这么来的。

再来看 glDrawArray:

void glDrawArrays (int mode, int first, int count);

参数:

mode
指定你要绘制何种图元, opengl 中的图元就这几个: GLPOINTS, GLLINESTRIP, GLLINELOOP, GLLINES, GLTRIANGLESTRIP, GLTRIANGLEFAN, GLTRIANGLES.
first
在已制定的数组中的开始位置(索引位置)
count
点的绘制次数, 比如我们绘制一个三角形,就是绘制三个顶点,即此参数为 3。

这两个函数就介绍这么多了,足以应付这个程序了。有问题可以查官方函数文档: http://www.khronos.org/opengles/sdk/1.1/docs/man/

好了,代码就介绍完了。一个三角形大家应该会绘制了吧,大家可以试试其他的图元,点,线,四边形,多边形等等。

学习愉快。

[转载]android 游戏导引(3. 图形引擎之模型管理)

mikel阅读(956)

[转载]android 游戏导引(3. 图形引擎之模型管理) – 圣斗士 – 博客园.

Android 游戏导引(3. 图形引擎之模型管理)

上一节中,我们构建了一个自己的场景世界。可以在内部绘制一些基本图元了。本来这一节要说说贴图的,想想还是休息下,放个小插曲,思考下模型的管 理,游戏引擎相关的东西。这些东西跟 cocos2d 很像,可能是 iphone 下常用 cocos2d 的缘故吧, 反正成熟且成功的东西,我们拿来用就行了。

源码下载: 点我吧

1 面向对象吧

基于教程到这里的进度,我们要会议几个图元模型的话,就要显式的在 onDrawFrame 中绘制。基于面向对象的思想,我们知道我们绘制的模型仅仅是一个渲染单位而已,并且我们在 onDrawFrame 的操作只是一个opengl 访问。 因此基于接口,我们的一个渲染模型类就诞生了。

2 模型父子链:树

你也许会说,上面要渲染的模型太多的时候太散乱了。想到这里,说明你还是一个合格的程序员,有着对完美的执着。与其手动的管理,不如让程序自己管 理。大家想想,如果是一个复杂的模型,比如一个人,它是有众多细小的模型构成的,比如脑袋,胳膊,腿等, 而脑袋又有鼻子,耳朵,嘴巴等构成。哈哈,这就是一个树形的结构了,看下结构特征:

  • 一个父节点有0个或多个子节点
  • 一个字节点最多有一个父节点

一个对象的父子关系如下:

现在游戏多采用树形模型管理,而且在 GUI 系统中也大放异彩。有了树形管理,我们可以轻易的将一种类型的鼻子安装到不同人的脑袋上,不用重复发明轮子了。

好了,现在我们的 onDrawFrame 中的形式是这样的了,右边的模型对象是一个封装好的单位,可能内部许多子节点。

3 层式屏幕管理

我们最终是要把模型绘制到屏幕上,我们思考下面问题:

  1. 屏幕上有众多模型需要渲染。比如一个人在草原中散步。概括讲人模型,还有草原,太阳,河流等等。
  2. 屏幕上的模型又可以归为不同的类别。如草原,太阳,河流这些是背景,我们控制的人是前景。

于是,层式管理来了,我们的渲染根结点称为场景 Scene, 分为不同的层 Layer, 在每一层上挂接着具体的模型。看下图就明白了,(注:来自cocos2d-python 文档)

为了向渲染 onDrawFrame 突出接口,Scene 和 Layer 也是一个渲染模型单位。

看看我们添加层式屏幕管理后的效果, 我们将所有要绘制的东西添加到一个场景中,就直接对这个场景节点 glVisit() 就可以了:

每个模型突出一个 glVisit(),这个函数的主要功能是调用自身绘制函数 draw() 然后对各个字节点逐个调用 glVisit().

4 游戏引擎

一个游戏引擎的设计遵循的原则是: 逻辑要和渲染分离,尽量将opengl 最小程度封装在底层,上层使用尽量不要触及底层api,尽量让核心代码原理Android系统的api。组件最小集合应该包含下面几种:

  • 图形引擎,我们上述讨论的就是
  • 事件分派系统,手机应用是基于触摸事件的,所以独立出来(事实上,也是一个调度器)
  • 时间调度器,游戏除了触摸时间还有自身的时间事件,如动画

其他的可能用到的组件有碰撞检测系统,输入系统,寻路算法等等。

游戏引擎的丰富会在以后的教程中逐步增设,今天这一节算是个开头,弄了个简单的图形引擎,也会在接下来随着需求的需要丰富其功能和接口。为了便于从 Android 相关代码中解脱出来,添加一个 GameSystem 单件类:

public class GameSystem {
private static GameSystem instance_ = new GameSystem();
public static GameSystem getInstance()  { return instance_;   }
// 场景
private GlObject runningScene_= null;
private int width = 0; // opengl的场景尺寸
private int height = 0;
public void setWindowSize(int width, int height)
{
this.width = width;
this.height = height;
}
public int getWindowWidth() { return this.width;  }
public int getWindowHeight()    { return this.height; }
// 设定场景
public void setScene(GlObject scene){       runningScene_ = scene;  }
//
public void glVisit(GL10 gl)    {
if (runningScene_ != null)
runningScene_.glVisit(gl);
}
}

我们将其插入到 android 代码的三个地方:

  1. Activity 的 onCreate 方法中,设定WindowSize: setWindowSize. 设定初始场景 setScene
  2. Renderer 的 onDrawFrame 方法中,来访问GameSystem 的游戏场景 glVisit

5 代码实现

在屏幕中除了上面的接口以外,增加的是坐标点,存储的是相对坐标,相对于父节点而言,用于描述模型的位置。这个坐标点不要理解为顶点数组中的顶点坐标。 可以这样理解,你将画笔移动到坐标点处,然后在此处依据顶点数组来绘制。代码较长,省略了一些,可以下载源码。

public class GlObject {
protected GlObject parent = null; // 父节点
protected LinkedList<GlObject> children = new LinkedList<GlObject>();// 字节点
private boolean visible = true; // 可访问(对 gl)
float x = 0;
float y = 0;
// 父子链管理
public void addChild(GlObject obj)  {
children.add(obj);
obj.parent = this;
}
public void removeChild(GlObject obj)   {
obj.parent = null;
children.remove(obj);
}
public void setParent(GlObject p)   {
if (parent != null) parent.removeChild(this);
p.addChild(p);
}
public GlObject getParent() { return parent;  }
// 坐标
float getX()    { return x;   }
float getY()    { return y;   }
void setXY(float x, float y)    {
this.x = x;
this.y = y;
}
// visible
public void setVisible(boolean v)   {       visible = true; }
public boolean getVisible() { return visible; }
// 外部gl访问接口
public void glVisit(GL10 gl)    {
if (!visible) return;
gl.glPushMatrix();
gl.glTranslatef(x, y, 0);
this.draw(gl);
for (GlObject child : children)
child.glVisit(gl);
gl.glPopMatrix();
}
// 绘制自身:子类重写此方法
public void draw(GL10 gl)   {}
////////////////////////////////////////////////////////////////////////////////////////
////  一些常用的图元绘制
// 绘制正方形
public static void drawQuater(GL10 gl, float left, float top, float right,float bottom) {
// 略
}
// 绘制三角形
public static void drawTriangle(GL10 gl, float oneX, float oneY,float twoX, float twoY, float threeX, float threeY) {
// 略
}
// 绘制扇形
public static void drawArc(GL10 gl, float length, float startAngle,float sweepAngle)    {
// 略
}
// 绘制直线
public static void drawLine(GL10 gl, float oneX, float oneY, float twoX,float twoY) {
// 略
}
}

6 绘制一个 android 机器人

代码还是以前的,绘制图元,只不过经过本章的洗礼,代码封装性和扩展性上有了进步。一个机器人有下面的结构组成:

  • 身体
    • 眼睛 * 2
    • 天线
  • 腿 * 2
  • 胳膊 * 2
  1. 设定 GameSystem 的初始游戏场景:
public class GlGame extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
// 。。。。略
// 初始化游戏系统:
// ... 屏幕大小
{
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
GameSystem.getInstance().setWindowSize(dm.widthPixels, dm.heightPixels);
}
// ...设定初始场景
GameSystem.getInstance().setScene(new AndroidScene());
//..... setContentView 代码
}
}

2. 添加一个场景类 AndroidScene 作为我们的画布,我们将会在其上绘制机器人

public class AndroidScene extends GlObject{
AndroidRobot robot = new AndroidRobot();
public AndroidScene(){
super();
// 在屏幕中心绘制
robot.setXY(GameSystem.getInstance().getWindowWidth()/2, GameSystem.getInstance().getWindowHeight()/2);
addChild(robot);
}
}

3. 添加一个机器人渲染模型 AndroidRobot, 代码太长, 折叠之:

好了,本次就唠叨到这里,学习愉快。