[转载]用Eclipse开发和调试Android应用程序(一)

mikel阅读(885)

[转载]用Eclipse开发和调试Android应用程序(一) – Android – mobile – JavaEye论坛.

前面介绍了Windows环境下,基于Android SDK(2.3) 和 Eclipse(helios)的Android开发环境的搭建,并创建了第一个应用程序Hello Android World。具体挺参考小生的blog:http://blog.sina.com.cn/deaboway 或者http://blog.csdn.net/deaboway 。

现在,我们已经可以使用Eclipse来创建和开发Android应用程序,本文将仍以Hello Android World工程来深入解析Eclipse中Android工程的结构以及调试。

写上篇的时候,刚好Android SDK Platform Honeycomb Preview, revision 1(android-3.0_pre_r01-linux.zip)已经加入http://dl-ssl.google.com/android /repository/repository.xml,却无法下载,因此我们的第一个Android应用程序是用的Android SDK Platform 2.3.1,即Android 9 AVD进行演示。现在Android SDK Platform Honeycomb Preview已经放到http://dl-ssl.google.com/android/repository/android- 3.0_pre_r01-linux.zip,敢为天下先是我等求知若渴的程序员的优秀品质,因此,本次我们使用最新版本的Android SDK Platform Honeycomb Preview来进行我们本次教程。

先看看最新的Honeycomb Preview的样子吧(由于是Preview版本,启动确实不敢恭维,根据传闻,前几天之所以该版本一度无法下载安装是因为google发现这个Preview版本太烂,面子上挂不住,所以又撤掉了,呵呵):

相比手机上目前使用的最高Android 2.3版本而言,Android 3.0 Honeycomb更适合平板电脑使用,是专门为Android平板电脑进行优化的系统版本。随着SDK的发布,更加有利于开发者和厂商针对 Android 3.0 Honeycomb平板电脑进行开发,包括Android平板电脑应用和匹配。

一、 Android 应用程序概述

1. Android 的嫡系组件

Android有四项一等公民(或称为嫡系组件),包括:Activity(活动)、ContentProvider(内容提供程序)、 BroadcastReceiver(广播接收器)与Service(服务)。它们都必须宣告于AndroidManifest.xml档案里。

Activity 活动

活动是最常用的 Android 应用程序形式。活动在一个称为视图(后文将介绍)的类的帮助下,为应用程序提供 UI。视图类实现各种 UI 元素,比如文本框、标签、按钮和计算平台上常见的其他 UI 元素。

一个应用程序可以包含一个或多个活动。这些活动通常与应用程序中的屏幕形成一对一关系。

应用程序通过调用 startActivity() 或 startSubActivity() 方法从一个活动转移到另一个活动。如果应用程序只需“切换”到新的活动,就应该使用前一个方法。如果需要异步的调用/响应模式,就使用后一个方法。在这两 种情况下,都需要通过方法的参数传递一个 intent。

由操作系统负责决定哪个活动最适合满足指定的 intent(后文将介绍)。

对于Activity,关键是其生命周期的把握(后文将介绍),其次就是状态的保存和恢复(onSaveInstanceState onRestoreInstanceState),以及Activity之间的跳转和数据传输(intent)。

Activity几乎承接着用户对应用程序(Application)的所有操作,Activity应该有一个窗口(Window),这个窗口是 可以通过不用的主题(Theme)改变样子的。Activity应该要注意它的生命周期(Lifecycle)、设备状态(Configuration) 改变时的影响以及运行状态和数据的保存,这个在一个应用程序是否可靠和人性化上至关重要。Activity里还应该要申明一些许可 (Permissions),以便使用Android的一些软硬件功能,这些申明可以由代码或者Manifest.xml给出。最后,每个 Activity(的入口)一定要在Manifest当中申明。

Service 服务

与其他多任务计算环境一样,“在后台”运行着一些应用程序,它们执行各种任务。Android 把这种应用程序称为“Service服务”。

Service是没有界面的程序,它是所谓的服务,也叫后台程序。应该要非常注意Service的启动(startService)和绑定 (bindService)这两种开启Service的方法之间的关系以及Service对应的生命周期,两种开户Service的方法对Service 的生命周期效果是不同的。还有就是申明许可以及申明Service,也是在代码内或者Manifest内申明。

BroadcastReceiver 广播接收器

广播接收器是一个应用程序组件,它接收请求并处理 intent。与服务一样,接收器在一般情况下也没有 UI 元素。广播接收器通常在 AndroidManifest.xml 文件中注册。广播接收器的类属性是负责实现这个接收器的 Java 类。

广播接收并不是通常所说的无线电广播,而是指由sendBroadcast()所发送出来的意图(Intent),即广播在这里的意思是意 图,BroadcastReceiver在注册(Registe)之后可以自动监听符合预先给定的条件的意图,如果有则会通知此 BroadcastReceiver的持有程序。

ContentProvider 内容提供程序 ——数据管理

内容提供程序是 Android 的数据存储抽象机制。我们以移动设备上常见的一种数据为例:地址簿或联系人数据库。地址簿包含所有联系人及其电话号码,用户在使用手机时可能需要使用这些 数据。内容提供程序对数据存储的访问方法进行抽象。内容提供程序在许多方面起到数据库服务器的作用。对数据存储中数据的读写操作应该通过适当的内容提供程 序传递,而不是直接访问文件或数据库。可能还有内容提供程序 的 “客户机” 和 “实现”。

ContentProvider是作保存应用程序数据和建立维持数据库之用,以便程序重新启动时回到以前的状态或者保存信息。应该注意应用程序的使用权限以及SQL语言的使用,Android用的是一个轻量级的数据库系统SQLite。

2. Android 生命周期

Android 程序的生命周期是由系统控制而非程序自身直接控制,这与桌面应用程序在程序自身收到关闭请求后执行一个特定的动作(比如从 main 函数中 return)而导致进程结束的思维不同。

在Android系统中,当某个activity调用startActivity(myIntent)时,系统会在所有已经安装的程序中寻找其 intentfilter和myIntent最匹配的一个activity,启动这个进程,并把这个intent通知给这个activity。这就是一个 程序的“生”。在Android中,所有的应用程序“生来就是平等的”,所以不光Android的核心程序甚至第三方程序也可以发出一个intent来启 动另外一个程序中的一个activity。Android的这种设计非常有利于“程序部件”的重用。

Android根据其重要性在内存不足的时候移去重要性最低的进程。重要性由高到低为:

1.前台进程。这样的进程拥有一个在屏幕上显示并和用户交互的activity或者它的一个IntentReciver正在运行。这样的程序重要性最高,只有在系统内存非常低,万不得已时才会被结束。

2.可见进程。在屏幕上显示,但是不在前台的程序。比如一个前台进程以对话框的形式显示在该进程前面。这样的进程也很重要,它们只有在系统没有足够内存运行所有前台进程时,才会被结束。

3.服务进程。这样的进程在后台持续运行,比如后台音乐播放、后台数据上传下载等。这样的进程对用户来说一般很有用,所以只有当系统没有足够内存来维持所有的前台和可见进程时,才会被结束。

4.后台进程。这样的程序拥有一个用户不可见的activity。这样的程序在系统内存不足时,按照LRU的顺序被结束。

5.空进程。这样的进程不包含任何活动的程序部件。系统可能随时关闭这类进程。

从某种意义上讲,垃圾收集机制把程序员从“内存管理噩梦”中解放出来,而Android的进程生命周期管理机制把用户从“任务管理噩梦”中解放出 来。Android使用Java作为应用程序API,并且结合其独特的生命周期管理机制同时为开发者和使用者提供最大程度的便利。

Activity 生命周期

Activity中常用的函数有SetContentView() findViewById() finish() startActivity(),其生命周期涉及的函数有:

void onCreate(Bundle savedInstanceState)

void onStart()

void onRestart()

void onResume()

void onPause()

void onStop()

void onDestroy()

注意的是,Activity的使用需要在Manifest文件中添加相应的,并设置其属性和intent-filter。

Service 生命周期

Service可以通过Context.startService()或Context.bindService()创建,通过 Context.stopService()、Service.stopSelf()、Service.stopSelfResult()或 Context.unbindService()来关闭。其生命周期涉及的函数有:

void onCreate()

void onStart(Intent intent)

void onDestroy()

其中onCreate()和onDestroy()可以被所有服务调用,无论是由Context.startService()还是 Context.bindService()发起的Service。但是,onStart()只能被由startService()发起的Service 调用。

如果一个Service运行其它对象绑定它,需要扩展如下callback方法:

IBinder onBind(Intent intent)

boolean onUnbind(Intent intent)

void onRebind(Intent intent)

BroadcastReceiver 生命周期

只包含一个方法:void onReceive(Context curContext, Intent broadcastMsg)

包含活动的组件的BroadcastReceiver将不会被系统关闭,但是仅包含不活动的组件的进程将随时会背系统关闭(当其它组建需要内存时)。

3. Intent 简介—— Android 的创新导航与触发机制

前文介绍了Android的四项一等公民:Activity(活动)、ContentProvider(内容提供程序)、 BroadcastReceiver(广播接收器)与Service(服务)。这四种组件是独立的,它们之间可以互相调用,协调工作,最终组成一个真正的 Android应用。

在这些组件之间的通讯中,主要是由Intent协助完成的。Intent是Android应用开发里很重要的一个元件,通过Intent可以从一 个Activity来启动另一个任意的Activity,不管是自己定义的还是系统定义的。在ActivityGroup(extends Activity)里面,Intent的flag设置对于子Activity的启动方式至关重要。

Intent负责对应用中一次操作的动作、动作涉及数据、附加数据进行描述,Android则根据此Intent的描述,负责找到对应的组件,将 Intent传递给调用的组件,并完成组件的调用。

因此,Intent在这里起着一个媒体中介的作用,专门提供组件互相调用的相关信息,实现调用者与被调用者之间的解耦。

Android应用程序框架的强大之处在于它将Web习惯引入到移动应用程序中。这并不意味着该平台提供了一个强大的浏览器,也不仅限于使用 JavaScript和服务器端资源,而是涉及Android平台的工作原理以及该平台的用户如何与移动设备交互这一核心问题。互联网的强大之处一言以蔽 之,在于一切事物通过一次单击即可获得。这些单击的内容对于用户来说就是URL(UniformResource Locator,统一资源定位符)或URI(Uniform Resource Identifier,统一资源标识符)。有效使用URI可帮助用户方便快捷地访问所需的日常信息。“把链接发给我”就说明了一切。

在移动设备上复制桌面设备体验的平台只能吸引一小部分忠实的用户。多级菜单、多次单击在移动市场中通常都不被人所接受。移动应用程序对直观易用的 要求比其他任何市场中的应用程序都要高。Intent和IntentFilter将“单击”范例引入到了Android平台移动应用程序使用和开发的核心 中。

Intent 结构

Intent是执行某操作的一个抽象描述,它描述了如下内容:

首先, 要执行的动作(action)的一个简要描述,如VIEW_ACTION(查看)、EDIT_ACTION(修改)等,Android为我们定义了一套标准动作:

MAIN_ACTION

VIEW_ACTION

EDIT_ACTION

PICK_ACTION

GET_CONTENT_ACTION

DIAL_ACTION

CALL_ACTION

SENDTO_ACTION

ANSWER_ACTION

INSERT_ACTION

DELETE_ACTION

RUN_ACTION

LOGIN_ACTION

CLEAR_CREDENTIALS_ACTION

SYNC_ACTION

PICK_ACTIVITY_ACTION

WEB_SEARCH_ACTION

此外,我们还可以根据应用的需要,定义我们自己的动作,并可定义相应的Activity来处理我们的自定义动作。

其次, 执行动作要操作的数据(data),Android中采用指向数据的一个URI来表示,如在联系人应用中,一个指向某联系人的URI可能 为:content://contacts/1。这种URI表示,通过 ContentURI这个类来描述,具体可以参考android.net.ContentURI类的文档。

此外, 除了action和data这两个重要属性外,还有一些附加属性:

category(类别),被执行动作的附加信息。例如 LAUNCHER_CATEGORY 表示Intent 的接受者应该在Launcher中作为顶级应用出现;而ALTERNATIVE_CATEGORY表示当前的Intent是一系列的可选动作中的一个,这 些动作可以在同一块数据上执行。

type(数据类型),显式指定Intent的数据类型(MIME)。一般Intent的数据类型能够根据数据本身进行判定,但是通过设置这个属性,可以强制采用显式指定的类型而不再进行推导。

component(组件),指定Intent的的目标组件的类名称。通常 Android会根据Intent 中包含的其它属性的信息,比如action、data/type、category进行查找,最终找到一个与之匹配的目标组件。但是,如果 component这个属性有指定的话,将直接使用它指定的组件,而不再执行上述查找过程。指定了这个属性以后,Intent的其它所有属性都是可选的。

extras(附加信息),是其它所有附加信息的集合。使用extras可以为组件提供扩展信息,比如,如果要执行“发送电子邮件”这个动作,可以将电子邮件的标题、正文等保存在extras里,传给电子邮件发送组件。

总之, action、 data/type、category和extras 一起形成了一种语言。这种语言使系统能够理解诸如“查看某联系人的详细信息”之类的短语。随着应用不断的加入到系统中,它们可以添加新的action、 data/type、category来扩展这种语言。应用也可以提供自己的Activity来处理已经存在的这样的“短语”,从而改变这些“短语”的行 为。

解析 Intent

在应用中,我们可以以两种形式来使用Intent:

· 显式(直接)Intent:指定了component属性的Intent(调用setComponent(ComponentName)或者setClass(Context,Class)来指定)。通过指定具体的组件类,通知应用启动对应的组件。

· 隐式(间接)Intent:没有指定comonent属性的Intent。这些Intent需要包含足够的信息,这样系统才能根据这些信息,在在所有的可用组件中,确定满足此Intent的组件。

对于显式(直接)Intent,Android不需要去做解析,因为目标组件已经很明确,Android需要解析的是那些隐式(间 接)Intent,通过解析,将Intent映射给可以处理此Intent的Activity、BroadcastReceiver或Service。

Intent解析机制主要是通过查找已注册在AndroidManifest.xml中的所有IntentFilter及其中定义的 Intent,最终找到匹配的Intent。在这个解析过程中,Android是通过Intent的action、type、category这三个属性 来进行判断的,判断方法如下:

· 如果Intent指明定了action,则目标组件的IntentFilter的action列表中就必须包含有这个action,否则不能匹配;

· 如果Intent没有提供type,系统将从data中得到数据类型。和action一样,目标组件的数据类型列表中必须包含Intent的数据类型,否则不能匹配。

· 如果Intent中的数据不是content:类型的URI,而且Intent也没有明确指定它的type,将根据Intent中数据的scheme(比 如http:或者mailto:)进行匹配。同上,Intent的scheme必须出现在目标组件的scheme列表中。

· 如果Intent指定了一个或多个category,这些类别必须全部出现在组建的类别列表中。比如Intent中包含了两个类别:LAUNCHER_CATEGORY和ALTERNATIVE_CATEGORY,解析得到的目标组件必须至少包含这两个类别。

Intent 和 IntentFilter

Intent是对需要的声明。

IntentFilter是在需要时有能力和有兴趣提供协助的声明。

Intent由一系列描述所需动作或服务的信息构成。本节将介绍所请求的动作以及与之相关的数据。

IntentFilter可以是通用的,也可以特定于向某些Intent提供服务。

Intent的动作属性通常为动词,例如VIEW、PICK或EDIT。很多内置的Intent动作都是作为Intent类的成员定义的。应用程 序开发人员也可以创建新动作。要查看信息,应用程序可以采用以下Intent动作:Intent的数据部分采用URI的形式表示,并且可以是信息的任何部 分,例如联系人记录、网站位置或对媒体剪辑的引用。

IntentFilter定义Intent与应用程序之间的关系。IntentFilter可以与Intent的数据部分或动作部分相关,或同时 与两者相关。IntentFilter还包含一个category(类别)字段。类别可以帮助对动作进行分类。例如,CATEGORY_LAUNCHER 类别指示Android包含此Intent-Filter的Activity在主应用程序启动器或主界面上应该处于可见状态。

分发Intent后,系统会计算可用的Activity、Service,以及已注册的BroadcastReceiver,并将 Intent分发给大多数适当的接收者。

IntentFilter通常在应用程序的AndroidManifest.xml中使用标记进行定义。从本质上说,AndroidManifest.xml文件就是一个应用程序描述符文件。

下一节介绍,这是 Android 在移动设备屏幕上显示 UI 元素的机制。

4. Android 视图——显示用户界面( UI )元素

Android 活动通过视图显示UI元素。视图采用以下布局设计之一:

· LinearVertical – 后续的每个元素都排在前一个元素下面,形成一个单一列。

· LinearHorizontal – 后续的每个元素都排在前一个元素右边,形成一个单一行。

· Relative – 后续的每个元素相对于前一个元素有一定的偏移量。

· Table – 与 HTML 表相似的一系列行和列。每个单元格可以包含一个视图元素。

选择一种布局(或布局的组合)之后,就可以用各个视图显示 UI。

视图元素由大家熟悉的 UI 元素组成,包括:

· Button

· ImageButton

· EditText

· TextView(与标签相似)

· CheckBox

· Radio Button

· Gallery 和 ImageSwitcher(用来显示多个图像)

· List

· Grid

· DatePicker

· TimePicker

· Spinner(与组合框相似)

· AutoComplete(具有文本自动补全特性的 EditText)

视图是在一个 XML 文件中定义的。每个元素都有一个或多个属于 Android 名称空间的属性。

[转载]ASP.NET MVC HtmlHelper中的Form和Link的小扩展

mikel阅读(1312)

[转载]我对ASP.NET MVC HtmlHelper中的Form和Link的小扩展 – 迭戈 – 博客园.

项目中碰到的问题,或多或少的记录下来,一是积累,二是各位大牛给提供更好的建议。

1、HtmlHelper中的Link

您在开发web程序的时候很有可能会定义一个执行JavaScript的伪链接(这是我起的名字),例如:


<a onclick="alert('hello world')" href="javascript:void(0)">Click me</a>

之所以我喊它为伪链接是因为它并不会跳转页面(当然那种定义location.href的除外)。

问题出现在这个伪链接并不是一成不变的,是根据数据状态来确定的,例如,当某一列的值为0的时候显示该连接,为1的时候不显示该连接,

那么我们可以这么写(示例而已):

&lt;%if (1 == 1) {%&gt;
<a onclick="alert('hello world')" href="javascript:void(0)">Click me</a>
&lt;%} %&gt;
&lt;%else { %&gt;
其它的东西。。。
&lt;%} %&gt;

很好,假如我们的状态有很多种呢,你可能要用到switch,然后还会套嵌if else,那么我们的view无疑会变得Tag soup,使维护变得异常的麻烦。

还好,我们可以为HtmlHelper扩展一个方法,将这些逻辑都写到扩展方法里面。(可能有朋友说将这些链接放到独立的ViewUserControl中,但是依然不能解决问题,因为那会使我们的ViewUserControl变得和view一样)

写到方法里面的链接必然要用到HtmlHelper的方法:Html.LinkExtensions.ActionLink,这个方法几乎能够提供我们使用html标签时所有形式。为什么

要用几乎,是因为对应上面的伪链接的形式,它支持的并不好。我在查看了起源码之后,并没有找到合适的方法能让ActionLink生成类似:

<a onclick="alert('hello world')" href="javascript:void(0)">Click me</a>

的链接。所以我决定实现一个专门生成这种伪链接的ActionLink方法。和MVC自带的ActionLink一样,使用其TagBuilder很容易实现该操作:

1 ///
2  /// 生成类似a href="javascript:void(0) onclick="alert('click me');"&gt;Click Me /a 链接
3  ///
4  ///
<span> </span> 5  ///
6  ///
7  ///
8  public static string ActionLinkForJS(this HtmlHelper htmlHelper, string linkText, object htmlAttributes)
9 {
10 return ActionLinkForJS(htmlHelper, linkText, new RouteValueDictionary(htmlAttributes));
11 }
12
13  ///
14  /// 生成类似a href="javascript:void(0) onclick="alert('click me');"&gt;Click Me /a 链接
15  ///
16  ///
17  ///
///
///
public static string ActionLinkForJS(this HtmlHelper htmlHelper, string linkText, IDictionary htmlAttributes)
{
if (String.IsNullOrEmpty(linkText))
{
throw new ArgumentException("linkText");
}

TagBuilder linkTag = new TagBuilder("a");
linkTag.InnerHtml = linkText;
linkTag.MergeAttribute("href", "javascript:void(0)");
linkTag.MergeAttributes(htmlAttributes);

return linkTag.ToString(TagRenderMode.Normal);
}

这样就实现了让ActionLink生成伪链接。
2、HtmlHelper中的BeginForm

曾几何时,我一直在用HtmlHelper中的BeginForm来生成一个Form表单。最近的一次使用出现了问题,代码是这样的:

<%using (Html.BeginForm("List", "Complaint", null, FormMethod.Post, null))

因为页面有不少查询条件,类似于搜索。我会把搜索条件Post到Action里面:

public ActionResult List(ComplaintInfo paramComplaint)

页面的查询条件类似于:

请求List这个Action的时候如果传递一个id过去,会查询出来对应的一条数据,对应的URL是这样的:http://localhost:8886/Complaint/List/220

问题就出现在这里,页面生成Form标签的action属性是这样的:

<form action="/Complaint/List/220" method="post">

这种在Post到action的时候(请注意上面的List方法),会对参数进行ModelBinder,进而相当于传递了一个参数id过去,这样其它的查询条件

就失去了作用(因为id是主键)。我尝试将BeginForm的参数routeValues显示定义为null,问题依然存在。我现在就想根据传递的actionName,controllerName

进而拼接对应Form的action属性。例如,我上面的BeginForm方法应该生成统一的形式:

<form action="/Complaint/List" method="post">

而不是在把RouteValue一起放置在Form的action属性里面。

我仔细的查看了BeginForm的源码,发现问题出现在

UrlHelper方法

中使用Route组件得到VirtualPath方法,会自动将RouteData匹配到相应的URL,导致生成的Form的action属性并不会随我们所欲。知道了问题,

改起来也很容易:

public static MvcForm BeginForm(this HtmlHelper htmlHelper, string actionName, string controllerName, object routeValues, FormMethod method, object htmlAttributes)
 {
      return BeginForm(htmlHelper, actionName, controllerName, new RouteValueDictionary(routeValues), method, new RouteValueDictionary(htmlAttributes));
  }
 
  public static MvcForm BeginForm(this HtmlHelper htmlHelper, string actionName, string controllerName, RouteValueDictionary routeValues, FormMethod method, IDictionary<string, object> htmlAttributes)
  {
      TagBuilder tagBuilder = new TagBuilder("form");
      tagBuilder.MergeAttributes(htmlAttributes);
     // action is implicitly generated, so htmlAttributes take precedence.
      tagBuilder.MergeAttribute("action", string.Format("/{0}/{1}", controllerName, actionName));
     // method is an explicit parameter, so it takes precedence over the htmlAttributes.
      tagBuilder.MergeAttribute("method", HtmlHelper.GetFormMethodString(method), true);
 
     HttpResponseBase httpResponse = htmlHelper.ViewContext.HttpContext.Response;
     httpResponse.Write(tagBuilder.ToString(TagRenderMode.StartTag));
     return new MvcForm(htmlHelper.ViewContext.HttpContext.Response);
 }

其实还有一种更简单直接的方法,就是不用BeginForm方法,而是直接写html:

<form action=”/Complaint/List” method=”post”>

到此便结束了(其实您可以利用tagbuilder类扩展很多东西出来),不知道您是否有更好的方案呢?欢迎在回复中写出来。

[转载]ASP.NET MVC HtmlHelper中的Form和Link的小扩展

mikel阅读(1359)

[转载]我对ASP.NET MVC HtmlHelper中的Form和Link的小扩展 – 迭戈 – 博客园.

项目中碰到的问题,或多或少的记录下来,一是积累,二是各位大牛给提供更好的建议。

1、HtmlHelper中的Link

您在开发web程序的时候很有可能会定义一个执行JavaScript的伪链接(这是我起的名字),例如:


<a onclick="alert('hello world')" href="javascript:void(0)">Click me</a>

之所以我喊它为伪链接是因为它并不会跳转页面(当然那种定义location.href的除外)。

问题出现在这个伪链接并不是一成不变的,是根据数据状态来确定的,例如,当某一列的值为0的时候显示该连接,为1的时候不显示该连接,

那么我们可以这么写(示例而已):

&lt;%if (1 == 1) {%&gt;
<a onclick="alert('hello world')" href="javascript:void(0)">Click me</a>
&lt;%} %&gt;
&lt;%else { %&gt;
其它的东西。。。
&lt;%} %&gt;

很好,假如我们的状态有很多种呢,你可能要用到switch,然后还会套嵌if else,那么我们的view无疑会变得Tag soup,使维护变得异常的麻烦。

还好,我们可以为HtmlHelper扩展一个方法,将这些逻辑都写到扩展方法里面。(可能有朋友说将这些链接放到独立的ViewUserControl中,但是依然不能解决问题,因为那会使我们的ViewUserControl变得和view一样)

写到方法里面的链接必然要用到HtmlHelper的方法:Html.LinkExtensions.ActionLink,这个方法几乎能够提供我们使用html标签时所有形式。为什么

要用几乎,是因为对应上面的伪链接的形式,它支持的并不好。我在查看了起源码之后,并没有找到合适的方法能让ActionLink生成类似:

<a onclick="alert('hello world')" href="javascript:void(0)">Click me</a>

的链接。所以我决定实现一个专门生成这种伪链接的ActionLink方法。和MVC自带的ActionLink一样,使用其TagBuilder很容易实现该操作:

1 ///
2  /// 生成类似a href="javascript:void(0) onclick="alert('click me');"&gt;Click Me /a 链接
3  ///
4  ///
<span> </span> 5  ///
6  ///
7  ///
8  public static string ActionLinkForJS(this HtmlHelper htmlHelper, string linkText, object htmlAttributes)
9 {
10 return ActionLinkForJS(htmlHelper, linkText, new RouteValueDictionary(htmlAttributes));
11 }
12
13  ///
14  /// 生成类似a href="javascript:void(0) onclick="alert('click me');"&gt;Click Me /a 链接
15  ///
16  ///
17  ///
///
///
public static string ActionLinkForJS(this HtmlHelper htmlHelper, string linkText, IDictionary htmlAttributes)
{
if (String.IsNullOrEmpty(linkText))
{
throw new ArgumentException("linkText");
}

TagBuilder linkTag = new TagBuilder("a");
linkTag.InnerHtml = linkText;
linkTag.MergeAttribute("href", "javascript:void(0)");
linkTag.MergeAttributes(htmlAttributes);

return linkTag.ToString(TagRenderMode.Normal);
}

这样就实现了让ActionLink生成伪链接。
2、HtmlHelper中的BeginForm

曾几何时,我一直在用HtmlHelper中的BeginForm来生成一个Form表单。最近的一次使用出现了问题,代码是这样的:

<%using (Html.BeginForm("List", "Complaint", null, FormMethod.Post, null))

因为页面有不少查询条件,类似于搜索。我会把搜索条件Post到Action里面:

public ActionResult List(ComplaintInfo paramComplaint)

页面的查询条件类似于:

请求List这个Action的时候如果传递一个id过去,会查询出来对应的一条数据,对应的URL是这样的:http://localhost:8886/Complaint/List/220

问题就出现在这里,页面生成Form标签的action属性是这样的:

<form action="/Complaint/List/220" method="post">

这种在Post到action的时候(请注意上面的List方法),会对参数进行ModelBinder,进而相当于传递了一个参数id过去,这样其它的查询条件

就失去了作用(因为id是主键)。我尝试将BeginForm的参数routeValues显示定义为null,问题依然存在。我现在就想根据传递的actionName,controllerName

进而拼接对应Form的action属性。例如,我上面的BeginForm方法应该生成统一的形式:

<form action="/Complaint/List" method="post">

而不是在把RouteValue一起放置在Form的action属性里面。

我仔细的查看了BeginForm的源码,发现问题出现在

UrlHelper方法

中使用Route组件得到VirtualPath方法,会自动将RouteData匹配到相应的URL,导致生成的Form的action属性并不会随我们所欲。知道了问题,

改起来也很容易:

public static MvcForm BeginForm(this HtmlHelper htmlHelper, string actionName, string controllerName, object routeValues, FormMethod method, object htmlAttributes)
 {
      return BeginForm(htmlHelper, actionName, controllerName, new RouteValueDictionary(routeValues), method, new RouteValueDictionary(htmlAttributes));
  }
 
  public static MvcForm BeginForm(this HtmlHelper htmlHelper, string actionName, string controllerName, RouteValueDictionary routeValues, FormMethod method, IDictionary<string, object> htmlAttributes)
  {
      TagBuilder tagBuilder = new TagBuilder("form");
      tagBuilder.MergeAttributes(htmlAttributes);
     // action is implicitly generated, so htmlAttributes take precedence.
      tagBuilder.MergeAttribute("action", string.Format("/{0}/{1}", controllerName, actionName));
     // method is an explicit parameter, so it takes precedence over the htmlAttributes.
      tagBuilder.MergeAttribute("method", HtmlHelper.GetFormMethodString(method), true);
 
     HttpResponseBase httpResponse = htmlHelper.ViewContext.HttpContext.Response;
     httpResponse.Write(tagBuilder.ToString(TagRenderMode.StartTag));
     return new MvcForm(htmlHelper.ViewContext.HttpContext.Response);
 }

其实还有一种更简单直接的方法,就是不用BeginForm方法,而是直接写html:

<form action=”/Complaint/List” method=”post”>

到此便结束了(其实您可以利用tagbuilder类扩展很多东西出来),不知道您是否有更好的方案呢?欢迎在回复中写出来。

[转载]跨平台iPhone中调用WCF服务

mikel阅读(1493)

[转载]跨平台iPhone中调用WCF服务 – 用自己的语言写个Hello World – 博客园.

由于对移动平台充满着好奇与兴趣,最近着手了iPhone开发和学习。学习的路线是从objective-c到cococa。方法是看了两本入门的英文书,还有就是学习apple的sdk。对于产品的基本想法是服务端用.net,手机客户端用iPhone。

一些复杂的逻辑处理放到服务端实现,客户端与服务端通过XML交互,在iPhone客户端解析XML通过cocoa展示数据。由于iPhone和 DoNet是两个完全不同的平台。iPhone依靠mac系统平台,donet依赖windows系统平台。这篇文章我将通过一个hello world程序讲述一下通过WCF实现从mac系统到windows的跨平台的调用。

1、创建简单的WCF服务

服务契约代码如下:

实现如下:

2、在iPhone中调用WCF

与donet调用wcf服务不同,这里使用NSURLConnection去获取WCF服务端的数据,代码如下:

NSURLConnection的委托方法:

解析XML的中hello world的委托方法,对于objective-c解析xml可以看我的上一篇博客:

运行:

总结:本文通过一个简单的例子,说明了iPhone调用WCF的方法。用wcf实现跨平台还是蛮简单的!

代码:

wcf code:http://files.cnblogs.com/zhuqil/WcfService1.rar

cocoa code:http://files.cnblogs.com/zhuqil/wcf2.zip

[原创]SQLServer2008跨数据库导入数据配置教程

mikel阅读(837)

SQL SERVER企业管理器—>服务器—>服务器对象—>链接服务器—>新建—>常规选项页—>填写链接服务器名或IP,服务器类型选SQL SERVER
—>安全性选项页—>用此安全上下文进行,填写登陆数据库的登录名和密码,就可以了。

–查询示例
select * from 链接服务器名.数据库名.dbo.表名

–导入示例
select * into 表 from 链接服务器名.数据库名.dbo.表名

–创建链接服务器
exec sp_addlinkedserver ‘ITSV ‘, ‘ ‘, ‘SQLOLEDB ‘, ‘远程服务器名或ip地址 ‘
exec sp_addlinkedsrvlogin ‘ITSV ‘, ‘false ‘,null, ‘用户名 ‘, ‘密码 ‘

–查询示例
select * from ITSV.数据库名.dbo.表名

–导入示例
select * into 表 from ITSV.数据库名.dbo.表名

–以后不再使用时删除链接服务器
exec sp_dropserver ‘ITSV ‘, ‘droplogins ‘

–连接远程/局域网数据(openrowset/openquery/opendatasource)
–1、openrowset

–查询示例
select * from openrowset( ‘SQLOLEDB ‘, ‘sql服务器名 ‘; ‘用户名 ‘; ‘密码 ‘,数据库名.dbo.表名)

–生成本地表
select * into 表 from openrowset( ‘SQLOLEDB ‘, ‘sql服务器名 ‘; ‘用户名 ‘; ‘密码 ‘,数据库名.dbo.表名)

–把本地表导入远程表
insert openrowset( ‘SQLOLEDB ‘, ‘sql服务器名 ‘; ‘用户名 ‘; ‘密码 ‘,数据库名.dbo.表名)
select *from 本地表

–更新本地表
update b
set b.列A=a.列A
from openrowset( ‘SQLOLEDB ‘, ‘sql服务器名 ‘; ‘用户名 ‘; ‘密码 ‘,数据库名.dbo.表名)as a inner join 本地表 b
on a.column1=b.column1

–openquery用法需要创建一个连接

–首先创建一个连接创建链接服务器
exec sp_addlinkedserver ‘ITSV ‘, ‘ ‘, ‘SQLOLEDB ‘, ‘远程服务器名或ip地址 ‘
–查询
select *
FROM openquery(ITSV, ‘SELECT * FROM 数据库.dbo.表名 ‘)
–把本地表导入远程表
insert openquery(ITSV, ‘SELECT * FROM 数据库.dbo.表名 ‘)
select * from 本地表
–更新本地表
update b
set b.列B=a.列B
FROM openquery(ITSV, ‘SELECT * FROM 数据库.dbo.表名 ‘) as a
inner join 本地表 b on a.列A=b.列A

–3、opendatasource/openrowset
SELECT *
FROM opendatasource( ‘SQLOLEDB ‘, ‘Data Source=ip/ServerName;User ID=登陆名;Password=密码 ‘ ).test.dbo.roy_ta
–把本地表导入远程表
insert opendatasource( ‘SQLOLEDB ‘, ‘Data Source=ip/ServerName;User ID=登陆名;Password=密码 ‘).数据库.dbo.表名

[转载]推荐8个超棒的学习 jQuery 的网站

mikel阅读(952)

[转载]推荐8个超棒的学习 jQuery 的网站 – 梦想天空 – 博客园.

根据国外科技网站 W3Techs 一项调查了近100万个网站数据显示,JQuery是目前最流行的 JavaScript 库。对于初学者来说,有的时候很难找到一个好的学习JQuery网站,所以本文收集了8个很棒的 JQuery 学习网站推荐给大家。

1. Learning jQuery

8 Great Websites to Learn Step-by-Step jQuery

最好的 jQuery 资源博客之一,从 jQuery 高手那里获得宝贵的经验。

2. jQuery Mix

8 Great Websites to Learn Step-by-Step jQuery

一个内容非常丰富的网站,有关 jQuery 的各种各样的信息。

3. jQuery for Designers

8 Great Websites to Learn Step-by-Step jQuery

非常棒的一个 jQuery 资源和教程网站,帮助你成长为 jQuery 高手。

4. 15 Days of jQuery

8 Great Websites to Learn Step-by-Step jQuery

这个网站虽然更新不定时,你仍然可以从他们的文章中学到很多东西。

5. jQuery4u

8 Great Websites to Learn Step-by-Step jQuery

jQuery4U 是另外一个有关 jQuery 资源、技巧和发展趋势的博客。

6. jQuery King

8 Great Websites to Learn Step-by-Step jQuery

jQuery King 让你学习 jQuery 更容易、更有趣。

7. jQFundamentals

8 Great Websites to Learn Step-by-Step jQuery

这是一本在线书籍,介绍 jQuery 库的基本内容。

8. jQuery How To

8 Great Websites to Learn Step-by-Step jQuery

这个网站不是每天都更新,不过你可以从他们的教程中学到很多有用的技巧。

(编译来源:梦想天空 原文来自:8 Great Websites to Learn Step-by-Step jQuery

[转载]推荐8个超棒的学习 jQuery 的网站

mikel阅读(0)

[转载]推荐8个超棒的学习 jQuery 的网站 – 梦想天空 – 博客园.

根据国外科技网站 W3Techs 一项调查了近100万个网站数据显示,JQuery是目前最流行的 JavaScript 库。对于初学者来说,有的时候很难找到一个好的学习JQuery的网站,所以本文收集了8个很棒的 jQuery 学习网站推荐给大家。

1. Learning jQuery

8 Great Websites to Learn Step-by-Step jQuery

最好的 jQuery 资源博客之一,从 jQuery 高手那里获得宝贵的经验。

2. jQuery Mix

8 Great Websites to Learn Step-by-Step jQuery

一个内容非常丰富的网站,有关 jQuery 的各种各样的信息。

3. jQuery for Designers

8 Great Websites to Learn Step-by-Step jQuery

非常棒的一个 jQuery 资源和教程网站,帮助你成长为 jQuery 高手。

4. 15 Days of jQuery

8 Great Websites to Learn Step-by-Step jQuery

这个网站虽然更新不定时,你仍然可以从他们的文章中学到很多东西。

5. jQuery4u

8 Great Websites to Learn Step-by-Step jQuery

jQuery4U 是另外一个有关 jQuery 资源、技巧和发展趋势的博客。

6. jQuery King

8 Great Websites to Learn Step-by-Step jQuery

jQuery King 让你学习 jQuery 更容易、更有趣。

7. jQFundamentals

8 Great Websites to Learn Step-by-Step jQuery

这是一本在线书籍,介绍 jQuery 库的基本内容。

8. jQuery How To

8 Great Websites to Learn Step-by-Step jQuery

这个网站不是每天都更新,不过你可以从他们的教程中学到很多有用的技巧。

(编译来源:梦想天空 原文来自:8 Great Websites to Learn Step-by-Step jQuery

[转载]MongoDB - 分布式文档存储数据库

mikel阅读(865)

[转载]MongoDB – 分布式文档存储数据库 – 开源中国社区.

MongoDB是一个介于关系数据库和非关系数据库之间的产品, 是非关系数据库当中功能最丰富,最像关系数据库的。他支持的数据结构非常松散,是类似json的bjson格式,因此可以存储比较复杂的数据类型。 Mongo最大的特点是他支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持 对数据建立索引。

官方网站http://www.mongodb.org/

它的特点是高性能、易部署、易使用,存储数据非常方便。主要功能特性有:

  • 面向集合存储,易存储对象类型的数据。
  • 模式自由。
  • 支持动态查询。
  • 支持完全索引,包含内部对象。
  • 支持查询。
  • 支持复制和故障恢复。
  • 使用高效的二进制数据存储,包括大型对象(如视频等)。
  • 自动处理碎片,以支持云计算层次的扩展性
  • 支持RUBY,PYTHON,JAVA,C++,PHP等多种语言。
  • 文件存储格式为BSON(一种JSON的扩展)
  • 可通过网络访问

所谓“面向集合”(Collenction-Orented),意思是数据被分组存储在数据集中,被称为一个集合(Collenction)。每个 集合在数据库中都有一个唯一的标识名,并且可以包含无限数目的文档。集合的概念类似关系型数据库(RDBMS)里的表(table),不同的是它不需要定 义任何模式(schema)。
模式自由(schema-free),意味着对于存储在mongodb数据库中的文件,我们不需要知道它的任何结构定义。如果需要的话,你完全可以把不同结构的文件存储在同一个数据库里。
存储在集合中的文档,被存储为键-值对的形式。键用于唯一标识一个文档,为字符串类型,而值则可以是各中复杂的文件类型。我们称这种存储形式为BSON(Binary Serialized dOcument Format)。

MongoDB服务端可运行在Linux、Windows或OS X平台,支持32位和64位应用,默认端口为27017。推荐运行在64位平台,因为MongoDB

在32位模式运行时支持的最大文件尺寸为2GB。

MongoDB把数据存储在文件中(默认路径为:/data/db),为提高效率使用内存映射文件进行管理。

[转载]Table锁定行列

mikel阅读(1491)

[转载]Table锁定行列 – KenshinCui’s Blog – 博客园.

摘要:在使用表格显示数据时我们经常会遇到数据过多无法一屏完全显示的问题,这个时候我们就会给用户显示滚动条来拖动。但是多数情况下表格是带有表 头的,纵向拖动往往就看不到表头;而横向拖动又会出现看不到主题列(例如统计某人基本信息时姓名就是主题列),这个时候怎么办呢?答案就是行列锁定。

主要内容:

1.行列锁定的常用方法

2.IE下实现行列锁定

3.使用JQuery开发一个简单的行列锁定插件

一、行列锁定的常用方法

从使用上来看,要实现行列锁定的效果无非就是使用第三方组件和自己从零做起一步步实现。第三方组件一般比较强大,除了行列锁定的功能之外一般还包括 排序、筛选等(例如Ext的Locking-grid扩展组件),但是使用第三方组件也会造成一些其他的问题,或者说有些时候你根本就没有办法使用第三方 组件(我遇到的就是这种情况)。今天我们主要讨论的是如何利用基本的html来自己实现行列锁定。自己实现table锁定行列的方法基本上有两种:一种是 利用多个table拼接,最终”拼”成一个大的table。这种情况一般将表头和主题列分别放到单独的table中,数据行放到另一个table,拖动数 据所在的table时利用js动态实现其他table的同步拖动。第二种就是利用单独的table,通过设置table行和列相对位置来实现行列锁定。两 种方式相比较而言,第一种的方式更加容易控制一些,而且由于它将一个大表格分散到多个table中更有利于完成其他复杂功能;第二种实现比第一种效果要好 一些,而且更有利于封装和扩展。由于我所遇到的情况是必须在原有html基础上实现行列锁定,因此这里就主要说一下第二种方式。

二、IE下实现行列锁定

由于我们下面说的方法主要利用tr、td的position:relative样式,而在新的css标准中没有对tr进行 position:relative定义,因此除了IE在firefox4、chrome等新版本浏览器中都无法使用我们下面所说的方法(事实上IE9也 是使用新标准,只不过其对兼容性做了处理,因此我们这种方法基本在IE所有版本中都是可行的)。我们的实现原理很简单:首先在table最外层包装一个 div用来显示滚动条,接着设置tr和td的position和z-index样式控制其相对显示,然后在滚动的时候动态修改tr和td的top和 left属性使其相对位置保持不表。下面我们来看一下具体的实现:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Table锁定行列</title>
<mce:style type="text/css"><!--
.LockRow /*固定行的样式*/
{
	position: relative;
	top: expression(this.parentElement.parentElement.parentElement.scrollTop);
	/*top:0px;*/
	z-index:2;
}
.LockCell /*固定列的样式*/
{
	position: relative;
	left: expression(this.parentElement.parentElement.parentElement.parentElement.scrollLeft);
	/*left:0px;*/
	z-index:0;
}
.LockCross /*行列交叉处样式*/
{
	z-index:3;
}
.divBoxing /*外出div样式*/
{
	clear:both;
	overflow: scroll;
	position:relative;
}
.tbLock /*设置单元格间隙的样式*/
{
	border-collapse:collapse;
}
.lockRowBg
{
	background-color:#CFF;
}
.lockColumnBg
{
	background-color:#CFF;
}
--></mce:style><style type="text/css" mce_bogus="1">.LockRow /*固定行的样式*/
{
	position: relative;
	top: expression(this.parentElement.parentElement.parentElement.scrollTop);
	/*top:0px;*/
	z-index:2;
}
.LockCell /*固定列的样式*/
{
	position: relative;
	left: expression(this.parentElement.parentElement.parentElement.parentElement.scrollLeft);
	/*left:0px;*/
	z-index:0;
}
.LockCross /*行列交叉处样式*/
{
	z-index:3;
}
.divBoxing /*外出div样式*/
{
	clear:both;
	overflow: scroll;
	position:relative;
}
.tbLock /*设置单元格间隙的样式*/
{
	border-collapse:collapse;
}
.lockRowBg
{
	background-color:#CFF;
}
.lockColumnBg
{
	background-color:#CFF;
}</style>
</head>
<body>
<div class="divBoxing" id:="divBoxing" style="width: 100%; height: 300px;">
	<table width="800" border="0" id="lockTable" class="tbLock">
		  <tbody>
		  <tr class="LockRow lockRowBg">
			<td width="100" align="center" class="LockCell LockCross lockRowBg">第一列</td>
			<td width="100" align="center" class="LockCell LockCross lockRowBg">第二列</td>
			<td width="100" align="center">第三列</td>
			<td width="100" align="center">第四列</td>
			<td width="100" align="center">第五列</td>
			<td width="100" align="center">第六列</td>
			<td width="100" align="center">第七列</td>
			<td width="100" align="center">第八列</td>
		  </tr>
		  <tr>
			<td align="center" class="LockCell lockColumnBg">1-2</td>
			<td align="center" class="LockCell lockColumnBg">2-2</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
		  </tr>
		  <tr>
			<td align="center" class="LockCell lockColumnBg">1-3</td>
			<td align="center" class="LockCell lockColumnBg">2-3</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
		  </tr>
		  <tr>
			<td align="center" class="LockCell lockColumnBg">1-4</td>
			<td align="center" class="LockCell lockColumnBg">2-4</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
		  </tr>
		  <tr>
			<td align="center" class="LockCell lockColumnBg">1-5</td>
			<td align="center" class="LockCell lockColumnBg">2-5</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
		  </tr>
		  <tr>
			<td align="center" class="LockCell lockColumnBg">1-6</td>
			<td align="center" class="LockCell lockColumnBg">2-6</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			</tr>
		  <tr>
			<td align="center" class="LockCell lockColumnBg">1-7</td>
			<td align="center" class="LockCell lockColumnBg">2-7</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			</tr>
		  <tr>
			<td align="center" class="LockCell lockColumnBg">1-8</td>
			<td align="center" class="LockCell lockColumnBg">2-8</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			</tr>
		  <tr>
			<td align="center" class="LockCell lockColumnBg">1-9</td>
			<td align="center" class="LockCell lockColumnBg">2-9</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			</tr>
		  <tr>
			<td align="center" class="LockCell lockColumnBg">1-10</td>
			<td align="center" class="LockCell lockColumnBg">2-10</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			</tr>
		  <tr>
			<td align="center" class="LockCell lockColumnBg">1-11</td>
			<td align="center" class="LockCell lockColumnBg">2-11</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			</tr>
		  <tr>
			<td align="center" class="LockCell lockColumnBg">1-12</td>
			<td align="center" class="LockCell lockColumnBg">2-12</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			</tr>
		  <tr>
			<td align="center" class="LockCell lockColumnBg">1-13</td>
			<td align="center" class="LockCell lockColumnBg">2-13</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			</tr>
		  <tr>
			<td align="center" class="LockCell lockColumnBg">1-14</td>
			<td align="center" class="LockCell lockColumnBg">2-14</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			</tr>
		  <tr>
			<td align="center" class="LockCell lockColumnBg">1-15</td>
			<td align="center" class="LockCell lockColumnBg">2-15</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			</tr>
		</tbody>
	</table>
</div>
</body>
</html>

三、使用JQuery开发一个简单的行列锁定插件

如果仅仅从实现上来说,到了第二部我们今天的内容就结束了。但是聪明的读者或许已经发现上面的用法存在的问题:第一我们需要手动的添加很多的class样式、需要对原有布局修改;第二我们上面使用了expression这个IE所特有的样式(虽然我们上面说过这个差距不适用于其他浏览器新版本,但是不代表不适用于旧版本,如果我们修改expression为纯js方式也就可以使用于其他低版本浏览器)。我们刚才说过第二种方式有一个优点就是便于封装而且几乎不必对原table布局作出修改,因此我们不妨对整个应用进行一下简单的封装,使其只需要简单的添加一行js就能够完美的运行。虽然在这个过程中我们只是将手动添加class样式换成动态添加、将expression表达换成onscroll事件,但是一切看起来确实那么的不一样。

下面就是我们使用JQuery进行封装的代码TableLock.js:

/*
author:KenshinCui
date:2011.03.29
example:$.fn.TableLock({table:'lockTable',lockRow:1,lockColumn:2,width:'100%',height:'300px'});
*/
(function($) {
    $.extend($.fn, {
        TableLock: function(options) {
            var tl = $.extend({
                table:'lockTable',//table的id
				lockRow:1,//固定行数
				lockColumn:1,//固定列数
				width:'100%',//表格显示宽度(实质是外出div宽度)
				height:'100%',//表格显示高度(实质是外出div高度)
				lockRowCss:'lockRowBg',//锁定行的样式
				lockColumnCss:'lockColumnBg'//锁定列的样式
            }, options);

			var tableId=tl.table;
			var table=$('#'+tableId);
			var rowSpan=function(tr){

			}
			if(table){
				var box=$("<div id:='divBoxing' class='divBoxing'></div>").scroll(function(){//在此处添加事件
					$('.LockRow').css('top',$(this).attr('scrollTop')+'px');
					$('.LockCell').css('left',$(this).attr('scrollLeft')+'px');
				});
				box.css('width',tl.width).css('height',tl.height);//设置高度和宽度
				table.wrap(box);
				table.addClass('tbLock');
				var crossNum=tl.lockRow*tl.lockColumn;
				if(tl.lockRow>0){
					var tr;
					for(var r=0;r<tl.lockRow;++r){//添加行锁定
						tr=table.find('tr:eq('+r+')').addClass('LockRow').addClass(tl.lockRowCss);
						for(var c=0;c<tl.lockColumn;++c){//设置交叉单元格样式,除了锁定单元格外还有交叉单元格自身样式
							if(tr)
							tr.find('td:eq('+c+')').addClass('LockCell LockCross').addClass(tl.lockRowCss);
						}
					}
				}
				if(tl.lockColumn>0){
					var rowNum=$('#'+tableId+' tr').length;
					var tr;
					for(var r=(tl.lockRow);r<rowNum;++r){
						tr=table.find('tr:eq('+r+')');
						for(var c=0;c<tl.lockColumn;++c){//添加列锁定
							tr.find('td:eq('+c+')').addClass('LockCell').addClass(tl.lockColumnCss);
						}
					}
				}

				//box.live('scroll',func);
			}else{
				alert('没有找到对应的table元素,请确保table属性正确性!');
			}
        }
    });
})(jQuery);

具体的样式表文件TableLock.css:

.LockRow /*固定行的样式*/
{
	position: relative;
	/*top: expression(this.parentElement.parentElement.parentElement.scrollTop);*/
	top:0px;
	z-index:2;
}
.LockCell /*固定列的样式*/
{
	position: relative;
	/*left: expression(this.parentElement.parentElement.parentElement.parentElement.scrollLeft);*/
	left:0px;
	z-index:0;
}
.LockCross /*行列交叉处样式*/
{
	z-index:3;
}
.divBoxing /*外出div样式*/
{
	clear:both;
	overflow: scroll;
	position:relative;
}
.tbLock /*设置单元格间隙的样式*/
{
	border-collapse:collapse;
}
.lockRowBg
{
	background-color:#CFF;
}
.lockColumnBg
{
	background-color:#CFF;
}

假设现在你有有这样一个页面,当然它不具备锁定行列的功能:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>不具备锁定行列功能的Table</title>
</head>
<body>
<table width="800" border="0">
	  <tbody>
	  <tr>
		<td width="100" align="center" >第一列</td>
		<td width="100" align="center" >第二列</td>
		<td width="100" align="center">第三列</td>
		<td width="100" align="center">第四列</td>
		<td width="100" align="center">第五列</td>
		<td width="100" align="center">第六列</td>
		<td width="100" align="center">第七列</td>
		<td width="100" align="center">第八列</td>
	  </tr>
	  <tr>
		<td align="center" >1-2</td>
		<td align="center" >2-2</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
	  </tr>
	  <tr>
		<td align="center" >1-3</td>
		<td align="center" >2-3</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
	  </tr>
	  <tr>
		<td align="center" >1-4</td>
		<td align="center" >2-4</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
	  </tr>
	  <tr>
		<td align="center" >1-5</td>
		<td align="center" >2-5</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
	  </tr>
	  <tr>
		<td align="center" >1-6</td>
		<td align="center" >2-6</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		</tr>
	  <tr>
		<td align="center" >1-7</td>
		<td align="center" >2-7</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		</tr>
	  <tr>
		<td align="center" >1-8</td>
		<td align="center" >2-8</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		</tr>
	  <tr>
		<td align="center" >1-9</td>
		<td align="center" >2-9</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		</tr>
	  <tr>
		<td align="center" >1-10</td>
		<td align="center" >2-10</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		</tr>
	  <tr>
		<td align="center" >1-11</td>
		<td align="center" >2-11</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		</tr>
	  <tr>
		<td align="center" >1-12</td>
		<td align="center" >2-12</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		</tr>
	  <tr>
		<td align="center" >1-13</td>
		<td align="center" >2-13</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		</tr>
	  <tr>
		<td align="center" >1-14</td>
		<td align="center" >2-14</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		</tr>
	  <tr>
		<td align="center" >1-15</td>
		<td align="center" >2-15</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		</tr>
	</tbody>
</table>
</body>
</html>

如果你需要让它拥有锁定行列的功能,只需要引入TableLock.js和TableLock.css(当然不要忘了jQuery类库),然后添加一句简单的代码即可:

<mce:script type="text/javascript" language="javascript"><!--
	$(function(){
		$.fn.TableLock({table:'lockTable',lockRow:1,lockColumn:2,width:'100%',height:'300px'});
	});
// --></mce:script>

下面是完整的页面代码:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>TableLock插件演示</title>
<link rel="stylesheet" href="TableLock.css" mce_href="TableLock.css" />
<mce:script type="text/javascript" language="javascript" src="jquery-1.5.1.js" mce_src="jquery-1.5.1.js"></mce:script>
<mce:script type="text/javascript" language="javascript" src="TableLock.js" mce_src="TableLock.js"></mce:script>
<mce:script type="text/javascript" language="javascript"><!--
	$(function(){
		$.fn.TableLock({table:'lockTable',lockRow:1,lockColumn:2,width:'100%',height:'300px'});
	});
// --></mce:script>
</head>
<body>
<table id="lockTable" width="800" border="0">
  <tr>
    <td width="100" align="center">第一列</td>
    <td width="100" align="center">第二列</td>
    <td width="100" align="center">第三列</td>
    <td width="100" align="center">第四列</td>
    <td width="100" align="center">第五列</td>
    <td width="100" align="center">第六列</td>
    <td width="100" align="center">第七列</td>
    <td width="100" align="center">第八列</td>
  </tr>
  <tr>
    <td align="center">1-2</td>
    <td align="center">2-2</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
  </tr>
  <tr>
    <td align="center">1-3</td>
    <td align="center">2-3</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
  </tr>
  <tr>
    <td align="center">1-4</td>
    <td align="center">2-4</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
  </tr>
  <tr>
    <td align="center">1-5</td>
    <td align="center">2-5</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
  </tr>
  <tr>
    <td align="center">1-6</td>
    <td align="center">2-6</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    </tr>
  <tr>
    <td align="center">1-7</td>
    <td align="center">2-7</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    </tr>
  <tr>
    <td align="center">1-8</td>
    <td align="center">2-8</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    </tr>
  <tr>
    <td align="center">1-9</td>
    <td align="center">2-9</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    </tr>
  <tr>
    <td align="center">1-10</td>
    <td align="center">2-10</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    </tr>
  <tr>
    <td align="center">1-11</td>
    <td align="center">2-11</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    </tr>
  <tr>
    <td align="center">1-12</td>
    <td align="center">2-12</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    </tr>
  <tr>
    <td align="center">1-13</td>
    <td align="center">2-13</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    </tr>
  <tr>
    <td align="center">1-14</td>
    <td align="center">2-14</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    </tr>
  <tr>
    <td align="center">1-15</td>
    <td align="center">2-15</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    </tr>
</table>
</body>
</html>

下面是运行后的效果:

注意:请确保在IE下.divBoxing具有position:relative;样式,否则在IE6和IE7中锁定行列将会溢出外层div,具体参见IE6 bug with overflow and position:relative 。

[转载]How to Build Applications Based On AndAR

mikel阅读(1082)

[转载]HowToBuildApplicationsBasedOnAndAR – andar – This page describes how someone can build augmented reality applications using AndAR. – AndAR – Android Augmented Reality – Google Project Hosting.

AndAR项目是Andorid的(Augmented Reality)增强现实开源项目

项目地址:http://code.google.com/p/andar/

License

The whole project is released under the GNU General Public License. This means it can be used in any project that is itself released under the GPL. If you would like to create a commercial application based on AndAR please contact ARToolworks.

Eclipse sample project Howto

This section is about the Eclipse sample project, alternatively you may check out the source code from the SVN repository.

AndAR Architecture

AndAR is an Augmented Reality Framework for Android. It not only offers a pure Java API but is also object oriented. The figure above shows a simplied class diagram of an application that makes use of AndAR.

Every Android application consists of one or more Activities. An Activity is a visual user interface, targeted to a single purpose. Only one may be active at a time. In order to write an Augmented Reality application, one has to extend the abstract class AndARActivity. This class already handles everything Augmented Reality related, like opening the camera, detecting the markers and displaying the video stream. The application would run already, by just doing that. However it would not detect any markers.

In order to do so, you have to register ARObjects to an instance of ARToolkit. This instance can be retrieved from the AndARActivity. The ARObject class itself is abstract. This means, it has to be extended, too. It expects the file name of a pattern file in it’s constructor. This file must be located in the assets folder of the Eclipse project.

Pattern files can be created by a tool called mk_patt, as described here. They are used to distinguish different markers. In order to draw a custom object, the method draw has to be overridden. Before this method is invoked a transformation matrix will already have been applied. This means the object will be alligned to the marker, without any further steps. This method will not be invoked, if the marker belonging to this object is not visible.

The class ARRenderer is reponsible for everything OpenGL related. If you want to mix augmented with non augmented 3D objects you may provide a class implementing the OpenGLRenderer interface. There are three methods defined by this interface. initGL being called only once, when the OpenGL surface is initialized. Whereas setupEnv is called once before the augmented objects are drawn. It can be used to issue OpenGL commands that shall effect all ARObjects, like initializing the lighting. In the draw method you may draw any non augmented 3D objects. It will be called once for every frame. Specifying such the described renderer is optional. The AndARActivity furthermore offers a method that allows the application to take screenshots.