存档

作者存档

iOS 预定义声音参考表

2012年10月19日 没有评论

在上一个应用 MMHot 中,我们讲解了如何显示图片,后来我打算再添加一个功能,就是长按屏幕可以保存图片,保存图片后播放一个声音通知用户。声音的播放使用了 AudioServices。

AudioServices 是 Audio Toolbox 下的一个播放小于 30秒 声音的功能集合。从 ios 2.0 开始,在系统中欲定义了一些系统声音,它们从 1000 到 2000。内置的声音文件存放的地址为 /System/Library/Audio/UIsounds/ 。

Sound ID File name (iPhone) File name (iPod Touch) Category Note
1011 SMSReceived_Vibrate
1102 FailedUnlock
1311 SMSReceived_Vibrate
1350 RingerVibeChanged
1351 SilentVibeChanged
4095 Vibrate There was no category for this sound before 2.2. In the SDK this is the constant kSystemSoundID_Vibrate.
1005 alarm.caf sq_alarm.caf CalendarAlert
1304 alarm.caf sq_alarm.caf SystemSoundPreview
1020 Anticipate.caf Anticipate.caf SMSReceived_Alert Available since 4.2
1320 Anticipate.caf Anticipate.caf SMSReceived_Selection Available since 4.2
1106 beep-beep.caf sq_beep-beep.caf ConnectedToPower
1113 begin_record.caf begin_record.caf BeginRecording Available since 3.0
1117 begin_video_record.caf begin_video_record.caf BeginVideoRecording Available since 3.0
1021 Bloom.caf Bloom.caf SMSReceived_Alert Available since 4.2
1321 Bloom.caf Bloom.caf SMSReceived_Selection Available since 4.2
1022 Calypso.caf Calypso.caf SMSReceived_Alert Available since 4.2
1322 Calypso.caf Calypso.caf SMSReceived_Selection Available since 4.2
1023 Choo_Choo.caf Choo_Choo.caf SMSReceived_Alert Available since 4.2
1323 Choo_Choo.caf Choo_Choo.caf SMSReceived_Selection Available since 4.2
1070 ct-busy.caf ct-busy.caf AudioToneBusy There was no category for this sound before 4.0.
1074 ct-call-waiting.caf ct-call-waiting.caf AudioToneCallWaiting There was no category for this sound before 4.0.
1153 ct-call-waiting.caf ct-call-waiting.caf VCCallWaiting Available since 4.1
1071 ct-congestion.caf ct-congestion.caf AudioToneCongestion There was no category for this sound before 4.0.
1073 ct-error.caf ct-error.caf AudioToneError There was no category for this sound before 4.0.
1075 ct-keytone2.caf ct-keytone2.caf AudioToneKey2 There was no category for this sound before 4.0.
1072 ct-path-ack.caf ct-path-ack.caf AudioTonePathAcknowledge There was no category for this sound before 4.0.
1024 Descent.caf Descent.caf SMSReceived_Alert Available since 4.2
1324 Descent.caf Descent.caf SMSReceived_Selection Available since 4.2
1200 dtmf-0.caf dtmf-0.caf TouchTone
1201 dtmf-1.caf dtmf-1.caf TouchTone
1202 dtmf-2.caf dtmf-2.caf TouchTone
1203 dtmf-3.caf dtmf-3.caf TouchTone
1204 dtmf-4.caf dtmf-4.caf TouchTone
1205 dtmf-5.caf dtmf-5.caf TouchTone
1206 dtmf-6.caf dtmf-6.caf TouchTone
1207 dtmf-7.caf dtmf-7.caf TouchTone
1208 dtmf-8.caf dtmf-8.caf TouchTone
1209 dtmf-9.caf dtmf-9.caf TouchTone
1211 dtmf-pound.caf dtmf-pound.caf TouchTone
1210 dtmf-star.caf dtmf-star.caf TouchTone
1114 end_record.caf end_record.caf EndRecording Available since 3.0
1118 end_video_record.caf end_video_record.caf EndVideoRecording Available since 3.0
1025 Fanfare.caf Fanfare.caf SMSReceived_Alert Available since 4.2
1325 Fanfare.caf Fanfare.caf SMSReceived_Selection Available since 4.2
1115 jbl_ambiguous.caf jbl_ambiguous.caf JBL_Ambiguous Available since 3.0
1110 jbl_begin.caf jbl_begin.caf JBL_Begin Available since 3.0
1112 jbl_cancel.caf jbl_cancel.caf JBL_Cancel Available since 3.0
1111 jbl_confirm.caf jbl_confirm.caf JBL_Confirm Available since 3.0
1116 jbl_no_match.caf jbl_no_match.caf JBL_NoMatch Available since 3.0
1026 Ladder.caf Ladder.caf SMSReceived_Alert Available since 4.2
1326 Ladder.caf Ladder.caf SMSReceived_Selection Available since 4.2
1100 lock.caf sq_lock.caf ScreenLocked
1305 lock.caf sq_lock.caf SystemSoundPreview
1254 long_low_short_high.caf long_low_short_high.caf Headset_StartCall
1006 low_power.caf low_power.caf LowPower
1001 mail-sent.caf mail-sent.caf MailSent
1303 mail-sent.caf mail-sent.caf SystemSoundPreview
1259 middle_9_short_double_low.caf middle_9_short_double_low.caf Headset_TransitionEnd
1027 Minuet.caf Minuet.caf SMSReceived_Alert Available since 4.2
1327 Minuet.caf Minuet.caf SMSReceived_Selection Available since 4.2
1000 new-mail.caf new-mail.caf MailReceived
1302 new-mail.caf new-mail.caf SystemSoundPreview
1028 News_Flash.caf News_Flash.caf SMSReceived_Alert Available since 4.2
1328 News_Flash.caf News_Flash.caf SMSReceived_Selection Available since 4.2
1029 Noir.caf Noir.caf SMSReceived_Alert Available since 4.2
1329 Noir.caf Noir.caf SMSReceived_Selection Available since 4.2
1108 photoShutter.caf photoShutter.caf CameraShutter
1003 ReceivedMessage.caf ReceivedMessage.caf SMSReceived
1301 ReceivedMessage.caf ReceivedMessage.caf SystemSoundPreview
1107 RingerChanged.caf RingerChanged.caf RingerSwitchIndication
1004 SentMessage.caf SentMessage.caf SMSSent
1109 shake.caf shake.caf ShakeToShuffle Available since 3.0
1030 Sherwood_Forest.caf Sherwood_Forest.caf SMSReceived_Alert Available since 4.2
1330 Sherwood_Forest.caf Sherwood_Forest.caf SMSReceived_Selection Available since 4.2
1255 short_double_high.caf short_double_high.caf Headset_Redial
1257 short_double_low.caf short_double_low.caf Headset_EndCall
1258 short_double_low.caf short_double_low.caf Headset_CallWaitingActions
1256 short_low_high.caf short_low_high.caf Headset_AnswerCall
1051 SIMToolkitCallDropped.caf SIMToolkitCallDropped.caf SIMToolkitTone
1052 SIMToolkitGeneralBeep.caf SIMToolkitGeneralBeep.caf SIMToolkitTone
1053 SIMToolkitNegativeACK.caf SIMToolkitNegativeACK.caf SIMToolkitTone
1054 SIMToolkitPositiveACK.caf SIMToolkitPositiveACK.caf SIMToolkitTone
1055 SIMToolkitSMS.caf SIMToolkitSMS.caf SIMToolkitTone
1007 sms-received1.caf sms-received1.caf SMSReceived_Alert
1012 sms-received1.caf sms-received1.caf SMSReceived_Alert
1307 sms-received1.caf sms-received1.caf SMSReceived_Selection
1312 sms-received1.caf sms-received1.caf SMSReceived_Selection
1008 sms-received2.caf sms-received2.caf SMSReceived_Alert
1308 sms-received2.caf sms-received2.caf SMSReceived_Selection
1009 sms-received3.caf sms-received3.caf SMSReceived_Alert
1309 sms-received3.caf sms-received3.caf SMSReceived_Selection
1010 sms-received4.caf sms-received4.caf SMSReceived_Alert
1310 sms-received4.caf sms-received4.caf SMSReceived_Selection
1013 sms-received5.caf sms-received5.caf SMSReceived_Alert
1313 sms-received5.caf sms-received5.caf SMSReceived_Selection
1014 sms-received6.caf sms-received6.caf SMSReceived_Alert
1314 sms-received6.caf sms-received6.caf SMSReceived_Selection
1031 Spell.caf Spell.caf SMSReceived_Alert Available since 4.2
1331 Spell.caf Spell.caf SMSReceived_Selection Available since 4.2
1032 Suspense.caf Suspense.caf SMSReceived_Alert Available since 4.2
1332 Suspense.caf Suspense.caf SMSReceived_Selection Available since 4.2
1033 Telegraph.caf Telegraph.caf SMSReceived_Alert Available since 4.2
1333 Telegraph.caf Telegraph.caf SMSReceived_Selection Available since 4.2
1057 Tink.caf Tink.caf PINKeyPressed
1103 Tink.caf sq_tock.caf KeyPressed
1034 Tiptoes.caf Tiptoes.caf SMSReceived_Alert Available since 4.2
1334 Tiptoes.caf Tiptoes.caf SMSReceived_Selection Available since 4.2
1104 Tock.caf sq_tock.caf KeyPressed
1105 Tock.caf sq_tock.caf KeyPressed
1306 Tock.caf sq_tock.caf KeyPressClickPreview The category was SystemSoundPreview before 3.2.
1016 tweet_sent.caf tweet_sent.caf SMSSent Available since 5.0
1035 Typewriters.caf Typewriters.caf SMSReceived_Alert Available since 4.2
1335 Typewriters.caf Typewriters.caf SMSReceived_Selection Available since 4.2
1101 unlock.caf sq_lock.caf ScreenUnlocked
1036 Update.caf Update.caf SMSReceived_Alert Available since 4.2
1336 Update.caf Update.caf SMSReceived_Selection Available since 4.2
1050 ussd.caf ussd.caf USSDAlert
1152 vc~ended.caf vc~ended.caf VCEnded Available since 4.0
1150 vc~invitation-accepted.caf vc~invitation-accepted.caf VCInvitationAccepted Available since 4.0
1151 vc~ringing.caf vc~ringing.caf VCRinging Available since 4.0
1154 vc~ringing.caf vc~ringing.caf VCCallUpgrade Available since 4.1
1002 Voicemail.caf Voicemail.caf VoicemailReceived
1015 Voicemail.caf Voicemail.caf Available since 2.1
1300 Voicemail.caf Voicemail.caf SystemSoundPreview
1315 Voicemail.caf Voicemail.caf SystemSoundPreview Available since 2.1

使用的时候,添加引用 #import <AudioToolbox/AudioToolbox.h>

SystemSound sound=1109;
AudioServicesPlaySystemSound(sound);

播放是以当前系统的音量来进行后台播放,比较适合我在这个应用中的需要。

分类: iOS, 转载 标签: , ,

MMHot 代码编写过程及心得

2012年10月17日 没有评论

把先前买的那本 ios 变成的书给撕了,每天在地铁上看一点点,又大致看了几个别人的代码,打算自己写一个应用出来练习下,经过一个星期的琢磨,应用 MMHot 代码部分终于完工了。本来打算花 $99 去买一个开发者帐号的,但是昨天晚上看了下水果的应用商店规范,发现 MMHot 应该不会被审核通过的,于是放弃了。$99 对我来说真心贵,不过这个不妨碍今天和大家一起分享这个应用编写的心得。

简单地说,MMHot 是一个浏览美女图片的 ios 应用。

项目使用了 2 个开源的库:EGOImage 和 ASIHttp,所以我觉得这个作为入口比较适合新手来初步了解和学习 objective-c ,既可以完成任务,又在学习的初期降低了门槛。ASIHttp  封装了网络应用中的大部分功能,可以满足常见的 get/post 例如文件下载、上传。EGOImageView 继承了 UIImageView,支持图片的异步下载。

作业的目标:1、大致了解 EGOImage 和 ASIHttp 的简单使用方法。2、代码添加视图。3、学习使用调试,了解 IDE 的功能。

应用是基于 Xcode 4.5.1 和 iOS 6 。新建项目时,我没有选择 Core Data 和 Automatic Reference Counting 。因为我看的代码都是基于用户自己手动管理内存的方式,ARC 跳跃太大,对我不合适。另外的原因是开源的库当前貌似还不支持ARC。

新建项目后,会自动包含 appDelegate 文件。这块需要注意的是 -(void)application:(UIApplication *) application didFinishLaunchingWithOptions:(NSDictionary *) launchOptions 方法。这个方法里用来设置需要第一个显示的视图。我们在很多应用中都看到当应用第一次运行的时候,会给出引导界面让用户了解大致的流程,第二次运行时就不显示引导界面了,为了实现这样的效果,也可以在这个方法里去实现。

在该方法里,包含下面的语句:

self.window=[[[UIWindow alloc] initWithFram:[[UIScreen mainScreen] bounds]] autorelease];
self.viewController=[[[MainViewController alloc] initWithNibName:@”MainViewController” bundle:nil] autorelease];
self.window.rootViewController=self.viewController;
[self.window makeKeyAndVisible];
return YES;
第一行代码是设置界面的window,由 IDE 自动生成,第二行代码是设置程序显示的第一个界面 MainViewController.xib ,第三回是设置窗体的根视图,对于 ios6 系统,要求每个窗体都必须有根视图。由旧系统转换的时候,如果没有添加的话,IDE 也会给出一个警告。第四、五也是自动生成的,很明了。

接下来,我们转到 MainViewController.h 文件。由于我们使用了前面说的2个开源库,所以需要引用进来。另外,由于应用中使用了手势和图片回调,所以还需要添加对应的 delegate:EGOImageViewDelegate 、UIGestureRecognizerDelegate 。该类有 3个变量和一个属性。

EGOImageView *imageView;
ASIHttpRequest *req;
NSMutableArray *list

@property (nonatomic,retain) EGOImageView *imageView;

然后就是具体的实现了。我们在 viewDidLoad 添加初始化代码,图片浏览嘛,当然要把顶部的任务栏给隐藏掉,所以我首先来隐藏任务栏:[[UIApplication sharedApplication] setStatusBarHidden:YES];

UIImage *image=[UIImage imageNamed:@”1.jpg”];
imageView=[[EGOImageView alloc]initWithImage:image];
[imageView setFrame:CGRectMake(0,0,[UIScreen mainScreen].bounds.size.width,[UIScreen mainScreen].bounds.size.height)];
imageView.delegate=self;
[self.view.assSubview:imageView];

//添加手势识别
UISwipGestureRecognizer *swipLeft=[[UISwipGestureRecognizer alloc] initWithtarget:self action:@selector(handleSwipGesture:)];
swipLeft.direction=UISwipGuestureRecognizerDirectionLeft;
[self.view addGuestureRecognizer:swipLeft]; //为了防止图片旋转后,手势也跟随变化,所以把手势添加到根视图中,而非 imageView
[swipLeft release];

//发送请求
req=[ASIHttpRequest requestWithURL:[NSURL URLWithString:@”http://www.withonly.com”]];
[req setDelegate:self];
[req setDidFinishSelector:@selector(ASIHttpRequestFinished:)];
[req setDidFailSelector:@selector(ASIHtppRequestFailed:)];
[req startAsynchronous];

视图在显示的时候,首先显示一个本地图片文件 1.jpg ,这样的话可以避免网络延迟带来的视觉等待,然后将视图添加到窗体视图中。手势识别没有什么好说的,都一样。最后是发送请求,请求成功时执行ASIHttpRequestFinished,失败时执行ASIHtppRequestFailed。需要提醒大家的是第 4 行,我3天晚上没有睡好觉就是因为少了这一行代码。

-(void) ASIHttpRequestFinished:(ASIHttpRequest *) request{
NSString *info=[request responseString];
NSMutableString *str=[[NSMutalbeString stringWithString:info];
NSError *error;
NSRegularExpression *regex=[NSRegularExpression regularExpressionWithPattern:@”img src=\”(.*?)\”” options:NSRegularExpressionCaseInsensitive| NSRegularExpressionDotMatchesLineSeparators error:&error];
NSArray *matches=[regex matchesInString:str options:NSMatchingCompleted range:NSMakeRange(0,[str length])];
if([matches count]>0){
[list removeAllObjects];
}

for(NSTextCheckingResult *match in matches){
NSRange range=[match rangeAtIndex:1];
[list addObject:[str substringWithRange:range]];
}
if([list count]>0){
[imageView setImageURL:[NSURL URLWithString:[list objectAtIndex:0]]];
[self ResizeImage]; //图片缩放
}

}

当请求成功后,通过正则提取返回结果里的图片 url 地址,并且保存在 list 变量里。最开始的时候是打算使用xml 来解析的。可是网上搜索了下2种关于xml解析的思路,和 java 是一个味道,擦的,难道没有net 风格的么。于是换做正则来提取。解析完了后,如果 list 里有记录,则显示第一条记录里放的图片。其它的方法都差不多了,没有啥好说的。

在文章的最后,我说一说那个让我好几天没有睡好觉的问题。因为在加载图片后,还需要对图片进行缩放。但是由于图片的下载过程是一个异步的操作,最开始的缩放代码里总是会崩溃,因为那时图片都没有下载回来。我很期待有一个类似图片加载完的回调方法。

后来,查看了EGOImageView 的源文件,发现里面有 imageViewLoadedImage 方法,然后添加到文件里,发现没有效果,后来又发现了imageButtonLoadedImage ,添加进去还是没有效果。很崩溃,于是在网上看到有用 NSNotification  来解决的。赶紧添加进去,还是不行。弄了几个晚上都没有有效的方法。

最后才发现,其实 EGOImageView 已经内部实现了 NSNotification 的相关方法了,只需要在代码里添加 imageView.delegate=self ,然后在 imageViewLoadedImage 实现回调例如图片的缩放就可以了。

分类: iOS, 日常 标签: , , , ,

loaded the “ViewControl” nib but the view outlet was not set 错误的解决办法

2012年10月10日 没有评论

糗事的 ios 项目最近一直都无法编译运行,因为每次 command+R 的时候都出现了 loaded the “ViewControl” nib but the view outlet was not set  这个错误提示。本来英语就不咋滴,再加上对 xcode 和 objective-c 不熟悉,简直弄昏了头。

后来发现了解决方法,很简单,基本功的问题。

1、先点击 File’s Owner ,然后选择右边的 Identity inspector 选项卡,Custom Class 窗口,Class 文本框里输入 xib 文件的文件名,这里是 ViewControl ,回车。

2、在 File’s Owner 里添加一个 Outlet 到 view 控件。具体方法见上一篇文章

3、重新编译,就可以运行了。

 

原因分析:由于当初新建项目时默认的 View 控件被我给删除了,后来我又添加的一个 view 控件。和新建项目默认的view不一样的地方在于,File’s Owner 的 Class 默认为 NSObject ,所以需要手工修改和当前的nib文件关联。

感觉在学习多视图处理的时候如果不注意应该也会碰到这个问题吧。

分类: iOS, 日常 标签: , ,

Xcode 中插座变量和动作释疑

2012年10月10日 没有评论

几乎在一年前,我的博客里《iOS版本的hello world》是发表的第一篇关于 ios 开发的文章,那只是一个很简单的示例,之后我就在没有再写了。一来是因为我很懒,另外一个很重要的原因就是我被一个问题弄迷惑了。

一年前,我从网上下了几个电子书,晚上躲在被窝里慢慢看。你知道的,现在我几乎很少买书的,这方面的书都太贵了,到后来才买的一本书。正是这书里的内容让我迷惑了很久很久。在  cocoaChina 上看了下,感觉有点高级不太针对入门的人,朋友中也没有人可以问,所以一直在困惑。

我们来举一个例子来说明下,在视图中有一个文本框和一个按钮,点击按钮显示文本框里的内容。要如何实现呢?

1、在 h 文件里添加一个属性,代码为 @property (nonatomic,retain) IBOutlet UITextView *txtInfo;

2、在 h 文件里添加一个动作 -(IBAction) btnClick:(id) sender;

3、在m文件里写实现代码 @synthesize txtInfo;  -(IBAction)btnClick:(id)sender{//这里是具体的点击实现按钮}

在这个时候来运行程序的话,应该是得不到预期的效果,为什么呢?因为还没有把控件和代码变量绑定起来。

接下来是第4步,4、切换到 xib 文件,拖动 File’s Owner 到文本框上去;然后拖动按钮到 File’s Owner 上去。需要注意的是,他们的拖动方向相反,前后并不一致。此时编译运行程序,应该就可以得到预期效果了。

其实第4步操作就是标题所述的绑定插座变量和动作。这个时候,我的疑问就来了。为什么要拖动方向相反呢,我要如何记住拖动的方向呢?

我就一直在纠结,为什么 xcode 不能像 vs 那样友好一些,拖下控件就可以写代码多好呀。

只到上个周末,我突然就明白了,那本书坑爹呀。

第4步是可以用一个方向来完成的,在 File’s Owner 上面点击右键,会弹出菜单。将里面的 + 号拉到控件上去一样第可以实现目的。插座变量,动作都可以用相同的顺序来。其实在 .net 里,是vs帮我们完成了这个绑定的操作。例如:

protected Button btn;  btn.Click+=new btn_Click;  protected void btn_Click(object sender, EventArgs e){}

分类: iOS, 日常 标签: , , ,

vs 2012 中js的intellisense智能提示

2012年9月17日 没有评论

在前面的博客里提及 Visual Studio 2012 RTM 已经出来有一段时间了,在 vs 以前的版本里,对于用户的智能提示做的还不够好,在 2012 的版本里大有改善,今天我们要分享的是如何在  vs 2012 里使用用户 js 的 intellisense 智能提示。

使用起来还是很简单的,比如说项目中有个 common.js 文件,这个时候只需要添加一个名为  common.intellisense.js 的文件就可以了。IDE 可以自动发现,在开始的时候我还不清楚,专门在页面里引用了下,结果运行时总报告错误,后来才发现这个技巧。

场景:在common.js 文件里有一个 load 方法,有2个参数 ,格式如下:

function load(url,charset){}

要实现 intellisense 智能提示,我们只需要在 common.intellisense.js 文件里添加下面的方法即可:

intellisense.annotate(window,{     “load”:function(){
/// <signature>
///   <summary>加载 js 文件</summary>
///   <param name=”url” type=”String”>js 文件的路径</param>
///   <param name=”charset” type=”String”>js 文件的字符编码,例如 utf-8</param>
///   <returns type=”Object” />
/// </signature> }, });

简单地说,我们只需要完善 intellisense.annotate 方法即可,该方法接受 2 个参数,第一个参数为想要进行智能提示的对象,示例中使用的是 window 对象,也可以是其它的对象;第二个参数是一个 json 对象,传递的是智能提示的参数列表。

智能提示以 signature 包含,常见的有 3个,summary 描述的是该方法的功能;param 是具体每一个参数的描述,还可以包括类型;return 是返回类型的描述。从事 C#/asp.net 、Java 的同学看着是不是觉得很熟悉呀~

此时,我们在页面中输入 load 时,就会出现描述的内容,输入参数时,就会提示参数相关的信息,感觉太酷了。

如果我们在文件头添加 reference 引用,就可以脱离上文中 js 代码必须和智能提示文件文件名对应的限制了,例如 /// <reference path=”Scripts/jquery-1.7.1-intellisense.js”/> 。如果你愿意,可以同时引入多个 reference 文件,需要提醒各位的是这里的斜杠可是 3 个哟,不要输入错了。

看起来很简单,对不对。如果有什么问题,快给我留言吧。

在Webform (asp.net)中使用Route 路由之中级实现

2012年9月7日 没有评论

相信经过前面2节文字的介绍,同学们可以快速地实现route路由的目的,并运用在实际的项目中了。在这一节里,我们在讲述一下路由更进一步的实现。

在前面的例子里,我们是把所有的路由信息给放在 Globla.asax.cs 文件里了,这样就产生了一个问题:由于实际业务的变化,每次都需要在该文件里做调整,然后重新编译部署。是不是觉得很麻烦,有没有一种更好的方式,不需要编译是最好啦。

很自然,有经验的同学会想到把路由表放在 web.config 配置文件里,这样的话每次在调整的时候只需要修改 web.config 文件就可以了。我也查询了下网上的资料,由于路由表是一个键值队列,需要在 web.config 里添加自定义节点,并且还需要编写这个自定义节点的实现类。我感觉实现思路有些麻烦,所以下面的一种方式就出来了。

我们把路由表信息放在 xml 文件里而不是 web.config 文件里,即使 web.config 事实上也是个xml。这样做的好处,一来不需要编写自定义节点的实现类;二是把路由表单独抽离出来,避免由于路由表的修改而带来误操作影响全局。

我们新建一个PageRoutes文件,继承 RouteBase 类,并实现其方法。主要有2个方法 GetRouteData 和 GetVirtualPath 。这2个方法是什么意思呢,简单地举例说,如果想从 /u/wave 得到 /user.aspx ,调用的是 GetRouteData 方法,如果是从 user.aspx 里得到 /u/wava , 调用的是 GetVirtualPath  方法。后者在 MVC 里用的非常多,在 webform 中,我这里详细描述 GetRouteData  方法,其它的原理是一样的。

我们来新建一个Route.xml文件用来保存路由信息。
<?xml version=”1.0″ encoding=”utf-8″ ?>
<Route>
<Page virtualPath=”/home” routePage=”~/default.aspx” />
<Page virtualPath=”/about” routePage=”~/about.aspx” />
<Page virtualPath=”/u/{userid}/{noteid}” routePage=”~/notedetail.aspx” />
<Page virtualPath=”/u/{userid}” routePage=”~/notelist.aspx” />
</Route>
接下来,我们把精力放在 GetRouteData 方法上,这个方法会拦截所有的请求,如果没有需要处理的,则返回 null 跳过进行后面的操作。下面的代码有点长,来慢慢地解说,

public IRouteHandler RouteHandler { get; set; }

public override RouteData GetRouteData (HttpContextBase httpContext)         {

string xmlPath = httpContext.Server.MapPath (“~”) + “Route.xml”;

if (!File.Exists (xmlPath)) { return null; } //如果配置文件不存在则直接返回

XmlDocument doc = new XmlDocument ( );

doc.Load (xmlPath);

XmlNodeList list = doc.GetElementsByTagName (“Page”);

string virtualPath = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(1).ToLower();

foreach (XmlNode node in list)          {

string n = node.Attributes[“virtualPath”].Value.ToLower();

//第一步,直接比对,优先级最高

if (n== virtualPath) {

var data = new RouteData();

data.RouteHandler = new PageRoute(node.Attributes[“routePage”].Value);

return data; }

//第二步,带 {userId}的参数比对

string v=n;

string o=new Regex(“{(\\w|\\W)+?}”).Replace(v,”(\\w|\\W)+”);

Regex reg = new Regex(o);

if (reg.IsMatch(virtualPath)){

var data = new RouteData();

data.RouteHandler = new PageRoute(node.Attributes[“routePage”].Value);

string[] a = n.Split(new char[] { ‘/’, ‘.’ });

string[] b = virtualPath.Split(new char[] { ‘/’, ‘.’ });

for (int i = 0, j = a.Length; i < j; i++) {

if (a[i].StartsWith(“{“))  {

string d = a[i].Replace(“{“, “”).Replace(“}”, “”);

data.Values[d] = b[i]; }}

return data; }}

return null; }

程序首先是检查xml文件是否存在,如果存在就加载并生成列表,使用当前的 url 在列表里遍历,如果找到了就返回信息。对于有参数的,则找到参数部分,看是否符合要求,符合的话先把参数填充进去,再返回信息。最后,如果都没有找到,则返回 null 跳过进行后面的。

现在,我们只需要在 Global 文件里添加 routes.Add(new PageRoutes()); 这一行就可以了。以后需要调整的时候直接修改 Route.xml 文件即可。至此,webform 中使用 Route 的文章基本上就写完了。

写在后面的话,其实这么写有一个潜在的性能问题,就是每次访问都需要加载 xml 文件,比较好的实现方式是把请求的路由信息放在缓存里,缓存依赖设置为文件类型的,这样的话每当xml有修改的话,缓存就自动失效重新加载 xml 。这个不是很难,就留给各位同学们去实现了。

而对于 GetVirtualPath 方法,我这里并没有去提及,一是对于传统的 webform 来说,用到的机会比较少;二是需要根据具体的项目来定义,这里以通用例子来讲解有误导嫌疑;三是给大家个锻炼的机会。

祝大家编码愉快。

分类: 日常 标签: , ,

在Webform (asp.net)中使用Route 路由之初级扩展

2012年9月7日 没有评论

在上一节,我们分享了如何实现基本的路由,可以满足很多的场景。

对于asp.net 稍微熟悉的同学一定不会对 Ashx 文件陌生,这是一个只具有代码逻辑的页面,通常用在验证码显示、文件下载等几乎没有用户界面的情况下。我就非常地喜欢使用这样的文件。

有的同学在对这样的文件进行路由的时候,会是这么来写代码,routes.MapPageRoute (“data”, “data”, “~/handler.ashx”); 编译一运行,我瓷熬,居然报错了。报错信息是什么呢?大致是这样的一条错误信息:类型“WebSite.Handler”不从“System.Web.UI.Page”继承。原因就在于常见的 aspx 和 ashx 虽然都实现了 IHttpHandler 接口,但是又不完全一样。

为了解决这个问题,其实这个问题也是我写这几篇文章最初的出发点,网上的代码基本上和上一节的差不多,并没有解决本节的问题。

我们在项目中新建一个类,取名 PageRoute,继承自 IRouteHandler 。在这个类里,我们只需要实现 IRouteHandler 接口就可以了。不多说,上代码。
#region IRouteHandler 成员

public string RoutePath { get; private set; }

public PageRoute (string routePath){RoutePath = routePath;}

public IHttpHandler GetHttpHandler (RequestContext requestContext)
{
if (!RoutePath.Contains (“.ashx”))
{
return BuildManager.CreateInstanceFromVirtualPath (RoutePath, typeof (Page)) as IHttpHandler;
}
else
{
return BuildManager.CreateInstanceFromVirtualPath (RoutePath, typeof (IHttpHandler)) as IHttpHandler;
}
}

#endregion

从代码里,可以清楚地看到,在 GetHttpHandler 方法里分别对 aspx 和 ashx 文件进行了处理,虽然返回的都是 IHttpHandler ,但是在转换的时候,设置的 typeof  是不一样的。

接下来,在 Global.asax.cs 里这么来写 routes.Add (“getdata”, new Route (“data”, new PageRoute (“~/handler.ashx”))); 各位同学们要记住这里的写法和上一节里的写法不一样喔。这样就可以实现对 ashx 文件的路由了,当然对于 aspx 文件,使用2种方式都可以的,例如 routes.Add (“user”, new Route (“u/{userid}”, new PageRoute (“~/userlist.aspx”))); 这样

是不是很神奇呀?

在这一节里,我们就完全解决了传统 webform 的路由实现问题,特别是不从“System.Web.UI.Page”继承这个问题。下一节我们来提一提再高级一点的用法。

分类: 日常 标签: , ,

在Webform (asp.net)中使用Route 路由之基本实现

2012年9月7日 没有评论

路由这个东西其实很早前就出现了,更多的是出现前其它的平台/语言中,对于 .Net 来说比较晚。那时很羡慕只需要在 apache 、ngix 中配置下就可以使用了。

我记得第一次近距离的使用是在门楼网里,那个时候屈屈把 Route 的这部分代码给剥离出来单独给我看过,使用了一个第三方组件,并且需要修改 IIS 的设置才能生效,缺点就是会接管所有的请求包括图片、样式等等。后来把代码消化后,用在了学校的新闻网里,没有想到5年多过去了这部分代码还在继续为师生们服务着。

再后来,微软推出了 MVC,到现在已经是第4个版本了。在 MVC 中,.Net 终于原生支持 Route了,但是在最开始还只是为 MVC 来服务的,网上也很多教程都是针对 MVC 系列的,我们这里就来讨论下如何在 webform 上来实现。

首先,需要在项目里添加 Global.asax 文件,在这个文件里要做的事情就是在应用启动的时候,添加路由注册信息到里面。

protected void Application_Start (object sender, EventArgs e) { RegisterRoutes (RouteTable.Routes);  }

然后在protected void RegisterRoutes (RouteCollection routes){routes.MapPageRoute (“default”, “home”, “~/default.aspx”);}里方法是这样的,什么意思,就是说你访问 /home 的话,路由会直接帮你转向到 default.aspx 页面去。

上面的方式可以满足最基本的需求,可是事实上很多情况下,url 地址里是有带有参数的,如何提交参数呢。可以这么来,routes.MapPageRoute (“notedetail”, “note/{userid}/{noteid}”, “~/note.aspx”); 从代码里可以发现,url 里附加了2个参数,分别为 userid 和 noteid ,它们用大括号给括起来了。看起来是不是有点像存储过程里的参数呢,哈哈。这个冷笑话一点都不好玩。

回到正题,再添加了上面的代码后,如果用户访问 /note/wave/1346 ,那么会被路由到 note.aspx 这个页面里去,在页面里接收参数可以这么来使用 string userId=Page.RouteData.Values[“userid”]; 就不再是传统的 QueryString 方法了。

至此,我们就实现了在 webform 中使用 Route 的基本功能呢了。下一节,我们来进行扩展。

分类: 日常 标签: , ,

小事故,丢人啊。

2012年8月20日 没有评论

昨天不小心出了点事故,骑自行车加速时把 olay 给弄掉下去了。

怎么说呢,我从学骑自行车开始,一次是小时候从墙壁险擦过去,一次是2、3年前某个雨夜摔了一下。应该算是幸运的,可是昨天把人家给弄得掉下去了。分析来看,应该是在加速的时候,车子摇摆,重心不稳,人家没有坐好结果就掉下去了,但是掉了一半似乎又被什么给挂住了,在地上给拖了一下。

当机立断,立马把车子给扔了,小腿被踏板给撞了下,一瘸一瘸地跑过去。左边胳膊和腿都擦伤了,雨伞也坏了,衣服倒还没有擦破。

回家后擦酒精,上碘酒。

真丢人啊,路面平坦的很。自己骑车给弄成这样。该怎么赔偿就怎么赔偿吧,诶哟喂。

分类: 日常 标签: ,

Windows 8 RTM 使用初印象

2012年8月2日 没有评论

window 8 已经RTM ,并在8月1日前发布给各OEM厂商了。从刚开始的时候,几乎每个版本都有在安装使用,这次通过内部服务器下载回来了,同时也拿到了一个新的还未上市的笔记本,因为是裸机,使用 u盘安装。

我觉得奇怪的是,无论我买多少 u盘,最后都会莫名其妙的不见了。

这次只好又重新买了一个 16G 的,等了几天今天下午的时候终于到了,网上找了个软件,做了个u盘启动盘,装了个win8英文版的系统。

安装过程、界面和以前的一样的,没有什么大的变化。感觉安装时间比以前的要长。进入系统后,查看版本号为9200。

skydriver 的图标,和以前传闻的一样,丝带给取消了,只剩下2朵白云,store 商店也可以正常访问,map 定位还不错。进入系统后,系统可以自动记住我先前设置的桌面背景、浏览器默认主页、用户图像,这些很个性化,赞一个。

过了不久,我邮件和手机短信都收到微软信息要求确认新机器,安全性有很大的提升。

其实,我更关注的是 VS 2012 ,可惜现在还没有 RTM 。

分类: 一句话 标签: , ,