[MVC]ASP.NET MVC V2预览版发布

mikel阅读(548)

ASP.NET开发团队刚发布了ASP.NET MVC第二版的第一个公开的预览版。你可以 在这里下载。

今 天的预览版是在.NET 3.5 SP1和VS 2008下工作的,可与ASP.NET MVC 1.0并行安装在同一个机器上(即,它们不相冲突,如果你安装2.0的话,你现有的ASP.NET MVC 1.0项目不会受影响)。如果你同时安装ASP.NET MVC 1.0 和 ASP.NET MVC 2.0的话,你会在Visual Studio 2008的 “新项目” 对话框中看到2个ASP.NET MVC项目模板:

ASP.NET MVC 2预览版的发布说明详述了如何将现有的ASP.NET MVC 1.0项目升级到使用V2,如果你想将它们移植来利用V2的新特性的话。

新特性

ASP.NET MVC V2将包括一堆新功能和特性(其中一些已经在 ASP.NET MVC产品路线图网页上列出了)。今天的“第一个预览版”包括的一些新特性还是第一次露面,更多的特性将在将来的预览版中出现。第一个预览版的代码还属于早期版本,开发团队今天发布这个版本,意在开始征询大家的反馈,并将它们融入将来的版本。

下面简短地说明一下其中一些新功能:

区域支持

ASP.NET MVC 2将支持一个叫“区域(areas)”的新特性,允许你轻松地将MVC应用的功能进行分割和组合。

“区域”提供了一个将控制器和视图进行分组的方式,允许你把一个大应用的各个子部分相对独立地进行构建。每个区域可以一个单独的ASP.NET MVC项目的形式来实现,并且这些项目可进而为主应用所引用。这在建造大应用时有助于管理其复杂性,并方便多个团队合作开发应用。

下面这个屏幕截图展示一个单一解决方案中有三个项目。其中一个项目叫“CompanySite”(公司网站),包括了核心的网站内容,布局,相关的控制器 和视图。还有2个单独的“区域”项目: “Blogs”(博客) 和 “Forums” (论坛)。这2个项目实现了网站的/Blogs 和 /Forums URL下的功能,封装了所有的路径规则,以及实现这2个部分的控制器和视图:

第一个预览版只包括了区域特性实现的第一个部分,还不包括任何工具支持(目前,你只能手工添加编译任务来创建并配置区域项目)。将来的预览版本将包括工具支持,同时进一步将功能集扩大和完善。

DataAnnotation(数据标记)验证支持

ASP.NET MVC 2现在包含了对最先在.NET 3.5 SP1中发布的DataAnnotation验证的内置支持,这个东西是在ASP.NET动态数据和.NET RIA服务中使用的。DataAnnotation提供了一个简易的方式,可以声明的方式在应用中的Model(模型)和ViewModel(视图模型) 类中添加验证规则,在ASP.NET MVC中有自动的绑定和UI辅助方法验证支持。

要看该特性如何在实际中使用,我们可以象下面这样创建一个新的“Customer” 视图模型类,内含5个属性(是用了 C#特性之一 — 自动属性来实现的)。

然后,我们可以使用System.ComponentModel.DataAnnotations命 名空间下的DataAnnotation特性,在这些属性上饰于适当的验证规则。下面的代码使用了4种不同的内置验证规则: Required], [StringLength], [Range], 和 [RegularExpression]。该命名空间下还包括一个基类,ValidationAttribute, 你可以继承来创建你自己的定制验证特性。

然后,我们可以创建一个CustomersController类,其中有2个 Create action方法。第一个 Create action方法处理对应于“/Customers/Create” URL的HTTP GET请求,基于一个空白的Customer对象显示一个视图模板。第二个 Create action方法则处理同个URL的HTTP POST请求,并接受一个Customer对象作为方法参数。它会检查提交的输入数据是否造成了任何模型绑定错误,如果造成了错误的话,它会使用已经输入 的数据重新显示视图模板,如果没错误的话,它会给用户显示一个提交成功了的视图:

最 后,我们可以在上面任意一个Create action方法中右击,选择 “添加视图”上下文菜单命令,自动地生成(scaffold)一个基于Customer对象的“Create”视图模板的框架。这么做的话,生成的框架视 图模板会包含下面这样一个HTML <form>:

这样,当我们在浏览器中请求“/Customers/Create” URL时,我们会得到象下面这样起始的空白表单:

如果我们输入不合法的数据,提交到服务器时,ASP.NET MVC 2模型绑定器会检测到我们的Customer类上有DataAnnotations特性,会自动地使用它们对提交的表单输入数据进行验证。如果有错误的 话,我们的控制器action方法会重新显示表单,并且给用户显示适当的验证错误消息,象下面这样。注意我们使用DataAnnotation特性指定的 验证属性错误消息字符串是如何通过Html.Validation辅助方法显示给用户的,不用编写额外的代码就可以实现。

The above form will redisplay with error messages each time the user enters invalid input and attempts to perform a form post.

在将来的ASP.NET MVC 2预览版中,我们计划将 jQuery验证插件作 为默认项目模板的一部分来发布,同时添加DataAnnotation验证规则在客户端JavaScript中自动强制执行的支持。这将允许开发人员轻松 地在一个地方,Model或ViewModel对象上,添加验证规则,然后无论对象用在应用中的什么地方,这些规则都会同时在客户端和服务器端强制执行。

如果你不希望直接标记你的模型或视图模型类,你还可以创建一个伴随你的模型类的“伙伴类(buddy class)”,另外封装DataAnnotaton规则。这个功能还在这样一些场景下有用: VS直接生成/更新类的属性代码,你无法简易地在生成的代码上饰以特性(例如,由LINQ to SQL 或 LINQ to Entities设计器生成的类)。

除了提供对DataAnnotations的内置支持外,ASP.NET MVC V2中的DefaultModelBinder类现在还有新的虚拟方法,可以在子类中覆盖,来轻松地集成其他的验证框架( 例如Castle Validator, EntLib Validation等等)。ASP.NET MVC中的验证UI辅助方法是设计来支持任何类型的验证框架的(它们不用知道DataAnnotations)。

强类型UI辅助方法

ASP.NET MVC V2包含了新的HTML UI辅助方法,这些辅助方法允许你在引用视图模板的模型对象时使用强类型的lambda表达式。这可以促成更好的 视图编译时检查(这样缺陷是在编译时发现而不是在运行时发现),还能促成视图模板中更好的代码intellisense支持。

你可以在下面看到一个示范更好intellisense的例子,注意我在使用新的Html.EditorFor()辅助方法时是如何得到Customer模型对象属性的完整列表的:

第 一个预览版提供对新的Html.EditorFor(), Html.LabelFor(), 和 Html.DisplayFor() 辅助方法的内置支持。将在这个星期发布的更新过的MVC Futures程序集还将包含对另外的Html.TextBoxFor(), Html.TextAreaFor(), Html.DropDownListFor(), Html.HiddenFor(), 和 Html.ValidationMessageFor()辅助方法的支持(随着时间的推移,这些方法也会移到核心ASP.NET MVC 2程序集中去)。

在下面,你可以看到Customer创建场景下“Create”视图模板的一个更新了的版本。注意,在UI辅助方法中,我们不是使用字符串表达式来引用 Customer对象,而是使用强类型的lambda表达式。我们在所有这些方法中都可以得到完整的 intellisense 和 编译时检查:

上面的Html.LabelFor()辅助方法生成<label for="Name">Name:</label> HTML 标识。

Html.EditorFor()辅助方法可以用于任何数据类型值。在默认情形下,它很聪明,会根据要编辑的类型输出合适的HTML <input/>元素。譬如,它会为上面的前4个属性(是字符串和整数类型)生成<input type=”text”/>元素,会为最后的那个“IsActive” 属性生成<input type=”checkbox”/>元素,因为这个属性是布尔值类型。

除了支持简单的数据类型外,Html.EditorFor()辅助方法还允许你传递给它拥有多个属性的比较复杂的对象。在默认情形下,它会对对象的所有公 开属性进行循环,输出<label>, <input/> 元素,以及它能找到的每个属性的任何合适的验证消息。例如,我们可以重写上面的视图,对Customer对象只做单个Html.EditorFor()调 用,从概念上来说输出跟上面一样的标识:

强类型的辅助方法允许你在Customer视图类的属性上饰以[DisplayName]特性,来控制为每个属性输出的标签字符串(例如:不是用 “IsActive”作为标签文字,我们可以加一个[DisplayName(“Is Active Customer:”)]特性)。

你也可以加一个[ScaffoldColumn(false)]特性,来表示,在象上面把一个复杂的对象传给Html.EditorFor()那样的场景下,某个特定的属性完全不应该显示出来。

UI 辅助方法模板化支持

Html.EditorFor() 和 Html.DisplayFor() 辅助方法对显示标准的数据类型以及含有多个属性的复杂对象有内置的支持。就象上面说的,它们还支持通过在视图模型上施加象[DisplayName]和 [ScaffoldColumn]特性这样的基本的定制机制。

但经常地,开发人员想要能够进一步定制UI辅助方法的输出,对生成的东西要有完全的控制。Html.EditorFor() 和 Html.DisplayFor()辅助方法通过一个模板化机制支持这个要求,这个机制允许你定义外部的模板,替换原先的,完全控制显示的输出。更棒的 是,你还可以在每个数据类型/类的基础上定制要显示的内容。

在第一个预览版中,你可以在"Views"[控制器名称]目录下(如果你想要定制某个特定的控制器所用视图的显示的话)或在 "Views"Shared目录下(如果你想要定制一个应用中所有视图和控制器的显示的话)加一个“EditorTemplates” 或者 “DisplayTemplates” 子目录。

然后你可以往这些目录中加分模板(partial template)文件,针对个别数据类型或者类来定制显示输出。例如,在下面,我在 "Views"Shared目录下加了一个EditorTemplates子目录,在其中加了三个定制的模板文件:

上面的“Customer.ascx”模板表示我想要定制在调用Html.EditorFor()时其参数为Customer对象时的输出(例如,我可以 定制Customer属性的精确顺序和布局)。上面的“DateTime.ascx” 模板表示我想要定制在调用Html.EditorFor()时其参数为DateTime属性时的输出(例如,我也许想要使用JavaScript的日历控 件,而不是普通的文本框)。我也可以在目录中加一个“Object.ascx” 模板,如果我想要替代所有对象的默认显示的。

除了在每个类的基础上定制输出外,你还可以在目录中加“具名模板(named templates)”。一个常见的场景也许是 “CountryDropDown”模板,它处理字符串数据类型,但不是提供标准的文本框,而是显示一个用户可以选择的列出了国家名称值 的<select>下拉框。下面是这个编辑器模板的一个例子:

然后,我们可以在调用Html.EditorFor()辅助方法时,把上面这个模板的名称作为参数传给它,明确地表示我们想要使用这个模板。例如,在下面,除了指定Country属性的lambda表达式外,我们还指定了在显示时要使用的编辑器模板的名称:

或者,你也可以在你的ViewModel属性和类型上指定“UIHint”特性。这允许你在单一一个地方指定要使用的默认编辑器或者显示器模板,然后在整个应用的所有视图中使用指定的模板(而不必显式地将这个名称作为参数传给Html.EditorFor)。

下面是一个如何使用UIHint特性来表示Customer.Country属性(字符串类型)应该在默认情形下显示时使用CountryDropDown模板的例子:

一旦在我们的视图模型上设置上述特性后,在使用Html.EditorFor()显示那个属性时,我们就不再需要显式指定模板名称了。现在,在/Customers/Create URL上点击刷新时,我们的Country属性就会显示为一个下拉框,而不是一个标准的文本框:

其他酷特性

ASP.NET MVC 2第一个预览版还包含了若干个虽小但是很妙的特性。我最喜爱的几个包括:

新的[HttpPost]特性

在 ASP.NET MVC中,把一个URL的处理分成2个action方法的做法是非常常见的,其中一个处理GET请求,另一个处理POST请求。

在ASP.NET MVC 1中,你使用[AcceptVerbs(HttpVerbs.Post)]特性来表示action方法的“Post”版本:

在ASP.NET MVC 2中这依然工作,但你现在也可以利用更简洁的[HttpPost]特性来做同样的事情:

默认参数值

处理可省参数在web场景中是司空见惯的事。在ASP.NET MVC 1中,处理可省参数一般有2个做法,通过注册定制的路径规则,在其中指定默认的值,或者将某个action方法的参数标记为nullable,然后在 action方法中添加代码处理该参数是否是null(如果是null就提供默认值)。

ASP.NET MVC 2第一个预览版现在支持在action方法的参数上饰以 System.ComponentModel命名空间下的DefaultValueAttribute。 这允许你在某个参数不在请求值中时指定ASP.NET MVC应该传给action方法的参数值。例如,下面是一个我们可以如何处理 /Products/Browse/Beverages 和 /Products/Browse/Beverages?page=2 URLs的例子,如果“page”参数不是查询字符串的一部分时,其值为“1”:

VB今天就允许你直接在语言中指定默认的参数值(而不必象上面那样显式指定DefaultValue特性),VS2010中的C#语言也将支持可省参数的默认值,将允许我们把上面的代码简化成:

这应该会使处理默认/可省场景变得非常地干净利落。

绑定二进制数据

ASP.NET MVC 2的第一个预览版还加了支持绑定base64编码的字符串值到类型为byte[]和System.Data.Linq.Binary的属性。现在还有2个 可以接受这些数据类型的重载的Html.Hidden()版本。在你想要在应用中启用并发性控制,在表单中来回传送数据库行记录的时间戳 (timestamp)值的场景下,这会非常有用。

结语

点击这里下载包含一个ASP.NET MVC 2项目的.zip文件,该项目实现了我在上面示范的样例。

今天的ASP.NET MVC 2版本还只是第一个预览版,将来的预览版中将包括更多的特性,开发团队期待在如何改进和增强功能方面得到许许多多的反馈。

有规律地发布这些预览版的目的是想帮助确保这个反馈过程是开放的,任何想参与的人都可以轻易地参与。请在 www.asp.net ASP.NET MVC论坛上发贴提反馈,建议或者贴出你遇到的问题等。 你也可以从 Phil Haack的MVC2贴子 Phil和 Scott Hanselman在Channel9录制的关于第一个预览版的录像中了解这个预览版的详情。

希望本文对你有所帮助,

Scott

[SCSF]Smart Client Software Factory 简介、安装

mikel阅读(525)

SCSF 系列:Smart Client Software Factory 简介、安装及通过模板新建项目

一、Smart Client Software Factory 简介

Smart Client Software Factory 是微软 patterns & practice 项目组的 Software Factory 系列软件框架,用于帮助开发者建立基于 MVP 模式的桌面程序(Winform),当然这种桌面程序是微软一直大力推广的所谓智能客户端程序(Smart Client)。

智能客户端(Smart Client)可以最大可能的整合瘦客户端(例如:基于 Browser 的 B\S Web 应用)和胖客户端(例如:传统的C\S结构的客户端应用)的优势,避免 B\S 用户体验差和 C\S 部署维护成本大的问题。

智能客户端与传统胖客户端的最大不同是 Smart Client 允许离线运行,一般通过 Web Service (或者 WCF) 与服务器交互。既可以充分利用客户端本地计算机的计算能力又可降低对服务器的强烈依赖。

Smart Client Software Factory 首先是为 Smart Client 应用设计的编程框架(就像 Java 中的 Struts,WebWork,是一个程序的半成品),通过合理的使用架构模式、设计模式和最佳实践为我们提供了建立 Smart Client 的指导原则和框架基础。同时 Smart Client Software Factory 也是一个软件工厂,它通过 Visual Studio 的 GuidanceAutomation 扩展了 VS 的功能,利用 RecipesTemplates (guidance package )帮助我们生成基础框架和代码,后面我们会看到。

二、Smart Client Software Factory 安装

这里介绍微软  2008-04-25 最新发布的 SCSF (April 2008 Release)。
安装必须环境:

安装可选组件: 

三、利用 Visual Studio 的模板新建项目

新建基于 Guidance Packages 的 Smart Client Development 项目

新建基于模板的项目

 

弹出创建向导:

Step1

 

点完成后,自动生成的解决方案文件夹

自动生成的基础解决方案

 

在自动生成的项目框架基础上创建解决方案文件夹,自定义项目,也可以通过在解决方案文件夹上点右键,选择 Smart Client Factory ,创建 Module 。

addModule

 

在 Smart Client 项目或者项目中的文件夹上点右键,Smart Client Factory 可以添加带有 Presenter 的 View (MVP)。

addView

 

如何具体使用,以后介绍。

[OSGi]什么是OSGi

mikel阅读(574)

OSGi(Open Service Gateway Initiative)有双重含义。一方面它指OSGi Alliance组织;另一方面指该组织制定的一个基于Java语言的服务(业务)规范——OSGi服务平台(Service Platform)。

OSGi Alliance是一个由Sun MicrosystemsIBM爱立信等于1999年3月成立的开放的标准化组织, 最初名为Connected Alliance。该组织及其标准原本主要目的在于使服务提供商通过住宅网关,为各种家庭智能设备提供各种服务。目前该平台逐渐成为一个为室内、交通工 具、移动电话和其他环境下的所有类型的网络设备的应用程序和服务进行传递和远程管理的开放式服务平台。

该规范和核心部分是一个框架 ,其中定义了应用程序的生命周期模式和服务注册。基于这个框架定义了大量的OSGi服务: 日志配置管理、偏好,HTTP(运行servlet)、XML分析、设备访问、软件包管理、许可管理、星级、用户管理、IO连接、连线管理、JiniUPnP

这个框架实现了一个优雅、完整和动态的组件模型。应用程序(称为bundle)无需重新引导可以被远程安装、启动、升级和卸载(其中Java包/类的管理被详细定义)。API中还定义了运行远程下载管理政策的生命周期管理服务注册允许bundles去检测新服务和取消的服务,然后相应配合。

OSGi原先关注于服务网关,其实可用于多个方面。现在OSGi规范已经用于从移动电话到开源的Eclipse(其中包括了与IBM的OSGi框架SMF兼容的开源版本)。 OSGi服务平台的应用包括:服务网关汽车移动电话工业自动化建筑物自动化PDA 网格计算娱乐(如iPronto)、和 IDE

OSGi规范是由成员通过公开的程序开发,对公众免费而且没有许可证限制。但是OSGi Alliance的兼容性程序只对成员开放,目前有12个兼容的实现

2003年Eclipse选择OSGi作为其插件的底层运行时架构。Equinox project对该理念进行了实验,2004年6月在Eclipse3 R3中发布。ProSyst是面向OSGi开发者的Eclipse插件。

2003年10月, 诺基亚摩托罗拉ProSyst 和其他OSGi成员组建了Mobile Expert Group (MEG)为下一代智能手机规范业务平台,做为对 MIDPCDC的补充。

[SQL]SQL Server 2008 Sp1

mikel阅读(637)

SQL Server 2008 Sp1 可以下载,只需要下载更新包即可能跟新。

 地址

以下是 Service Pack 1 中的新增功能:

  • 集成是一种安装方法,它将程序的基础安装文件与其 Service Pack 集成到一起,这样,只执行一个步骤即可安装它们。您可以将 SQL Server 2008 更新与原始安装媒体集成在一起,从而可以同时安装原始媒体和更新。可从“下载中心”下载的更新安装文档中有关于集成过程的最新说明。MSDN 也提供了更新安装文档。
  • 可以使用控制面板中的“程序和功能”卸载 SQL Server 2008 累积更新或 Service Pack。有关详细信息,请参阅更新帮助文件中的“Overview of SQL Server 服务安装概述”。
  • SQL Server 2008 Service Pack 1 提供了报表生成器 2.0 的 ClickOnce 版本。报表生成器可用于以本机模式或 SharePoint 集成模式安装的 Reporting Services (SSRS)。如果 SSRS 是以 SharePoint 集成模式安装的,那么您需要安装适用于 SharePoint 的 Microsoft SQL Server 2008 Report Builder 2.0 ClickOnce 外接程序,才能在 SharePoint 网站上使用 Report Builder 2.0 ClickOnce。有关详细信息,请参阅适用于 SharePoint 的 Report Builder 2.0 ClickOnce 自述文件

[C#]打造自己的LINQ Provider(上):Expression Tree揭秘

mikel阅读(625)

版权声明:原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://terrylee.blog.51cto.com/342737/90559

概述

在.NET Framework 3.5中提供了LINQ 支持后,LINQ就以其强大而优雅的编程方式赢得了开发人员的喜爱,而各种LINQ Provider更是满天飞,如LINQ to NHibernate、LINQ to Google等,大有“一切皆LINQ”的趋势。LINQ本身也提供了很好的扩展性,使得我们可以轻松的编写属于自己的LINQ Provider。 本文为打造自己的LINQ Provider系列文章第一篇,主要介绍表达式目录树(Expression Tree)的相关知识。

认识表达式目录树

究竟什么是表达式目录树(Expression Tree),它是一种抽象语法树或者说它是一种数据结构,通过解析表达式目录树,可以实现我们一些特定的功能(后面会说到),我们首先来看看如何构造出一 个表达式目录树,最简单的方法莫过于使用Lambda表达式,看下面的代码:

Expression<Func<int, int, int>> expression = (a, b) => a * b + 2;

在我们将Lambda表达式指定给Expression<TDelegate>类型的变量(参数)时,编译器将会发出生成表达式目 录树的指令,如上面这段代码中的Lambda表达式(a, b) => a * b + 2将创建一个表达式目录树,它表示的是一种数据结构,即我们把一行代码用数据结构的形式表示了出来,具体来说最终构造出来的表达式目录树形状如下图所示: TerryLee_0160 这里每一个节点都表示一个表达式,可能是一个二元运算,也可能是一个常量或者参数等,如上图中的ParameterExpression就是一 个参数表达式,ConstantExpression是一个常量表达式,BinaryExpression是一个二元表达式。我们也可以在Visual Studio中使用Expression Tree Visualizer来查看该表达式目录树: TerryLee_0166 查看结果如下图所示: TerryLee_0162 这里说一句,Expression Tree Visualizer可以从MSDN Code Gallery上的LINQ Sample中得到。现在我们知道了表达式目录树的组成,来看看.NET Framework到底提供了哪些表达式?如下图所示: TerryLee_0161 它们都继承于抽象的基类Expression,而泛型的Expression<TDelegate>则继承于 LambdaExpression。在Expression类中提供了大量的工厂方法,这些方法负责创建以上各种表达式对象,如调用Add()方法将创建 一个表示不进行溢出检查的算术加法运算的BinaryExpression对象,调用Lambda方法将创建一个表示lambda 表达式的LambdaExpression对象,具体提供的方法大家可以查阅MSDN。上面构造表达式目录树时我们使用了Lambda表达式,现在我们看 一下如何通过这些表达式对象手工构造出一个表达式目录树,如下代码所示:

static void Main(string[] args)
{
ParameterExpression paraLeft = Expression.Parameter(typeof(int), "a");
ParameterExpression paraRight = Expression.Parameter(typeof(int), "b");
BinaryExpression binaryLeft = Expression.Multiply(paraLeft, paraRight);
ConstantExpression conRight = Expression.Constant(2, typeof(int));
BinaryExpression binaryBody = Expression.Add(binaryLeft, conRight);
LambdaExpression lambda =
Expression.Lambda<Func<int, int, int>>(binaryBody, paraLeft, paraRight);
Console.WriteLine(lambda.ToString());
Console.Read();
}

这里构造的表达式目录树,仍然如下图所示: TerryLee_0160 运行这段代码,看看输出了什么: TerryLee_0158   可以看到,通过手工构造的方式,我们确实构造出了同前面一样的Lambda表达式。对于一个表达式目录树来说,它有几个比较重要的属性: Body:指表达式的主体部分; Parameters:指表达式的参数; NodeType:指表达式的节点类型,如在上面的例子中,它的节点类型是Lambda; Type:指表达式的静态类型,在上面的例子中,Type为Fun<int,int,int>。 在Expression Tree Visualizer中,我们可以看到表达式目录树的相关属性,如下图所示: TerryLee_0163 

表达式目录树与委托

大家可能经常看到如下这样的语言,其中第一句是直接用Lambda表达式来初始化了Func委托,而第二句则使用Lambda表达式来构造了一个表达式目录树,它们之间的区别是什么呢?

static void Main(string[] args)
{
Func<int, int, int> lambda = (a, b) => a + b * 2;
Expression<Func<int, int, int>> expression = (a, b) => a + b * 2;
} 

其实看一下IL就很明显,其中第一句直接将Lambda表达式直接编译成了IL,如下代码所示:

.method private hidebysig static void  Main(string[] args) cil managed
{
.entrypoint
.maxstack  3
.locals init ([0] class [System.Core]System.Func`3<int32,int32,int32> lambda)
IL_0000:  nop
IL_0001:  ldsfld     class [System.Core]System.Func`3<int32,int32,int32>
TerryLee.LinqToLiveSearch.Program::'CS$<>9__CachedAnonymousMethodDelegate1'
IL_0006:  brtrue.s   IL_001b
IL_0008:  ldnull
IL_0009:  ldftn      int32 TerryLee.LinqToLiveSearch.Program::'<Main>b__0'(int32,
int32)
IL_000f:  newobj     instance void class [System.Core]System.Func`3<int32,int32,int32>::.ctor(object,
native int)
IL_0014:  stsfld     class [System.Core]System.Func`3<int32,int32,int32>
TerryLee.LinqToLiveSearch.Program::'CS$<>9__CachedAnonymousMethodDelegate1'
IL_0019:  br.s       IL_001b
IL_001b:  ldsfld     class [System.Core]System.Func`3<int32,int32,int32>
TerryLee.LinqToLiveSearch.Program::'CS$<>9__CachedAnonymousMethodDelegate1'
IL_0020:  stloc.0
IL_0021:  ret
}

而第二句,由于告诉编译器是一个表达式目录树,所以编译器会分析该Lambda表达式,并生成表示该Lambda表达式的表达式目录树,即它与我们手工创建表达式目录树所生成的IL是一致的,如下代码所示,此处为了节省空间省略掉了部分代码:

.method private hidebysig static void  Main(string[] args) cil managed
{
.entrypoint
.maxstack  4
.locals init ([0] class [System.Core]System.Linq.Expressions.Expression`1<
class [System.Core]System.Func`3<int32,int32,int32>> expression,
[1] class [System.Core]System.Linq.Expressions.ParameterExpression CS$0$0000,
[2] class [System.Core]System.Linq.Expressions.ParameterExpression CS$0$0001,
[3] class [System.Core]System.Linq.Expressions.ParameterExpression[] CS$0$0002)
IL_0000:  nop
IL_0001:  ldtoken    [mscorlib]System.Int32
IL_0006:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(...)
IL_000b:  ldstr      "a"
IL_0010:  call       class [System.Core]System.Linq.Expressions.ParameterExpression
[System.Core]System.Linq.Expressions.Expression::Parameter(
class [mscorlib]System.Type,
IL_0038:  call    class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle()
IL_003d:  call    class [System.Core]System.Linq.Expressions.ConstantExpression
[System.Core]System.Linq.Expressions.Expression::Constant(object,
class [mscorlib]System.Type)
IL_0042:  call    class [System.Core]System.Linq.Expressions.BinaryExpression
[System.Core]System.Linq.Expressions.Expression::Multiply(class [System.Core]System.Linq.Expressions.Expression,
class [System.Core]System.Linq.Expressions.Expression)
IL_0047:  call    class [System.Core]System.Linq.Expressions.BinaryExpression
[System.Core]System.Linq.Expressions.Expression::Add(class [System.Core]System.Linq.Expressions.Expression,
class [System.Core]System.Linq.Expressions.Expression)
IL_004c:  ldc.i4.2
IL_004d:  newarr     [System.Core]System.Linq.Expressions.ParameterExpression
}

现在相信大家都看明白了,这里讲解它们的区别主要是为了加深大家对于表达式目录树的区别。

执行表达式目录树

前面已经可以构造出一个表达式目录树了,现在看看如何去执行表达式目录树。我们需要调用Compile方法来创建一个可执行委托,并且调用该委托,如下面的代码:

static void Main(string[] args)
{
ParameterExpression paraLeft = Expression.Parameter(typeof(int), "a");
ParameterExpression paraRight = Expression.Parameter(typeof(int), "b");
BinaryExpression binaryLeft = Expression.Multiply(paraLeft, paraRight);
ConstantExpression conRight = Expression.Constant(2, typeof(int));
BinaryExpression binaryBody = Expression.Add(binaryLeft, conRight);
Expression<Func<int, int, int>> lambda =
Expression.Lambda<Func<int, int, int>>(binaryBody, paraLeft, paraRight);
Func<int, int, int> myLambda = lambda.Compile();
int result = myLambda(2, 3);
Console.WriteLine("result:" + result.ToString());
Console.Read();
}
运行后输出的结果:

TerryLee_0159 这里我们只要简单的调用Compile方法就可以了,事实上在.NET Framework中是调用了一个名为ExpressionCompiler的内部类来做表达式目录树的执行(注意此处的Compiler不等同于编译器 的编译)。另外,只能执行表示Lambda表达式的表达式目录树,即LambdaExpression或者 Expression<TDelegate>类型。如果表达式目录树不是表示Lambda表达式,需要调用Lambda方法创建一个新的表达 式。如下面的代码:

static void Main(string[] args)
{
BinaryExpression body = Expression.Add(
Expression.Constant(2),
Expression.Constant(3));
Expression<Func<int>> expression =
Expression.Lambda<Func<int>>(body, null);
Func<int> lambda = expression.Compile();
Console.WriteLine(lambda());
}

访问与修改表达式目录树

在本文一开始我就说过, 通过解析表达式目录树,我们可以实现一些特定功能,既然要解析表达式目录树,对于表达式目录树的访问自然是不可避免的。在.NET Framework中,提供了一个抽象的表达式目录树访问类ExpressionVisitor,但它是一个internal的,我们不能直接访问。幸运 的是,在MSDN中微软给出了ExpressionVisitor类的实现,我们可以直接拿来使用。该类是一个抽象类,微软旨在让我们在集成ExpressionVisitor的基础上,实现自己的表达式目录树访问类。现在我们来看简单的表达式目录树:
static void Main(string[] args)
{
Expression<Func<int, int, int>> lambda = (a, b) => a + b * 2;
Console.WriteLine(lambda.ToString());
} 
输出后为:
TerryLee_0164
现在我们想要修改表达式目录树,让它表示的Lambda表达式为(a,b)=>(a – (b * 2)),这时就需要编写自己的表达式目录树访问器,如下代码所示:
public class OperationsVisitor : ExpressionVisitor
{
public Expression Modify(Expression expression)
{
return Visit(expression);
}
protected override Expression VisitBinary(BinaryExpression b)
{
if (b.NodeType == ExpressionType.Add)
{
Expression left = this.Visit(b.Left);
Expression right = this.Visit(b.Right);
return Expression.Subtract(left,right);
}
return base.VisitBinary(b);
}
}

使用表达式目录树访问器来修改表达式目录树,如下代码所示:

static void Main(string[] args)
{
Expression<Func<int, int, int>> lambda = (a, b) => a + b * 2;
var operationsVisitor = new OperationsVisitor();
Expression modifyExpression = operationsVisitor.Modify(lambda);
Console.WriteLine(modifyExpression.ToString());
}
运行后可以看到输出:
TerryLee_0165
似乎我们是修改表达式目录树,其实也不全对,我们只是修改表达式目录树的一个副本而已,因为表达式目录树是不可变的,我们不能直接修改表达式目录树,看看上面的OperationsVisitor类的实现大家就知道了,在修改过程中复制了表达式目录树的节点。

为什么需要表达式目录树

通过前面的介绍,相信大家对于表达式目录树已经有些了解了,还有一个很重要的问题,就是为什么需要表达式目录树?在本文开始时,就说过通过解析表达式目录树,可以实现我们一些特定的功能,就拿LINQ to SQL为例,看下面这幅图:
TerryLee_0167
当我们在C#语言中编写一个查询表达式时,它将返回一个IQueryable类型的值,在该类型中包含了两个很重要的属性Expression和Provider,如下面的代码:
TerryLee_0168
我们编写的查询表达式,将封装为一种抽象的数据结构,这个数据结构就是表达式目录树,当我们在使用上面返回的值时,编译器将会以该值所期望的方 式进行翻译,这种方式就是由Expression和Provider来决定。可以看到,这样将会非常的灵活且具有良好的可扩展性,有了表达式目录树,可以 自由的编写自己的Provider,去查询我们希望的数据源。经常说LINQ为访问各种不同的数据源提供了一种统一的编程方式,其奥秘就在这里。然而需要 注意的是LINQ to Objects并不需要任何特定的LINQ Provider,因为它并不翻译为表达式目录树,后面会说到这一点。

总结

本文详细介绍了表达式目录树的相关知识,为我们编写自己的LINQ Provider打下一个基础,希望对于大家有所帮助。查看目前网上的各种lINQ Provider,请访问万般皆LINQ

本文出自 “TerryLee技术专栏” 博客,请务必保留此出处http://terrylee.blog.51cto.com/342737/90559

[C#]Expression Tree上手指南 (一)

mikel阅读(841)

大家可能都知道Expression Tree是.NET 3.5引入的新增功能。不少朋友们已经听说过这一特性,但还没来得及了解。看看博客园里的老赵等诸多牛人,将Expression Tree玩得眼花缭乱,是否常常觉得有点落伍了呢?其实Expression Tree是一个一点就透的特性,只要对其基本概念有了一定的了解,就可以自己发挥出无数的用法。特别是之前对Reflection,泛型等知识有过一些了 解的话,就会发现Expression Tree的加入绝对是你工作中的得力助手。如果你是Expression Tree的新手,那么从本文开始,你就可以领略这一工具,之后再看老赵的文章就从容不迫了~

从表达式说起

Expression Tree从名称上看就是“表达式树”的意思。许多人一看到它,就会想起Lambda表达式,委托,Linq等等一堆名词。但其实最基本的概念就是“表达式”。现在让我们把那些名词全都给忘了,来重新了解一下表达式。

表达式是当今编程语言中最重要的组成成分。简单的说,表达式就是变量、数值、运算符、函数组合起来,表示一定意义的式子。例如下面这些都是(C#)的表达式:

3 //常数表达式
a //变量或参数表达式
!a //一元逻辑非表达式
a + b //二元加法表达式
Math.Sin(a) //方法调用表达式
new StringBuilder() //new 表达式

此外还有取地址表达式,新建数组表达式,赋值表达式等许多种。如你所见,表达式常常能够表示一个值或对象,因此在C#这类强类型语言里,表达式常常 有一个相应的类型。例如“3”这个表达式就是int类型的。不过有时表达式也没有值,例如方法调用表达式,如果方法没有返回值的话这个表达式也就没有值。 这种情况我们也说表达式的类型是void。

表达式的一个重要的特点就是它可以无限地组合,只要符合正确的类型和语义。例如+可以用于各类数值类型的加法,那么加号的左右就可以是任何类型为相 应数值的表达式。可以是函数调用和常数:Math.Sin(a) + 3;也可以是同样的加法表达式a + 2 + 3。想必大家在实践中早就用上这个特性了。那么a + 2 + 3是如何计算出正确的值来的呢?应该首先计算(a + 2)的结果b,然后计算b + 3的值。如果我们用一个图来表示这个过程,它就像这样:

 image

同理,表达式Math.Sin(a) + 3也可以表示成这样:

 image

如你所见,所有表达式都可以表示成这种树一样的结构。每个节点和它所有的后裔都构成一个独立的表达式。如果我们将表达式表示成这种结构,就可以轻易地明白它的运算规则和步骤。因此我们可以用一种树状的数据结构来表示每一个表达式。这个数据结构就是表达式树。

表达式树

刚才提到了,表达式树就是一种表示表达式的数据结构。System.Linq.Expression命名空间下的Expression类和它的诸多 子类就是这一数据结构的实现。每个表达式都可以表示成Expression某个子类的实例。每个Expression子类都按照相应表达式的特点储存自己 的子节点。例如BinaryExpression就表示各种二元运算符的表达式。它的Left和Right属性就是参与二元运算的两个运算数。下面开始我 们将每种表达式的内部特定结构称作表达式的“成分”。比如二元运算表达式的成分就是左运算数表达式、右运算符表达式和一个运算符。

Expression各个子类的构造函数都是不公开的,要创建表达式树只能使用Expression类提供的静态方法。(这同时也说明表达式树体系是不能自己扩展的)如果我们要创建1 + 2 + 3这个表达式的表达式树,可以这样写:

ConstantExpression exp1 = Expression.Constant(1);
ConstantExpression exp2 = Expression.Constant(2);
BinaryExpression exp12 = Expression.Add(exp1, exp2);
ConstantExpression exp3 = Expression.Constant(3);
BinaryExpression exp123 = Expression.Add(exp12, exp3);

这个应该非常好理解。下面如果我们想写出Math.Sin(a)这个表达式的表达式树怎么办呢?这时问题就来了,这里面的“a”不知道该用什么表示。为了解决这个问题,下面Lambda表达式该登场了。

Lambda表达式

Lambda也是C#3.0/VB9新引入的表达式。我们都知道它和以前的匿名函数和委托有关。不过现在还是把这些暂时都忘掉,完全把Lambda 表达式当成一种新的表达式来看到。刚才我们看到了各种各样的表达式,有的表示一个常数;有的表示一个变量;有的表示加法;有的表示函数调用等等。 Lambda表达式作为一个表达式,它表达的是一个函数。Lambda表达式的成分就是一系列的参数加上一个表示函数逻辑的表达式组成。

(parameters) => expression

Lambda表达式最重要的特色是它可以引入一批参数,这批参数可以在函数体表达式中使用。基于这种特色,我们就可以创建出带自定义变量的表达式树,而这些自定义变量就表示成Lambda表达式的参数:

ParameterExpression expA = Expression.Parameter(typeof(double), "a"); //参数a
MethodCallExpression expCall = Expression.Call(null,
typeof(Math).GetMethod("Sin", BindingFlags.Static | BindingFlags.Public),
expA); //Math.Sin(a)
LambdaExpression exp = Expression.Lambda(expCall, expA); // a => Math.Sin(a)

我们这里使用了一个新的Expression树节点——MethodCallExpression。它可以表示一次方法调用。方法是使用MethodInfo实例来表示的。如果画成图的话,Lambda表达式可以画成这样:

image

 

由此可见,用Lambda表达式表示函数是一个非常直观的过程。有时候我们真的觉得没有名字的函数才是真正的函数。因为函数只需要参数和函数体两个成分即可,名称只是为了在别处引用它才需要的。

到此为止,我们已经理解了表达式树的基本概念。但是我们还只能用最原始的方法一步一步地构建表达式树。前面我们用到的 LambdaExpression是适用于各种类型函数的类,.NET还提供了一种适用于特定委托类型的 LambdaExpression<TDelegate>类型。我们用它来表示强类型的LambdaExpression。现在我们就要引入 C#、VB真正表达式和表达式树之间的桥梁——表达式树字面量(Expression Tree Literals),可以自动从Lambda表达式生成它的表达式树

Expression<Func<double, double>> exp = a => Math.Sin(a);

注意这个赋值语句,左侧是一个强类型的LambdaExpression:Expression<Func<double, double>>,右侧是一个真正的C#语法的Lambda表达式。C#的编译器在这种情况下就能自动为你生成右侧Lambda表达式的表达 式树。也就是说,这个exp和我们刚才手工生成Lambda表达式树基本是一样的。注意,这种特殊的语法仅能从Lambda表达式获得表达式树。别的表达 式是不能自动生成表达式树的。但是一旦我们获得了Lambda表达式,就可以直接从它的子节点获得内部表达式了。这是一个非常有用的语法,要深刻理解它的 作用。

需要注意的是,这里的委托类型Func<double, double>有双重作用,首先它限定生成的表达式树是一个接受double,并返回double的一元Lambda函数;其次这个委托可以直接用 在Lambda表达式树的编译当中,可在C#作强类型处理。我们后面谈到表达式树的编译时再详细的讨论这个问题。

表达式树的意义:数据化的表达式

我们现在已经能够用两种方式创建表达式树——用Expression的节点组合或者直接从C#、VB的Lambda表达式生成。不管使用的是那种方 法,最后我们得到的是一个内存中树状结构的数据。如果我们愿意,可以将它还原成文本源代码的表达式或者序列化到字符串里。注意,如果是C#的表达式本身, 我们是没法对它进行输出或者序列化的,它只存在于编译之前的源文件里。现在的表达式树已经成为了一种数据,而不在是语言中的表达式。我们可以在运行的时候 处理这一数据,精确了解其内在逻辑;将它传递给其他的程序或者再次编译成为可以执行的代码。这就可以总结为表达式树的三大基本用途:

  • 运行时分析表达式的逻辑
  • 序列化或者传输表达式
  • 重新编译成可执行的代码

在下一篇中,我们将着重介绍这三者在实际开发中的用途。

习题

还有习题?别担心,你可以将下列问题当做上机实践的素材,以便很快地理解本次学到的内容。

第一题:画出下列表达式的表达式树。一开始,您很可能不知道某些操作其实也是表达式(比如取数组的运算符a[2]),不过没有关系,后面的习题将帮你验证这一点。

-a

a + b * 2

Math.Sin(x) + Math.Cos(y)

new StringBuilder(“Hello”)

new int[] { a, b, a + b}

a[i – 1] * i

a.Length > b | b >= 0

(高难度)new System.Windows.Point() { X = Math.Sin(a), Y = Math.Cos(a) }

提示:注意运算符的优先级。倒数第二题的a是String类型,其余变量你可以用任意合适的简单类型。如果想知道以上表达式分别是什么表达式,可以查MSDN。

第二题:将上述表达式中的变量提取成参数,表示成Lambda表达式的形式。然后用Expression静态方法逐渐组合的方式将他们构建出来。

例如a + b * 2写成Lambda表达式就成了(int a, int b)=> a + b * 2。按照前面Math.Sin(a)例子的做法用Expression的方法组合出这一逻辑。

第三题:验证您第二题的结果。请将生成Expression实例ToString(),它就会显示出它的表达式原型。看看您构建的表达式ToString()出来是不是正确。

如果您发现生成的Expression不是你想要构建的,又不知道该怎么做的话,可以用表达式树字面量的语法让C#编译器帮您生成。然后用Reflector反编译它就能看到正确的表达式树。不过C#编译器有时会使用一些作弊手法,聪明的你应该能找到绕过的手段……

 

(待续)

[ASP.NET]简说Session

mikel阅读(442)

*       Session大家都知道也都用过(ASP.NET我遇到过没用过Cookies的,还没遇到过没用过Session)Session的保存方式默认是在内存中,更确切的说是在
ASP.NET
的进程中,这种方式是默认的保存方式即InProc方式,在web.config里面可以进行配置。这种方式由于和应用程序在同一进程中,所以有时会发生丢失的
情况。有没有解决办法呢?答案是有的。
       一般常用的Session保存方式还有StateServerSQLServer,StateServer是一个单独的进行,较之InProc要稳定的多。而SQLServer则是可以持久的保存Session
       还有一个平时大家都说关闭浏览器Session便会丢失,其实不是这样的。Session都是有个超时时间的(TimeOut),因为Web本身就是无连接的。服务器怎么可能知道客户关闭了浏览器?即而怎么可能随之关闭Session,下面讲一下为什么表面上浏览器关闭了Session就会丢失Session在服务器上是以散列表结构保存的,并且每个会话Session服务哭都会生成一个唯一ID,又名SessionID。而自定义的Session 键值是以哈希表形式存储在相应的SessionID下面的。比如

 

用户A

SessionIDgoly4y550qfsmy554cm3k155  

KeyLoginOK Valuetrue

KeyUserName Value:春哥

 

用户B

SessionIDv4h40355mnhk3k451nfibj55  

KeyLoginOK Valuetrue

KeyUserName Value:曾哥

 

从上面的例子就可以看出为什么用户A登录后的 Session[“UserName”]是春哥,而用户B登后的Session[“UserName”]是曾哥了。

 

话接上题,因为每次会话请求都会生成一个新的唯一的SessionID,所以当关闭浏览器的时候,当前的SessionID还是存在于服务器上的,Session并没有丢,但是重新又建立请求时又生成了新的SessionID所以以前的Session当然是取不到的了。(IE8打开页面A后再打开页面B是同一个SESSIONid,所以会发生双开覆盖用户信息的问题。可以通过文件新会话页面方式开启新的会话页面。而IE7以下不会这样情况)。

 

最后说一下基本上Session不能共享也是因为这样的原因即每个请求都会是一个新的会话SessionID

[JQuery]一步一步实现跨浏览器的可编辑表格

mikel阅读(489)

      在修改数据时,有时候为了方便,我们希望能够直接在表格里面对数据进行直接修改。
      要实现可编辑的表格功能,我们要解决以下问题:
      
      1.明确要修改的数据在表格中是哪些列(如何找到这些单元格);
      
      2.如何让单元格变成可以编辑的;
            3.如何处理单元格的一些按键事件;
            4.解决跨浏览器问题。

     我们通过JQuery可以一步一步解决上述问题。
     

 一、    绘制表格

 首先我们先画好一个表格。

     Code1:

Code

   画好表格以后显示的如图:

       editTable01.jpg
      

 

       很明显它看起来不像一个表格,既没有边框,而且很丑。那么我们先给这个表格设置一些样式。

       Code2:

Code

       现在效果好多了:

       editTable02.jpg

       

      
      
但是单元格和单元格之间还是有重叠的边框,只需要在标签选择符table中加上这样一个属性就能去除重复边框:

      border-collapse: collapse;       

table{
    color
: #4F6B72; 
    border
: 1px solid #C1DAD7;
    border-collapse
: collapse;
    width
: 400px;
}

      

editTable03.jpg

      

二、    让表格的单元格变成可编辑的列

 

绘制好表格以后,我们选取表格中的编号列作为可编辑的列。要让这一列的单元格能够被编辑,就需要在这些列中插入文本框,我们通过这一列单元格的onclick事件来插入文本框。

       Code3:


$(document).ready(function(){
    
//找到学号这一列的所有单元格
    //因为学号这一列的单元格在所有td中的位置是偶数(0,2,4,6),所以通过even就可以筛选到td中偶数位的单元格
    var numTd = $("tbody  td:even");
    
    
//单击这些td时,创建文本框
    numTd.click(function(){
        
//创建文本框对象
        var inputobj = $("<input type='text'>");
        
//获取当前点击的单元格对象
        var tdobj = $(this);
        
        
//去除文本框的border
        inputobj.css("border","0");
        
//让文本框和单元格的宽度保持一致
        inputobj.width(tdobj.width());
        
//让文本框的字体和单元格的字体大小一样
        inputobj.css("font-size",tdobj.css("font-size"));
        
//让文本框和单元格的字体保持一致
        inputobj.css("font-family",tdobj.css("font-family"));
        
//让文本框和单元格的背景保持一致
        inputobj.css("background-color",tdobj.css("background-color"));
        
        
//appendTo方法把文本框添加到td中
        inputobj.appendTo(tdobj);
    }
);
}
);

      

       现在已经把文本框插入到单元格中了。既然要编辑文本框,文本框就应该有值,文本框的值来源于单元格中的数据,并且我们要清空单元格中原有的数据。

       Code4:

       


$(document).ready(function(){
    
//找到学号这一列的所有单元格
    //因为学号这一列的单元格在所有td中的位置是偶数(0,2,4,6),所以通过even就可以筛选到td中偶数位的单元格
    var numTd = $("tbody  td:even");
    
    
//单击这些td时,创建文本框
    numTd.click(function(){
        
//创建文本框对象
        var inputobj = $("<input type='text'>");
        
//获取当前点击的单元格对象
        var tdobj = $(this);
        
//获取单元格中的文本
        var text = tdobj.html();
        
        
//清空单元格的文本
        tdobj.html("");
        
        
//去除文本框的border
        inputobj.css("border","0");
        
//让文本框和单元格的宽度保持一致
        inputobj.width(tdobj.width());
        
//让文本框的字体和单元格的字体大小一样
        inputobj.css("font-size",tdobj.css("font-size"));
        
//让文本框和单元格的字体保持一致
        inputobj.css("font-family",tdobj.css("font-family"));
        
//让文本框和单元格的背景保持一致
        inputobj.css("background-color",tdobj.css("background-color"));
        inputobj.css(
"color","#C75F3E");
        
        
//给文本框赋值
        inputobj.val(text);
        
        
//appendTo方法把文本框添加到td中
        inputobj.appendTo(tdobj);
    }
);
}
);


       但是以上代码看起来非常的繁琐,jQuery有一个非常好的优点,就是它的代码连缀。上面的代码可以通过连缀进行简化:

       Code5:


$(document).ready(function(){
    
//找到学号这一列的所有单元格
    //因为学号这一列的单元格在所有td中的位置是偶数(0,2,4,6),所以通过even就可以筛选到td中偶数位的单元格
    var numTd = $("tbody  td:even");
    
    
//单击这些td时,创建文本框
    numTd.click(function(){
        
//创建文本框对象
        var inputobj = $("<input type='text'>");
        
//获取当前点击的单元格对象
        var tdobj = $(this);
        
//获取单元格中的文本
        var text = tdobj.html();
        
        
//清空单元格的文本
        tdobj.html("");
        
        inputobj.css(
"border","0")
                .css(
"font-size",tdobj.css("font-size"))
                .css(
"font-family",tdobj.css("font-family"))
                .css(
"background-color",tdobj.css("background-color"))
                .css(
"color","#C75F3E")
                .width(tdobj.width())
                .val(text)
                .appendTo(tdobj);
    }
);
}
);


       现在表格中已经成功的插入了文本框,可以对单元格进行编辑了。

       editTable04.jpg 


       
    但是有个明显的bug,当你再次点击同一个单元格时,会出现如下效果:

        editTable05.jpg

      
 

       是什么原因造成上面这个bug呢?因为在文本框中插入单元格之后,文本框是属于单元格的,我们点击文本框时,同样会触发单元格的click事件。

       我们需要阻止文本框的点击行为(阻止事件冒泡)。

      Code6:

inputobj.click(function(){
            
return false;
        }
);


       但是点击单元格的边框时,还是会出现上述的bug,那我们做如下判断:如果单元格中已经插入了文本框,就跳出click事件。

       Code7:

      

Code

      

       上面的bug解决了,但是我发现,点击单元格时,虽然从表面上看文字是变了色,但没有让我觉得它是能被编辑的。那么我就做一点点的改动,插入文本框的同时,选中文本框的文本。

       Code 8:
      

inputobj.get(0).select();

 

       但是问题又来了,在Safari浏览器中,要让文本框处于选中状态,必须显得让文本框获得焦点。而我们这里只是在点击单元格时,插入文本框并给文本框赋值,文本框并没有获得焦点。解决的方法:通过jQuerytrigger方法来触发某个事件。

       Code9: 

inputobj.trigger("focus").trigger("select");

 

   三、文本框按键事件处理

      

以上的这些问题解决了,那我们就再来给文本框添加一些按键事件。我们知道不同的浏览器中获取按键的keyCode是不同的,但是jQuery帮我们解决了这个问题。

       只需要在事件的function中加入event参数,然后在方法体中,通过event对象的which属性就能获得keyCode,event.which属性同化了不同浏览器获取keyCode的方法。

       获得keyCode之后,我主要做两个按键事件:ESC(键值:27)Enter(键值:13)

       Code10:

       

Code

      

       下面是完整的js代码:

       Code11:

      

Code

      

       下面是源文件下载:/Files/psunny/EditTable.rar

[模板]免费开源的模版引擎VTemplate

mikel阅读(463)

1、什么是VTemplate?

VTemplate是一个免费的开源(采用LGPL开 源许可协议)模板引擎,用于解析运行VT模板; 其主要目标是为ASP.NET开发提供另外一种技术选择方案,以保证用简单的语法,良好的结构,不混杂业务逻辑的方式书写页面; 适合于充当Model-View-Controller(MVC)模式应用的View角色,以使能更好的分离页面设计人员与业务开发人员的职责; 也可以作为动态文本生成工具,生成HTML、XML、Mail、程序源代码或其它文本等。

 

2、VTemplate模版范例

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title> test1 </title>
</head>
<body>
<vt:for from="1" to="9" index="i">
<vt:for from="1" to="$i" index="j">
<vt:expression var="r" args="i" args="j" expression="{0}*{1}" />{$:i}*{$:j}={$:r}&nbsp;&nbsp;&nbsp;&nbsp;
</vt:for>
<br />
</vt:for>
</body>
</html>

以上模版代码经过VTemplate解析运行后将输出一个99乘法表,如下:

1*1=1    
2*1=2     2*2=4    
3*1=3     3*2=6     3*3=9    
4*1=4     4*2=8     4*3=12     4*4=16    
5*1=5     5*2=10     5*3=15     5*4=20     5*5=25    
6*1=6     6*2=12     6*3=18     6*4=24     6*5=30     6*6=36    
7*1=7     7*2=14     7*3=21     7*4=28     7*5=35     7*6=42     7*7=49    
8*1=8     8*2=16     8*3=24     8*4=32     8*5=40     8*6=48     8*7=56     8*8=64    
9*1=9     9*2=18     9*3=27     9*4=36     9*5=45     9*6=54     9*7=63     9*8=72     9*9=81   

而程序处理代码则只有简单的两行,如下:
注:假设上面的模版代码存放在test1.html文件上

TemplateDocument document = new TemplateDocument(Server.MapPath("template/test1.html"), Encoding.UTF8);
document.Render(Response.Output);

 

 

3、什么是VT模版元素?

VT模版元素VTemplate模版引擎定义的有特殊作用的模版语言元素,分为标签元素变量元素

3.1、标签元素都是程序逻辑控制元素,是标准的HTML标签元素,如上例中用于循环处理的<vt:for>标签和用于计算表达式值的<vt:expression>标签等

3.2、变量元素是数据输出元素,其格式是以“{$:”字符开头,以“}”字符结束。 如上例中的{$:i}、{$:j}和{$:r}等

4、变量与变量表达式

4.1、变量是VTemplate模版引擎中的核心元素,用于存储或控制数据的输出,其类似于程序语言中的“变量”概念,定义格式也是一样。如上例中的i,j,r变量。

4.2、变量表达式则是定义获取变量中某个字段、属性或函数方法结果值。

定义格式为:“前缀.变量.变量字段/属性/函数方法”。

前缀:以#号开头后跟模版块的Id值,用于指示此变量是取自于对应Id的模版块下的变 量,如#my.user则表示user变量是取自于Id为my的模版块下的变量;如果省略Id号,即前缀只为#号,则表示是当前模版块下的变量;而如果前 缀是“##”,则表示是当前模版块的父模版块(如果不存在父级模版块则为当前模版块)下的变量;如果省略前缀,则表示是文档(根)模版块的变量

变量字段/属性/函数方法:表示要从变量中取得数据的字段/属性/函数方法,其中函数方法只支持不带参数的方法。此段可以定义0次或多次。

例子:

#my.user Id为my的模版块下的变量user的值
#my.user.age Id为my的模版块下的变量user的age属性/字段值
#my.user.location.getcity() Id为my的模版块下的变量user的location属性/字段值的getcity方法返回的值
#.user 当前模版块下的变量user的值
#.user.age.tostring() 当前模版块下的变量user的age属性/字段值的tostring方法返回的值
##.user.location.city 当前模版块的父级模版块的变量user的location属性/字段值的city属性/字段的值
user.age 文档(根)模版块的变量user的age属性/字段值

注:变量表达式可在“变量元素”或“标签元素”的部分属性值中使用。

5、标签元素

5.1、<vt:template>模版块标签元素

此标签用于定义模版块。在VTemplate的模版规范中,变量是基于模版块存在的,同模版块下同名的变量都是引用同一个变量实例,但不同模版块中的同名变量都是互相独立互不影响的。

标签样例:

<vt:template id="mytemplate" name="mytemplate">…………………………</vt:template>

或自闭合的样例:

<vt:template id="filetemplate" file="include/myfile.html" charset="utf-8" />

标签中已定义的属性列表:

名称 说明
id 标签元素的Id,建议唯一但不强制。(可不定义)
name 标签元素的名称。(可不定义)
file 模版块数据文件的路径地址,可以绝对或相对地址
charset 模版块数据文件的编码,如果未定义则如果存在父级模版块的话则采用父级模版块的编码,否则采用系统默认编码
render 定义用于处理此模块数据的实例,格式:"类实例,程序集"。如果已定义此属性但未定义rendermethod属性,则类实例必须已实现ITemplateRender接口。(可不定义)
rendermethod 定义用于处理此模块数据的类实例的方法,此方法必须已标记TemplateRenderMethodAttribute特性。(可不定义)

 

5.2、<vt:include>文件包含标签元素

此标签用于包含外部文件。

标签样例:

<vt:include file="include/myfile.html" charset="utf-8">…………………………</vt:include>

或自闭合的样例:

<vt:include file="include/myfile.html" charset="utf-8" />

标签中已定义的属性列表:

名称 说明
id 标签元素的Id,建议唯一但不强制。(可不定义)
name 标签元素的名称。(可不定义)
file 模版块数据文件的路径地址,可以绝对或相对地址
charset 模版块数据文件的编码,如果未定义此属性则如果存在父级模版块的话则采用父级模版块的编码,否则采用系统默认编码

 

5.3、<vt:for>循环标签元素

此标签用于定义数据循环,类似于程序语言中的for循环。

标签样例:

<vt:for from="1" to="9" index="i">…………………………</vt:for>

标签中已定义的属性列表:

名称 说明
id 标签元素的Id,建议唯一但不强制。(可不定义)
name 标签元素的名称。(可不定义)
from 循环起始值,可为一个数值常量(如:1)或变量表达式(必须以$字符开头,如:$i)
to 循环结束值,可为一个数值常量(如:1)或变量表达式(必须以$字符开头,如:$i)
step 循环值的步值,可为一个数值常量(如:1)或变量表达式(必须以$字符开头,如:$i),如果未定义此属性,则默认为1
index 定义存储循环索引值的变量,注:此索引值是一个LoopIndex实例。(可不定义)

5.4、<vt:foreach>集合数据循环标签元素

此标签用于定义处理集合数据的循环,类似于程序语言中的foreach循环。

标签样例:

<vt:foreach from="users" item="user" index="i">…………………………</vt:foreach>

标签中已定义的属性列表:

名称 说明
id 标签元素的Id,建议唯一但不强制。(可不定义)
name 标签元素的名称。(可不定义)
from 变量表达式
item 定义存储当前循环值的变量。(可不定义)
index 定义存储循环索引值的变量,注:此索引值是一个LoopIndex实例。(可不定义)

 

5.5、<vt:foreachelse>空集合数据循环标签元素

此标签用于定义当集合数据为空(数量为0)时显示处理的节点。此标签必须在<vt:foreach>标签中定义,并且此标签为单节点标签(即不需要配对的结束标签)。

标签样例:

<vt:foreach from="users" item="user" index="i">

{$:i}、我叫{$:user.name},今年{$:user.age}岁

<vt:foreachelse />

没有任何用户

</vt:foreach>

注:当users集合数据为空时则显示"没有任何用户"字样,否则不显示此字样。

 

标签中已定义的属性列表:

名称 说明
id 标签元素的Id,建议唯一但不强制。(可不定义)
name 标签元素的名称。(可不定义)

5.6、<vt:if>条件判断标签元素

此标签用于定义数据条件判断,类似于程序语言中的if语句。

标签样例:

<vt:if var="user.age" value="20" compare=">">…………………………</vt:if>

标签中已定义的属性列表:

名称 说明
id 标签元素的Id,建议唯一但不强制。(可不定义)
name 标签元素的名称。(可不定义)
var 用于判断条件的变量表达式
value 用于比较条件的值,可为数值/字符串常量或变量表达式(必须以$字符开头,如:$i)
注:此属性可以多次定义,当var变量表达式中的值和其中一个value属性值匹配时即符合条件。
compare 比较的方式,可以为以下几种:
> : 大于
>= : 大于等于
< : 小于
<= : 小于等于
!=或<> : 不等于
= 或== : 相等
如果未定义此属性则表示采用“相等”比较。
expression 定义需要简单运算的表达式,表达式中支持 “{0}”标记,用于代替var属性的变量表达式的值。(可不定义)

5.7、<vt:elseif>条件分支判断标签元素

此标签用于定义数据条件的分支判断。类似于程序语言中的else if语句。此标签可以同时支付一个或多个。此标签只能在<vt:if>标签中定义,并且此标签为单节点标签(即不需要配对的结束标签)。

标签样例:

<vt:if var="user.age" value="20">

20岁用户
<vt:elseif value="30” />

30岁用户

<vt:elseif value="40” />

40岁用户

</vt:if>

标签中已定义的属性列表:

名称 说明
id 标签元素的Id,建议唯一但不强制。(可不定义)
name 标签元素的名称。(可不定义)
var 用于判断条件的变量表达式。如果未定义此属性,则为标签所在的<vt:if>标签中的var属性值
value 用于比较条件的值,可为数值/字符串常量或变量表达式(必须以$字符开头,如:$i)
注:此属性可以多次定义,当var变量表达式中的值和其中一个value属性值匹配时即符合条件。
compare 比较的方式,可以为以下几种:
> : 大于
>= : 大于等于
< : 小于
<= : 小于等于
!=或<> : 不等于
= 或== : 相等
如果未定义此属性则表示采用“相等”比较。
expression 定义需要简单运算的表达式,表达式中支持 “{0}”标记,用于代替var属性的变量表达式的值。(可不定义)

5.8、<vt:else>条件分支判断标签元素

此标签用于定义数据条件的分支判断,即当<vt:if>标签中的所有条件分支都条件不成立时用于显示处理的节点。类似于程序语言中的else语句。此标签只能在<vt:if>标签中定义,并且此标签为单节点标签(即不需要配对的结束标签)。

标签样例:

<vt:if var="user.age" value="20">

20岁用户
<vt:elseif value="30” />

30岁用户

<vt:else />

未知岁数

</vt:if>

标签中已定义的属性列表:

名称 说明
id 标签元素的Id,建议唯一但不强制。(可不定义)
name 标签元素的名称。(可不定义)

 

5.9、<vt:expression>表达式标签元素

此标签用于对变量表达式进行简单数据运算

标签样例:

<vt:expression var="r" args="i" args="j" expression="{0}*{1}" />

 

标签中已定义的属性列表:

名称 说明
id 标签元素的Id,建议唯一但不强制。(可不定义)
name 标签元素的名称。(可不定义)
var 存储表达式运算结果的变量
args 参与表达式计算的变量表达式。(可不定义)
注:此属性可以多次定义,在表达式中分别以{0},{1}表示各个args属性的变量表达式值
expression 要进行运算的表达式。

 

5.10、<vt:serverdata>服务器数据标签元素

此标签用于获取服务器的部分数据,如Session、Application、DateTime等等

标签样例:

<vt:serverdata var="session" type="session" item="username" />

 

标签中已定义的属性列表:

名称 说明
id 标签元素的Id,建议唯一但不强制。(可不定义)
name 标签元素的名称。(可不定义)
var 存储服务器数据的变量
type

要获取服务器数据的类型。支持以下几种:

类型 说明
Time

获取服务器时间

item 属性值可定义为以下值:

today = 获取今天的日期(不带时间部分)

yesterday = 获取昨天的日期(不带时间部分)

tomorrow = 获取明天的日期(不带时间部分)

其它值 = 获取服务器现在的时间

Random

获取一个0—1之间的双精度随机数

item 属性不需要定义

Application

获取服务器当前上下文的HttpApplicationState对象.如果模版引擎不在Web程序上使用则无效

item 属性值则为Application集合的键值key

Session

获取服务器当前上下文的HttpSessionState对象.如果模版引擎不在Web程序上使用则无效

item 属性值则为Session集合的键值key

Cache

获取服务器当前上下文的缓存对象

item 属性值则为Cache集合的键值key

QueryString

获取服务器当前上下文的Request.QueryString数据集合.如果模版引擎不在Web程序上使用则无效

item 属性值则为Request.QueryString集合的键值key

Form 获取服务器当前上下文的Request.Form数据集合.如果模版引擎不在Web程序上使用则无效

item 属性值则为Request.Form集合的键值key

Cookie

获取服务器当前上下文的Request.Cookie数据集合.如果模版引擎不在Web程序上使用则无效 

item 属性值则为Request.Cookie集合的键值key,如果item值包含“.”号,则表示属于某个Cookie下的某个Value值,例如:

item="user"则表示是Request.Cookie["user"]值;
item="user.name"则表示是Requst.Cookie["user"]["name"]值

ServerVariables 获取服务器当前上下文的Request.ServerVariables数据集合.如果模版引擎不在Web程序上使用则无效

item 属性值则为Request.ServerVariables集合的键值key

Request 获取服务器当前上下文的HttpRequest对象.如果模版引擎不在Web程序上使用则无效

item 属性不需要定义

Environment 获取服务器系统平台的环境参数

item 属性不需要定义

item 要获取的数据项,此属性值根据type值而具有不同的意义,具体的看上表。

 

 

6、变量元素

变量元素主要用于输出变量表达式的值。其定义格式为:

{$:变量表达式 属性="属性值"}

例子:

{$:i}、{$:user.age format=”00”}、{$:user.name length=”20” htmlencode=”true”}

{$:#my.i}、{$:##.user.age}、{$:#my.user.location.getcity() htmlencode=”true”}

 

元素中已定义的属性列表:

名称 说明
htmlencode 输出变量表达式的值时是否需要进行HTML字符编码。true/false,默认为false(可不定义)
urlencode 输出变量表达式的值时是否需要进行URL字符编码。true/false,默认为false(可不定义)
xmlencode 输出变量表达式的值时是否需要进行XML字符编码。true/false,默认为false(可不定义)
textencode 输出变量表达式的值时是否需要进行文本字符编码(先进行HTML字符编码,再将“空格”转换为"&nbsp;”;“回车换行”转换为"<br />”字符)。true/false,默认为false(可不定义)
jsencode 输出变量表达式的值时是否需要进行JavaScript脚本字符编码。true/false,默认为false(可不定义)
format 用于格式化变量表达式的值的格式(如果变量表达的值已实现IFormattable接口则调用接口方法,否则调用String.Format方法)。(可不定义)
length 输出变量表达的值时的最大长度。如果值的字符长度超出此定义的值,则将进行字符截取。默认为0不截取(可不定义)
charset 定义在进行urlencode或length截取字符时采用的编码。默认为所在模版块的charset(可不定义)

 

7、项目托管
VTemplate项目托管在Google code上。
SVN: http://net-vtemplate.googlecode.com/svn/src/VTemplate.Engine/

 例子请参考VTemplate.WebTester项目

 http://net-vtemplate.googlecode.com/svn/src/VTemplate.WebTester/

[Linux]Ubuntu操作系统安装使用教程

mikel阅读(586)

随着微软的步步紧逼,包括早先的Windows黑屏计划实施逮捕番茄花园作者判刑,种种迹象表明,中国用户免费使用盗版Windows的日子将不会太长久了,那么这个世界上有没有即免费又易用的操作系统呢?答案是有,那就是Ubuntu操作系统。

   Ubuntu是一个流行的Linux操作系统,基于Debian发行版和GNOME桌面环境,和其他Linux发行版相比,Ubuntu非常易用,和 Windows相容性很好,非常适合Windows用户的迁移,预装了大量常用软件,中文版的功能也较全,支持拼音输入法,预装了Firefox、 Open Office、多媒体播放、图像处理等大多数常用软件,一般会自动安装网卡、音效卡等设备的驱动,对于不打游戏不用网银的用户来说,基本上能用的功能都有 了,在Windows操作系统下不用分区即可安装使用,就如同安装一个应用软件那么容易,整个Ubuntu操作系统在Windows下就如同一个大文件一 样,很容易卸载掉。下面我就介绍一下Ubuntu操作系统安装使用的方法,供Ubuntu新手参考,希望能起到Linux扫盲的作用。

  下载Ubuntu

  Ubuntu有三个版本,分别是桌面版(Desktop Edition),服务器版(Server Edition),上网本版(Netbook Remix),普通桌面电脑使用桌面版即可,下载地址请点这里,32 位CPU请选择32bit version,上网本则可下载Netbook Remix,目前Ubuntu已经占据三分之一的上网本市场,仅次于WIndows XP系统。Google的Chrome操作系统强有力的对手就是Ubuntu Netbook Remix。

  目前最新的版本是9.04版,下载后的文件名是ubuntu-9.04-desktop-i386.iso,大小是698M,通过迅雷下载非常快,大约半个小时左右可以下载完毕。

  安装Ubuntu

  在Windows下可以不用重新分区,直接像安装一个应用程序那样安装Ubuntu,安装方法是,先使用一个虚拟光驱(例如微软的Windows虚拟光驱)装载ubuntu-9.04-desktop-i386.iso文件,然后运行根目录下的wubi.exe,运行前要将本地磁盘的名字都修改为英文名,否则会出现错误信息“UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3: ordinal not in range(128)”而无法运行。

  运行之后,会出现如下界面,选择“Install inside Windows”即可在Windows下直接安装而无需分区。

Ubuntu Wubi

  接着出现下面的安装界面,选择一个磁盘,然后将语言选择为“Chinese(Simplified)简体中文”,Installation size为Ubuntu环境的总共磁盘大小,然后是登录用户名和密码,设置好了以后就点安装继续。

Ubuntu Wubi

  后面的安装操作很简单,不需要手动干预就可以直接安装好整个操作系统,大部分的硬件驱动都可以自动安装好。提示安装完毕后,重启系统,就可以使用Ubuntu了。

  自动登录Ubuntu

   Ubuntu默认是每次登录都是要输入用户名和密码的,这是基于安全方面的考虑,不过对于桌面版,大家都习惯自己的电脑能自动登录,类似Windows XP系统那样,通过一些设置可以实现Ubuntu自动登录。设置的方法是:点击“系统”—“系统管理”—“登录窗口” (需要输入管理员密码),然后在“安全”选项页—勾选(启用自动登录),然后在下拉列表里选择自己的用户名。之后Ubuntu就能够自动登录了。

  开机自动运行程序

  类似Windows的启动菜单,在Linux也可以实现开机自动运行一些命令,比较简单的方法是修改 /etc/rc.local 文件,将需要执行的命令添加进去。

  桌面设置

  Ubuntu的桌面,默认有两个任务栏,一个在上面,一个在下面,通常习惯Windows的用户喜欢将上面的移到下面,Ubuntu的面板无法拖动,在上面点右键后,可以让其显示在屏幕下端。

  桌面背景设置和Windows很类似,在“桌面”上点右键,点更改桌面背景,就可以进行修改设置。

  修改root密码

  Ubuntu默认的用户并不是root,我们可以通过操作来使用root这个超级管理员帐号,以获得更大的权限。先打开终端,然后执行下面的语句

  sudo passwd root

  就可以修改超级管理员root的密码,之后就可以使用su命令切换到root用户来执行某些更高权限的操作。

  Hosts修改

  在Windows下,我们上Twitter等网站都需要修改hosts文件,在Linux下也有hosts文件,文件位于/etc/hosts,使用root用户可以编辑修改这个文件,主机名和IP的格式与Windows的完全相同,例如:

  127.0.0.1 localhost

  在Ubuntu下安装软件

  Ubuntu下的软件安装有几种方式,常用的是deb包的安装方式,deb是debian系列的Linux包管理方式,ubuntu属于debian的派生,也默认支持这种软件安装方式,当下载到一个deb格式的软件后,直接在界面上就可以安装。

  另一种常见的安装方式是源代码编译安装,很多软件会提供了源代码给最终用户,用户需要自行编译安装,先使用tar将源代码解压缩到一个目录下,然后进入这个目录,执行以下三条命令:

  ./configure

  make

  sudo make install

  执行完成后,即可完成软件的编译和安装。

  还有一种方式是apt-get的安装方法,APT是Debian及其衍生发行版的软件包管理器,APT可以自动下载,配置,安装二进制或者源代码格式的软件包,因此简化了Unix系统上管理软件的过程。常用的安装命令是:

  sudo apt-get install 软件名

  sudo apt-get remove 软件名

  Firefox浏览器的更新

   Ubuntu安装完成后会自动安装一个Firefox浏览器,遗憾的是这个Firefox版本通常较低,例如Ubuntu 9.04会安装Firefox 3.0,不过我们可以想办法下载最新的Firefox覆盖掉老版本Firefox,具体方法是,先上Firefox官方网站下载最新的Linux版本 Firefox,然后将其解压缩到某一个目录下,例如firefox目录,进入终端,到这个目录的父目录,执行下面的语句:

  sudo cp -r firefox /usr/lib/firefox-3.5.2

  sudo mv /usr/bin/firefox /usr/bin/firefox.old

  sudo ln -s /usr/lib/firefox-3.5.2/firefox /usr/bin/firefox-3.5.2

  sudo ln -s /usr/bin/firefox-3.5.2 /usr/bin/firefox

  之后就可以将Firefox成功替换为最新的Firefox 3.52版本,未来的Firefox更新也可以使用这种方法。

  Firefox的Flash问题

  经过我的实际测试,Ubuntu自动安装的Flash插件swfdec存在很多问题,在Firefox中,很多网页的Flash无法显示,包括Google音乐和开心网等,因此建议使用下面两条语句将其卸载。

  sudo apt-get remove swfdec-mozilla

  sudo apt-get remove swfdec-gnome

  之后可安装官方的Adobe Flash Player的Linux版,下载地址是: http://get.adobe.com/flashplayer/

  安装完成后,还要解决中文乱码问题,解决方法是执行下面语句:

  sudo cp /etc/fonts/conf.d/49-sansserif.conf /etc/fonts/conf.d/49-sansserif.conf.bak

  sudo rm /etc/fonts/conf.d/49-sansserif.conf

  之后,Firefox的Flash就完全正常了,在Firefox中访问开心网等Flash网站,显示都正常。

  安装常用软件

  介绍完了安装的方法和Firefox,下面就可以去各个网站下载一些常用的Linux软件来安装了,下面是我整理的一些常用的Linux软件列表:

  Linux QQ:访问这个地址,下载deb文件安装,可以在Linux下玩腾讯QQ。

  防火墙 firestarter: 使用 sudo apt-get install firestarter 安装。

  杀毒软件 AntiVir: 虽然Linux下的病毒很少,但对于新手还是有必要安装一个杀毒软件,访问这个地址可以下载免费版的AntiVir杀毒软件,这个软件我曾经在《五个最佳的防病毒软件》中介绍过。

  rpm 转 deb 工具: 使用 sudo apt-get install alien 安装

  JAVA环境安装: JRE的安装 sudo apt-get install sun-java6-jre ,JDK的安装 sudo apt-get install sun-java6-jdk

  eclipse安装: 先到这个地址下载最新的eclipse,然后使用tar xvfz eclipse-php-galileo-linux-gtk.tar.gz -C /opt 解压缩后就可以使用。

eclipse安装

  Picasa 3 for Linux安装: 访问这个地址,下载后直接安装。

  Google Earth安装: 在这里下载最新版本的Google Earth,下载下来是个BIN文件,在图形界面上右击 GoogleEarthLinux.bin,在“权限”选项卡中勾选“允许以程序执行文件”,如下图。

Google Earth安装

  之后在终端上执行 ./GoogleEarthLinux.bin 即可安装。

Google Earth安装

  安装LAMP环境

  Ubuntu的桌面版也可以安装LAMP(Linux + Apache + MySQL + PHP)环境,这里我介绍一个最简单的方法,就是使用XAMPP,这个项目我曾经在《常见的WAMP集成环境》中介绍过,XAMPP不但支持Windows,还支持Linux,在其网站下载之后,运行下面两条命令:

  tar xvfz xampp-linux-1.7.2.tar.gz -C /opt

  /opt/lampp/lampp start

  就可以启动LAMP环境,XAMPP是功能全面的集成环境,软件包中包含Apache、MySQL、SQLite、PHP、Perl、FileZilla FTP Server、Tomcat等等,很适合开发环境使用。

  安装程序添加程序菜单和桌面

  有些程序是直接解压缩安装的,因此不会添加“应用程序”的菜单项,我们可以手动将其添加菜单项,具体方法是,打开“系统”—“首选项”—“主菜单”,新增即可。

  添加桌面快捷方式是,在桌面上点右键,创建启动器。这个“启动器”就是Windows里面的“快捷方式”。

  将“应用程序”的菜单项创建到桌面快捷方式的方法是,在“应用程序”的菜单项上单击鼠标右键,选择“将此启动器添加到桌面”或“将此启动器添加到面板”,就可以了。

  以上是我在安装使用Ubuntu时整理的教程,如果你还没有安装过这个操作系统,相信在这个教程的指引下,你就能轻松驾驭这个Linux系统,如果你在使用Ubuntu的过程中也有一些经验和心得,请留言与大家分享。


原创文章如转载,请注明:转载自月光博客 [ http://www.williamlong.info/ ]
本文链接地址:http://www.williamlong.info/archives/1905.html