
作者: 来源:来自“Jesse Liberty”的视频“USING MULTIPLE PAGES, PART 1” 标题:如何在Silverlight中切换“页面”
最近初学Silverlight,有海量的问题需要解决。先把这个切换页面的方法记录一下。
这个做法是来自“Jesse Liberty”的视频“USING MULTIPLE PAGES, PART 1”,基本方法是创建一个PageSwticher,这个PageSwitcher不直接显示页面,而是作为一个后台,负责切换各个页面。 具体做法是:
新建一个UserControl,名字可以叫做PageSwitcher。然后将PageSwitcher.xaml中的Grid控件去掉,编程下面这样:
CODE:PageSwitcher.xaml
<UserControl x:Class="SilverlightDemo.PageSwitcher"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation%22
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml%22>
</UserControl>
然后在后台代码中增加一个方法,比如叫做SwitchPage,用来切换页面,然后在构造函数中调用,用来显示第一个要显示页面:
CODE:SwitchPage方法
public partial class PageSwitcher : UserControl
{
public PageSwitcher()
{
InitializeComponent();
SwitchPage(new Page()); //显示第一个要显示的页面
}
/// <summary>
/// 切换页面
/// </summary>
/// <param name="newPage">需要被切换到的页面</param>
public void SwitchPage(UserControl newPage)
{
this.Content = newPage;
}
}
然后在我们的各个页面中,在需要切换页面的事件响应方法中,只需要这么做:
CODE:需要切换页面的事件响应方法中最后,我们需要修改app.xaml.cs中的Application_Startup方法,修改起始页面
CODE:app.xaml.cs使用部分代码
CODE:设置cookie
if (!InternetSetCookie("http://xxxx/xxxx.htm", "Test", "Sent as Test via VB+ ;expires=Sun,22-Feb-2099 00:00:00 GMT"))
{
MessageBox.Show(GetLastError().ToString());
}
CODE:读取cookie
int size = 1000;
StringBuilder cookie = new StringBuilder(size);
if (!InternetGetCookie("http://xxxx/xxxx.htm", "Test", cookie, ref size))
{
MessageBox.Show(GetLastError().ToString());
}
else
{
MessageBox.Show(cookie.ToString());
}
作者:大师 来源:互联网 标题:ASP.NET 3.5 要如何安裝在 IIS 5.0/6.0 中
这几天在研究 .Net 3.5,发现了一个疑问,就是在 IIS 里面为什么看不到 ASP.NET 3.5 的选项?且以前在 .NET 2.0 的时候有个 aspnet_regiis.exe 的执行档 在.NET 3.5 也看不到!!
后来我才搞懂,原來 ASP.NET 3.5 只是使用 .Net Framework 3.5 的组件(assembly)而已!整个核心的架构还是建立在 .NET 2.0 之上,.NET Framework 的 API 都沒变,只是到了 .NET 3.5 很多 assembly 都重新写过了,且执行的速度也比 .NET 2.0 的组件还快。
如果你用 Visual Studio 2008 开一个网站,你开启 web.config 会发现在 <assemblies> 区段中出现了一堆 assembly 的定义,其版本都是 3.5.0.0
CODE:web.config
<compilation debug="true">
<assemblies>;
<add assembly="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
<add assembly="System.Data.DataSetExtensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
<add assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
<add assembly="System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
</assemblies>
</compilation>
所以 ASP.NET 3.5 的程式要安装在 IIS 上不需要特別指定 ASP.NET 3.5 的版本,继续沿用 ASP.NET 2.0 的版本即可,但作業系統本身必須要先安裝 .Net Framework 3.5 runtime 就是了!
CODE:web.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<servlet>
<description>
This is the description of my J2EE component
</description>
<display-name>
This is the display name of my J2EE component
</display-name>
<servlet-name>imgServlet</servlet-name>
<servlet-class>
com.zouzhxi.test.servlet.imgServlet
</servlet-class>
<init-param>
<param-name>imgWidth</param-name>
<param-value>80</param-value>
</init-param>
<init-param>
<param-name>imgHeight</param-name>
<param-value>25</param-value>
</init-param>
<init-param>
<param-name>codeLength</param-name>
<param-value>4</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>imgServlet</servlet-name>
<url-pattern>/servlet/imgServlet</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
Hibernate中数据检索方法的比较
query:使用hsql语句,可以设置参数是常用的一种方式
criteria:尽量避免了写hql语句,看起来更面向对象了。
get和load方式是根据id取得一个记录。
1、从返回结果上对比:
load方式检索不到的话会抛出org.hibernate.ObjectNotFoundException异常
get方法检索不到的话会返回null
2、从检索执行机制上对比:
get方法是直接从数据库中检索,而load方法的执行则比较复杂:
1,首先查找session的persistent Context中是否有缓存,如果有则直接返回
2,如果没有则判断是否是lazy,如果不是直接访问数据库检索,查到记录返回,查不到抛出异常
3,如果是lazy则需要建立代理对象,对象的initialized属性为false,target属性为null
4, 在访问获得的代理对象的属性时,检索数据库,如果找到记录则把该记录的对象复制到代理对象的target上,并将initialized=true,如果找不到就抛出异常。
JSP中出现According to TLD or attribute directive in tag file, attribute value does not accept any expressions
应用部署运行的时候出现JSP异常, 发生在使用JSTL库的时候: According to TLD or attribute directive in tag file, attribute value does not accept any expressions, 可能是因为使用了JSP2.0版本, 同时又没有使用JSTL core库的备用版本(RT库), 以下有两种处理方法:
第一种:修改web.xml文件
原来的
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
修改后
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web
Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
第二种:使用JSTL core RT库
JSTL core库的有两种taglib伪指令, 其中RT库即是依赖于JSP传统的请求时属性值,
而不是依赖于EL来实现(称为EL库.JSP2.0将支持EL)
JSP中使用<%@ taglib uri=http://java.sun.com/jstl/core
prefix="c"%>在2.3版本都可以,在2.4就不行了, 难道是版本不兼容吗?
只要将<%@ taglib uri="http://java.sun.com/jstl/core"
prefix="c"%>
改为<%@ taglib uri="http://java.sun.com/jstl/core_rt"
prefix="c"%>
由于我自己也遇上这问题
本文来源于互联网上
作者:佚名 来源:希赛网 标题:Java和JSP编程的六个常见问题
1.对应String类型的对象使用println()方法时,如果对象为null,将打印null而不是引发NullPointerException,由此引用的问题是容易造成错觉,对于以后对字符串的操作容易引起问题。
2.引发NullPointerException异常,主要原因是没有对对象的存在性进行验证,在jsp编程中经常出现:
if (request.getParameter(“username”)。 equals(“xxx”)) out.println(session.getAttribute(“record”))等。解决这个问题的方法是在使用前进行判空比较:
CODE:
if (request.getParameter(“username”)!=null)
{if if (request.getParameter(“username”).
equals(“xxx”))…}
3.引发NumberFormatException异常:主要原因是将用户提交的内容转换为整数或者浮点数时用户输入了其它非法字符。处理的主要方式是在需要进行转换的地方使用try/catch块捕获此异常然后提示用户输入合法数据。
4.引发StringIndexOutOfBoundsException异常:主要原因是使用String的substring()、charAt()等方法,而字符串的长度不够,就会引发此异常;在字符串为null时也会引发NullPointerException.解决的方法是判空,判断长度或者转换为字节数组。考虑到这些操作很多,可以将之封装到javabean中。
5.引发NoClassDefFoundError错误,主要原因是类路径或者类文件放置错误,类文件的放置要符合服务器的要求。
6.引发java.lang.Error错误,主要原因是对系统所访问外部资源,未执行关闭操作,导致外部资源大量浪费,最终可能导致系统无法正常运行;对系统所访问的外部资源关闭次数太多,外部系统无法正常处理;所系统访问的外部资源出现异常情况。
解决的方法是:访问外部资源前,首先检查该资源(如数据库)是否可正常连接或操作;访问外部资源时,如果进行了连接,一定进行关闭操作,并仅进行一次关闭操作;尽量在同一操作中共享外部资源,以减少该操作对资源的消费,提高程序的执行效率。
作者:Bakul L. Patel 来源:developerWorks 标题:用 JSON 处理缓存
数据验证是每个企业 Web 应用程序中最富于挑战性、日新月异的部分。通常验证元数据会使 JavaScript 模块中混入服务器端代码。在本文中,您将了解如何在服务器代码的帮助下将元数据缓存在客户端的优秀方法,服务器代码将提供 JSON(JavaScript Object Notation)形式的字符串化元数据。这种方法还允许以类似 Ajax 的方式来处理多值和多组属性。
每个应用程序的开发都是为了解决某个领域的问题。而每个领域都有自己的一套约束数据的规则和规范。应用程序将这些约束应用于数据时,约束也就成了验证。所有应用程序都需要验证用户输入的数据。
目前,应用程序一般都使用 if-else 语句组合来验证数据。这些语句包含了开发人员硬编码或通过服务器端代码置入的验证数据。通常,开发人员会使用服务器端代码来避免可能导致 JavaServer Page(JSP)的细微数据更改。
您可以使用 JavaScript Object Notation(JSON)来分组和缓存元数据,并使用 JavaScript 函数来访问元数据以验证用户输入。
JavaScript 中有分散的元数据时,您无法控制服务器将评估多少数据以及有多少数据传递到客户机。所有服务器端代码片段都将被评估并发送到服务器上。但是,使用 JSON 缓存数据时,您可以完全控制向客户机发送的元数据量,因为服务器端代码将生成 JSON 形式的元数据。这有助于仅将元数据发送至与看到或输入数据的用户相对应的客户机上。
您还可以使用 JSON 来缓存用户输入的数据。程序缓存数据后,将擦除数据字段而不是刷新屏幕,这与 Ajax 类似。通过这种方法,用户可以为同一属性输入另一组数据。
让我们一起来探究一下如何使用 JSON 来缓存元数据。
JSON 概览
使用 JSON(即 JavaScript Object Notation),将以一种特定的字符串形式来表示 JavaScript 对象。如果将具有这样一种形式的字符串赋给任意一个 JavaScript 变量,该变量随后将引用一个通过指定给该变量的字符串构建的对象。
例如,假定有一个 policy 对象,它拥有以下属性: 计划名称 描述 持续时间 您可以使用以下这种 JSON 形式的字符串来表示该 policy 对象:
CODE:policy 对象
{
"Plane" : { "Full Life Cover" },
"Description" : { "The best life insurance plan" },
"Term" : { "20 years" }
}
如果将此字符串赋给任意一个 JavaScript 变量,则该变量将接受以这种对象为单位的数据。要访问数据,请提供需要访问的属性所在的路径。对于本例,将以上字符串赋给一个名为 policy 的变量:
CODE:policy 的变量
var policy = {
"Plane" : { "Full Life Cover" },
"Description" : { "The best life insurance plan" },
"Term" : { "20 years" }
}
将此字符串粘贴到 HTML 页面的标题部分中,然后编写以下警报:
如果在任何支持 JavaScript 的浏览器中查看此页面,您都会看到显示策略计划的警报。
示例 为了演示 JSON 的性能,我们来看一个有 vehicle 对象列表的 person 对象 和一个可以拥有一台或多台车辆的 person 对象。每台车辆都有以下属性: 品牌 注册码 CC 浏览器 UI 应当允许用户添加多台具有优秀应用性能的车辆(通常为固有要求)。 每个属性都有一些与之关联的限制或验证规则。 您需要指定以下规则: 品牌名称 品牌名称决不能包含数字。 品牌名称最多可包含两个单词,中间可加一个空格。 注册码 注册码必须全都是数字。 CC CC 必须全都是数字。 CC 的最小值为 50,最大值为 5000。
将有三个与车辆属性相对应的输入字段,用户可在其中输入信息。接下来,您将看到如何将验证消息分组到 JSON 组中以及如何访问这些验证消息。
传统方法
现在,当用户输入的车辆数据为 40CC 时,程序必须显示一条消息,说明输入的数据不在有效的 CC 范围内。您可以用 清单 1 中的代码简单地显示这条消息:
CODE:清单 1. 传统代码
if(cc < <%= minCC %> || cc > <%= maxCC %>) {
alert(<%= ResourceList.vehicleCCRangeMsg >);
}
ResourceList 是一个服务器端类,该类中含有关于车辆的国际化消息(如 vehicleCCRangeMsg)。这种方法解决问题时略显混乱:
在这种方法中,您将把服务器端代码添加到所有客户端验证函数中,以检查条件并显示消息。
如果更改了元数据和消息(例如服务器端类或变量)的组织方法,您将会为更改使用这些元数据和消息的客户机脚本验证函数感到十分头痛。
JSON 能帮助您做什么?
如果只需在条件语句和警报中引用一个 JavaScript 变量而不是服务器端代码,您感觉怎么样?不需要把服务器端代码包含在 JavaScript 中,而保存的服务器端元数据和消息中的更改也不会影响客户端脚本。这种方法太棒了,是不是?好的,那就是使用基于 JSON 缓存元数据时要做的。
您将使用一个 JavaScript 对象把我们的验证数据和消息分组到一个层级中。然后就像访问层级的 JavaScript 对象一样访问这些消息。就是这样,您已经做到了!
当此 JSON 元数据对象就绪后,先前的 JavaScript 代码片段将类似于 清单 2。
CODE:清单 2. 带有 JSON 元数据缓存对象的警报
if(cc < vehicleValidationsMetadata.CC.minCC ||
cc > vehicleValidationsMetadata.CC.maxCC) {
alert(vehicleValidationsMetadata.CC.RangeMessage);
}
现在,问题是谁来准备 JSON 元数据对象?嗯,只有服务器能做这项工作。服务器必须生成这个 JSON 对象,并将其提供给客户机(浏览器)。一些 Java API 可以帮助您准备此类(事实上是任意一类)JSON 对象。请参阅 参考资料 来查看那些 API。
生成 JSON 元数据对象的典型方法为:
为实体及其验证消息准备一个层级 Java 对象。
对这些实体及其验证消息调用 toString()。这些实体及其验证消息最有可能把一个 JSON 形式的字符串提供给您。
将该字符串另存到一个请求范围内。
在 JSP 中,获取该字符串,并将其指派到 JavaScript 变量值的大括号内。
最终的车辆元数据对象看上去就会像 清单 3 一样。
CODE:清单 3. 验证元数据 JSON 对象
var vehicleValidationsMetadata = {
"BrandName":{
"CanContainDigits":{false},
"MaxWords":{2},
"FormatMessage":{"Brand Name cannot contain digits."},
"WordLimitMessage":{"Brand Name cannot contain more than two words"}
},
"RegistrationNumber":{
"CanContainAlphabets":{false},
"CanContainDigits":{"true"},
"FormatMessage":{"Registration Number can contain only digits."}
},
"CC":{
"minCC":{50},
"maxCC":{5000},
"FormatMessage":{"CC can only be numeric"},
"RangeMessage":{"CC can be within range of 50 and 5000"}
}
}
服务器必须生成整个字符串,第一行和最后一行除外,因为当前的用户语言环境可能要求使用这些消息(并且只有服务器端代码能完成这项工作)。在这里,需要注意的一点是此元数据对象仅用于验证车辆。更理想的情况是将 vehicle 元数据对象封装到 person 元数据对象中。那样,您就不需要再创建另一个 JavaScript 变量,而只需将该元数据对象包含到 person 元数据对象中。
在将此元数据对象准备好后,您可以使用该对象中的元数据和消息来验证数据输入和显示消息。现在,验证车辆输入信息的 JavaScript 函数看上去就会跟 清单 4 一样。
CODE:清单 4. 车辆数据验证函数
function validateVehicleData() {
var brandName = //get brand name from form field
var registrationNumber = //get Registration Number from form field.
var CC = //get CC from form field
var brandNameTokens = brandName.split(' ');
if(brandNameTokens.length > vehicleValidationsMetadata.BrandName.MaxWords) {
alert(vehicleValidationMessages.BrandName.WordLimitMessage);
}
.
.
.
if((!vehicleValidationsMetadata.RegistrationNumber.CanContainAlphabets) &&
isNaN(parseInt(registrationNumber))) {
alert(vehicleValidationMessages.RegistrationNumber.FormatMessage);
}
var ccNum = parseInt(CC);
if(ccNum < vehicleValidationMessages.CC.minCC ||
ccNum > vehicleValidationMessages.CC.maxCC) {
alert(vehicleValidationMessages.CC.RangeMessage);
}
}
这段代码看上去是不是好多了?它没有在 JavaScript 中混入服务器代码。如果服务器端更改存储元数据的方法,则无需再重写客户机脚本。这会使 JSP 编程人员的日子更轻松些。
扩展客户端数据缓存
某些 Web 应用程序要求用户为同一个属性或对象输入多个数据。例如,person-vehicle 要求人员为其拥有的每台车辆都输入数据。如果此人拥有多台车辆,应用程序必须允许输入多台车辆的数据。我将把此类对象作为一个 多组属性 来引用。如果多组属性包含任何可以保存多个数据实例的属性,我将称之为 多值属性。
现在,多组属性和多值属性面临的问题是必须将数据输入到相同的输入字段中。那意味着在输入第二台车辆的数据之前,必须先保存已输入的第一台车辆的数据。您可以通过两种方法来解决此问题:
将第一台车辆的数据发送到服务器上并清空输入字段,以允许用户输入下一台车辆的数据。
将数据缓存到客户机上并清空输入字段,以允许用户输入下一台车辆的数据。
第一种方法存在的问题是每输入一台车辆的数据就需要访问一次服务器。这不太好;如果在输入车辆数据后都必须等待服务器响应,用户会觉得很失望。换种方法,第二种方法的响应时间几乎为零。用户可以快速输入所有车辆数据而无需等待。但这里需要考虑的是如何将数据存储到客户端上。这里有更多方法可将数据存储到客户机上:
在用户单击以添加下一台车辆的数据时将数据以某种形式缓存到隐藏的表字段中。
将数据缓存到一个 JavaScript 对象中。
如果要将数据存储到隐藏字段中,您会为用户每次输入新的车辆数据都要处理很多隐藏字段或处理隐藏字段数据而感到烦恼。这就像有字符串操作就需要频繁处理字符串一样。
但是第二种缓存数据的方法提供了一种面向对象的方法来缓存。当用户输入新车辆数据时,您将在数组对象中创建一个新元素。不需要任何笨拙的字符串操作。当用户输完所有车辆数据后,您只需构建一个源于该对象的 JSON 字符串,并通过存储到某个隐藏字段中的方式将该字符串发送至服务器。这种方法要比第一种方法好得多。
JSON、数据缓存和 Ajax 功能
当使用 JSON 将数据缓存到客户端时,系统将在用户每次单击 Add Vehicle 按钮时更新数据缓存对象。用于完成此项任务的 JavaScript 函数看起来可能跟 清单 5 一样。
CODE:清单 5. 用于将车辆数据添加到 JavaScript 对象中以进行客户端缓存的函数
function addVehicleData() {
var brand = //get vehicle brand;
var regNo = //get registration number;
var cc = //get cc;
vehicleData[vehicleData.length] = new Object();
vehicleData[vehicleData.length].brandName = new Object();
vehicleData[vehicleData.length].brandName = brand;
//same way update other two properties
}
在这里,vehicleData 是用于在用户装入页面时进行初始化的 JavaScript 变量。它被初始化为一个新的数组对象,该数组对象为空或者含有用户先前输入的车辆的车辆元素。
当此函数将数据保存到 JavaScript 对象中后,程序可以调用另一个函数来清空输入字段以允许用户输入新数据。
在此类应用程序中,要求用户输入出现次数最少或出现次数最多的多组或多值属性。您可以将这些限制置入 JSON 元数据对象中。在这种情况下,先前的元数据对象将变为 清单 6 中所示的代码。
CODE:清单 6. 带有出现次数限制的 JSON 元数据对象
var vehicleValidationsMetadata = {
"MIN_OCC":{0},
"MAX_OCC":{10},
"MAX_OCC_MSG":{"...."},
"MIN_OCC_MSG":{".....},
//Everything else is the same
}
然后,addVehicleData() 函数将先验证数据的出现次数,然后在仅当总出现次数未超出允许的限制时再将数据添加到 JavaScript 对象中。清单 7 显示了检查方法。
CODE:清单 7. JSON 元数据对象限制检查
function addVehicleData() {
if(vehicleData.length == vehicleValidationsMetadata.MAX_OCC-1) {
alert(vehicleValidationsMetadata.MAX_OCC_MSG);
}
//Everything else is the same
}
当用户提交一个页面时调用的函数实际上用于验证最少的出现次数。这种方法的最大好处是屏幕不需要刷新以输入新车辆数据。提供此类静态屏幕曾经是 Ajax 技术的主要目标,而您现在用 JSON 也能完成此目标。这是关于更新 JSON 数据对象和通过 JavaScript 处理 HTML DOM 树的全部内容。用户响应时间是最小值,因为所有操作仅在客户端上执行。您可以使用 JSON 来为应用程序提供 Ajax 功能。
当用户单击 Save 按钮时,程序将调用另一个 JavaScript 函数,该函数将把此 JSON 对象 字符串化 并将其存储到程序提交到服务器上的隐藏表字段中。JSON.js(请参阅 参考资料)有一个 JSON.stringify() 函数,该函数将获取 JavaScript 对象作为输入并返回字符串输出。
服务器端必须能够理解 JSON 形式的字符串并生成一个服务器端对象,以处理和保存数据。Web 站点 http://www.json.org/java/index.html 提供了一个 Java API,该 API 用于处理基于 Java 的应用程序的大部分需求。
您在本文中看到了 JSON 的强大用途。归结如下: JSON 提供了一种优秀的面向对象的方法,以便将元数据缓存到客户机上。 JSON 帮助分离了验证数据和逻辑。 JSON 帮助为 Web 应用程序提供了 Ajax 的本质。
作者:雪儿 来源:bbs.jishu.me 标题:Silverlight .XAML切换场景 参数传递
问题: 1. page.xaml第一个场景 1. scene2.xaml第二个场景 在资源管理器中增加了一个scene2.xaml文件, 而Silverlight Application默认是启动的Page.xaml, 而不会放完page.xaml后播放scene2.xaml文件内容。 这时如何才能全新的进入第二个scene2.xaml文件呢? 分析 如果在page.xaml场景里的某个事件,不管是storyboard.Completed放完事件, 还是按扭点击事件里让当前的跟控件换成scene2控件,事实上sl把跟控件作为场景。
CODE:C# Code
//通过接口调用UserControl的跟节点,如果不合用此接口,会执行几次后失败!
public interface IContent
{
UIElement Content { get; set; }
}
public partial class Page : UserControl,IContent
{
public Page()
{
InitializeComponent();
this.MouseLeftButtonDown += new MouseButtonEventHandler(Page_MouseLeftButtonDown);
}
void Page_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
//scene2是scene2.xaml,因为这里需要直接实例化,并把现在的跟节点替换为新页。
(Application.Current.RootVisual as IContent).Content = new scene2();
}
public new UIElement Content
{
get
{
return base.Content;
}
set
{
base.Content=value;
}
}
}
以上代码来自:WPF之家
作者:雪儿 来源:bbs.jishu.me 标题:Silverlight里C#绘制Path的方法
以下是C#代码
CODE:C# Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace slArrow
{
public partial class Page : UserControl
{
public Page()
{
InitializeComponent();
LayoutRoot.Loaded += new RoutedEventHandler(LayoutRoot_Loaded);
}
void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
{
drawArrow(new Point(300, 300));
}
public void drawArrow(Point endP)
{
double slopy;
double cosy;
double siny;
double Par = 8.0;
//slopy = Math.atan2((StartP.y-endP.y+20),(StartP.x-endP.x));
slopy=3.1415926;
cosy = Math.Cos(slopy);
siny = Math.Sin(slopy);
PathGeometry aPathGeometry = new PathGeometry();
arrowPath.Data = aPathGeometry;
aPathGeometry.Figures = new PathFigureCollection();
PathFigure aPathFigure = new PathFigure();
aPathFigure.StartPoint = endP;
LineSegment Line1 = new LineSegment();
LineSegment Line2 = new LineSegment();
LineSegment Line3 = new LineSegment();
Point p1 = new Point();
Point p2 = new Point();
Point p3 = new Point();
p1.X = endP.X + ( Par * cosy - ( Par / 2.0 * siny ) );
p1.Y = endP.Y + ( Par * siny + ( Par / 2.0 * cosy ) );
p2.X = endP.X + ( Par * cosy + Par / 2.0 * siny );
p2.Y = endP.Y - ( Par / 2.0 * cosy - Par * siny );
p3.X = endP.X;
p3.Y = endP.Y;
Line1.Point = p1;
Line2.Point = p2;
Line3.Point = p3;
aPathFigure.Segments.Add(Line1);
aPathFigure.Segments.Add(Line2);
aPathFigure.Segments.Add(Line3);
aPathGeometry.Figures.Add(aPathFigure);
}
}
}
以下代码放在XAML文档里边
CODE:XAML Code
<UserControl x:Class="slArrow.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
<Path x:Name="arrowPath" Stroke="Red" StrokeThickness="4"/>
</Grid>
</UserControl>
源码下载:下载地址
作者:杨芹勍 来源:博客园 标题:Delphi的JSON库 - DJSON- JSONTokener(下)
CODE:Delphi源代码:
{
Copyright (c) 2002 JSON.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
The Software shall be used for Good, not Evil.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
}
{
* A JSONTokener takes a source string and extracts characters and tokens from
* it. It is used by the JSONObject and JSONArray constructors to parse
* JSON source strings.
* @author JSON.org
* @version 2
}
unit JSONTokener;
interface
uses
SysUtils,
StrUtils,
AutoPtr,
JSONException;
type
TJSONTokener = class
private
fMyIndex: Integer;
fMySource: string;
public
constructor Create(aMySource: string); virtual;
procedure Back;
class function DeHexChar(c: Char): Integer;
function More: Boolean;
function Next: Char; overload;
function Next(c: Char): Char; overload;
function Next(n: Integer): string; overload;
function SyntaxError(aMsg: string): EJSONException;
function ToString: string; override;
function NextClean: Char;
function NextString(quote: Char): string;
function NextTo(d: Char): string; overload;
function NextTo(delimiters: string): string; overload;
function NextValue: IAutoPtr<TObject>;
function SkipTo(toc: Char): Char;
function SkipPast(tos: string): Boolean;
end;
implementation
uses
StringObject,
BooleanObject,
IntegerObject,
LongObject,
DoubleObject,
Utils,
JSONObject,
JSONArray;
{ TJSONTokener }
procedure TJSONTokener.Back;
begin
if fMyIndex > 0 then
Dec(fMyIndex);
end;
constructor TJSONTokener.Create(aMySource: string);
begin
inherited Create;
fMyIndex := 0;
fMySource := aMySource;
end;
class function TJSONTokener.DeHexChar(c: Char): Integer;
begin
if (c >= '0') and (c <= '9') then
Exit(Ord(c) - Ord('0'));
if (c >= 'A') and (c <= 'F') then
Exit(Ord(c) - (Ord('A') - 10));
if (c >= 'a') and (c <= 'f') then
Exit(Ord(c) - (Ord('a') - 10));
Result := -1;
end;
function TJSONTokener.More: Boolean;
begin
Result := fMyIndex < Length(fMySource);
end;
function TJSONTokener.Next(n: Integer): string;
var
i, j: Integer;
begin
i := fMyIndex;
j := i + Ord(n);
if j >= Length(fMySource) then
raise SyntaxError('Substring bounds error');
Inc(fMyIndex, n);
Result := SubString(fMySource, i, j);
end;
function TJSONTokener.NextClean: Char;
var
c: Char;
begin
while True do
begin
c := Next;
if Ord(c) = Ord('/') then
begin
case Next of
'/':
begin
repeat
c := Next;
until (Ord(c) = 13) or (Ord(c) = 10) or (Ord(c) = 0);
end;
'*':
begin
while True do
begin
c := Next;
if Ord(c) = 0 then
raise SyntaxError('Unclosed comment');
if Ord(c) = Ord('*') then
begin
if Ord(Next) = Ord('/') then
Break;
Back;
end;
end;
end;
else begin
Back;
Exit('/');
end;
end;
end
else if Ord(c) = Ord('#') then
begin
repeat
c := Next;
until (Ord(c) = 13) or (Ord(c) = 10) or (Ord(c) = 0);
end
else if (Ord(c) = 0) or (Ord(c) > Ord(' ')) then
begin
Exit(c);
end;
end;
end;
function TJSONTokener.NextString(quote: Char): string;
var
c: Char;
begin
while True do
begin
c := Next;
case c of
#0, #13, #10:
begin
raise SyntaxError('Unterminated string');
end;
#92: // ''
begin
c := Next;
case c of
'b': Result := Result + #8;
't': Result := Result + #9;
'n': Result := Result + #10;
'f': Result := Result + #12;
'r': Result := Result + #13;
'u': Result := Result + Char(StrToInt('$' + Next(4)));
'x': Result := Result + Char(StrToInt('$' + Next(2)));
else begin
Result := Result + c;
end;
end;
end;
else begin
if Ord(c) = Ord(quote) then
Exit;
Result := Result + c;
end;
end;
end;
end;
function TJSONTokener.NextTo(delimiters: string): string;
var
c: Char;
begin
while True do
begin
c := Next;
if (Pos(c, delimiters) >= 1) or (Ord(c) = 0) or
(Ord(c) = 13) or (Ord(c) = 10) then
begin
if Ord(c) <> 0 then
Break;
Exit(Trim(Result));
end;
Result := Result + c;
end;
end;
function TJSONTokener.NextValue: IAutoPtr<TObject>;
var
c, b: Char;
s, sb: string;
begin
c := NextClean;
case c of
'"', '''': Exit(TAutoPtr<TObject>.New(TStringObject.Create(NextString(c))));
'{':
begin
Back;
Exit(TAutoPtr<TObject>.New(TJSONObject.Create(Self)));
end;
'[', '(':
begin
Back;
Exit(TAutoPtr<TObject>.New(TJSONArray.Create(Self)));
end;
end;
{
/*
* Handle unquoted text. This could be the values true, false, or
* null, or it can be a number. An implementation (such as this one)
* is allowed to also accept non-standard forms.
*
* Accumulate characters until we reach the end of the text or a
* formatting character.
*/
}
b := c;
while (Ord(c) >= Ord(' ')) and (Pos(c, ',:]}/"[{;=#') < 1) do
begin
sb := sb + c;
c := Next;
end;
Back;
// If it is true, false, or null, return the proper value.
s := Trim(sb);
if Length(s) = 0 then
raise SyntaxError('Missing value');
if LowerCase(s) = 'true' then
Exit(TAutoPtr<TObject>.New(TBooleanObject.TRUE));
if LowerCase(s) = 'false' then
Exit(TAutoPtr<TObject>.New(TBooleanObject.FALSE));
if LowerCase(s) = 'null' then
Exit(TAutoPtr<TObject>.New(TJSONObject.NULL));
{
/*
* If it might be a number, try converting it. We support the 0- and 0x-
* conventions. If a number cannot be produced, then the value will just
* be a string. Note that the 0-, 0x-, plus, and implied string
* conventions are non-standard. A JSON parser is free to accept
* non-JSON forms as long as it accepts all correct JSON forms.
*/
}
if ((Ord(b) >= Ord('0')) and (Ord(b) <= Ord('9')))
or (Ord(b) = Ord('.'))
or (Ord(b) = Ord('-'))
or (Ord(b) = Ord('+')) then
begin
if Ord(b) = Ord('0') then
begin
if (Length(s) > 2) and ((s[2] = 'x') or (s[2] = 'X')) then
begin
try
Exit(TAutoPtr<TObject>.New(TIntegerObject.Create(
StrToInt('$' + SubString(s, 2)))));
except
// Ignore the error
end;
end
else
begin
try
Exit(TAutoPtr<TObject>.New(TIntegerObject.Create(
Utils.Base8(s))));
except
end;
end;
end;
try
Exit(TAutoPtr<TObject>.New(TIntegerObject.Create(
StrToInt(s))));
except
try
Exit(TAutoPtr<TObject>.New(TLongObject.Create(
StrToInt64(s))));
except
try
Exit(TAutoPtr<TObject>.New(TDoubleObject.Create(
StrToFloat(s))));
except
Exit(TAutoPtr<TObject>.New(TStringObject.Create(s)));
end;
end;
end;
end;
Exit(TAutoPtr<TObject>.New(TStringObject.Create(s)));
end;
function TJSONTokener.NextTo(d: Char): string;
var
c: Char;
begin
while True do
begin
c := Next;
if (Ord(c) = Ord(d)) or (Ord(c) = 0) or (Ord(c) = 13) or (Ord(c) = 10) then
begin
if Ord(c) <> 0 then
Break;
Exit(Trim(Result));
end;
Result := Result + c;
end;
end;
function TJSONTokener.SkipPast(tos: string): Boolean;
begin
fMyIndex := PosEx(tos, fMySource, fMyIndex) - 1;
if fMyIndex < 0 then
begin
fMyIndex := Length(fMySource);
Exit(False);
end;
Inc(fMyIndex, Length(tos));
Result := True;
end;
function TJSONTokener.SkipTo(toc: Char): Char;
var
c: Char;
index: Integer;
begin
index := fMyIndex;
repeat
c := Next;
if Ord(c) = 0 then
begin
fMyIndex := index;
Exit(c);
end;
until Ord(c) = Ord(toc);
Back;
Result := c;
end;
function TJSONTokener.SyntaxError(aMsg: string): EJSONException;
begin
Result := EJSONException.Create(aMsg + ToString);
end;
function TJSONTokener.ToString: string;
begin
Result := ' at character ' + IntToStr(fMyIndex) + ' of ' + fMySource;
end;
function TJSONTokener.Next(c: Char): Char;
var
n: Char;
begin
n := Next;
if Ord(n) <> Ord(c) then
raise EJSONException.Create('Expected ''' + c + ''' and instead saw ''' + n + '''');
Result := n;
end;
function TJSONTokener.Next: Char;
var
c: Char;
begin
if More then
begin
c := fMySource[fMyIndex];
Inc(fMyIndex);
Exit(c);
end;
Result := #0;
end;
作者:杨芹勍 来源:博客园 标题:Delphi的JSON库 - DJSON- JSONTokener(上)
1、Java支持垃圾回收,Delphi不支持,在此我使用Delphi中的智能指针替代。 2、Java中有Boolean、Integer、Long等类,Delphi没有, 我便按照Java的方法分别创建了TBooleanObject、TIntegerObject、TLongObject等类。 3、在C语法和Pascal语法之间切换,头有点疼…… 但我已下定决心把DJson做完! 现在用Delphi的人不多,原因有两点: 1、公司管理层的问题。 2、关于Delphi相关成熟的库太少。 既然第一点已经无法挽回,那就让我们在第二点上做努力吧!
CODE:首先贴出Java源代码
1package org.json;
2
3/**//*
4 * Copyright (c) 2002 JSON.org
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * The Software shall be used for Good, not Evil.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * SOFTWARE.
25 */
26
27/**
28 * A JSONTokener takes a source string and extracts characters and tokens from
29 * it. It is used by the JSONObject and JSONArray constructors to parse
30 * JSON source strings.
31 * @author JSON.org
32 * @version 2
33 */
34public class JSONTokener {
35
36 /** *//**
37 * The index of the next character.
38 */
39 private int myIndex;
40
41
42 /** *//**
43 * The source string being tokenized.
44 */
45 private String mySource;
46
47
48 /** *//**
49 * Construct a JSONTokener from a string.
50 *
51 * @param s A source string.
52 */
53 public JSONTokener(String s) {
54 this.myIndex = 0;
55 this.mySource = s;
56 }
57
58
59 /** *//**
60 * Back up one character. This provides a sort of lookahead capability,
61 * so that you can test for a digit or letter before attempting to parse
62 * the next number or identifier.
63 */
64 public void back() {
65 if (this.myIndex > 0) {
66 this.myIndex -= 1;
67 }
68 }
69
70
71
72 /** *//**
73 * Get the hex value of a character (base16).
74 * @param c A character between '0' and '9' or between 'A' and 'F' or
75 * between 'a' and 'f'.
76 * @return An int between 0 and 15, or -1 if c was not a hex digit.
77 */
78 public static int dehexchar(char c) {
79 if (c >= '0' && c <= '9') {
80 return c - '0';
81 }
82 if (c >= 'A' && c <= 'F') {
83 return c - ('A' - 10);
84 }
85 if (c >= 'a' && c <= 'f') {
86 return c - ('a' - 10);
87 }
88 return -1;
89 }
90
91
92 /** *//**
93 * Determine if the source string still contains characters that next()
94 * can consume.
95 * @return true if not yet at the end of the source.
96 */
97 public boolean more() {
98 return this.myIndex < this.mySource.length();
99 }
100
101
102 /** *//**
103 * Get the next character in the source string.
104 *
105 * @return The next character, or 0 if past the end of the source string.
106 */
107 public char next() {
108 if (more()) {
109 char c = this.mySource.charAt(this.myIndex);
110 this.myIndex += 1;
111 return c;
112 }
113 return 0;
114 }
115
116
117 /** *//**
118 * Consume the next character, and check that it matches a specified
119 * character.
120 * @param c The character to match.
121 * @return The character.
122 * @throws JSONException if the character does not match.
123 */
124 public char next(char c) throws JSONException {
125 char n = next();
126 if (n != c) {
127 throw syntaxError("Expected '" + c + "' and instead saw '" +
128 n + "'");
129 }
130 return n;
131 }
132
133
134 /** *//**
135 * Get the next n characters.
136 *
137 * @param n The number of characters to take.
138 * @return A string of n characters.
139 * @throws JSONException
140 * Substring bounds error if there are not
141 * n characters remaining in the source string.
142 */
143 public String next(int n) throws JSONException {
144 int i = this.myIndex;
145 int j = i + n;
146 if (j >= this.mySource.length()) {
147 throw syntaxError("Substring bounds error");
148 }
149 this.myIndex += n;
150 return this.mySource.substring(i, j);
151 }
152
153
154 /** *//**
155 * Get the next char in the string, skipping whitespace
156 * and comments (slashslash, slashstar, and hash).
157 * @throws JSONException
158 * @return A character, or 0 if there are no more characters.
159 */
160 public char nextClean() throws JSONException {
161 for (;;) {
162 char c = next();
163 if (c == '/') {
164 switch (next()) {
165 case '/':
166 do {
167 c = next();
168 } while (c != 'n' && c != 'r' && c != 0);
169 break;
170 case '*':
171 for (;;) {
172 c = next();
173 if (c == 0) {
174 throw syntaxError("Unclosed comment");
175 }
176 if (c == '*') {
177 if (next() == '/') {
178 break;
179 }
180 back();
181 }
182 }
183 break;
184 default:
185 back();
186 return '/';
187 }
188 } else if (c == '#') {
189 do {
190 c = next();
191 } while (c != 'n' && c != 'r' && c != 0);
192 } else if (c == 0 || c > ' ') {
193 return c;
194 }
195 }
196 }
197
198
199 /** *//**
200 * Return the characters up to the next close quote character.
201 * Backslash processing is done. The formal JSON format does not
202 * allow strings in single quotes, but an implementation is allowed to
203 * accept them.
204 * @param quote The quoting character, either
205 * " (double quote) or
206 * ' (single quote).
207 * @return A String.
208 * @throws JSONException Unterminated string.
209 */
210 public String nextString(char quote) throws JSONException {
211 char c;
212 StringBuffer sb = new StringBuffer();
213 for (;;) {
214 c = next();
215 switch (c) {
216 case 0:
217 case 'n':
218 case 'r':
219 throw syntaxError("Unterminated string");
220 case '':
221 c = next();
222 switch (c) {
223 case 'b':
224 sb.append('b');
225 break;
226 case 't':
227 sb.append('t');
228 break;
229 case 'n':
230 sb.append('n');
231 break;
232 case 'f':
233 sb.append('f');
234 break;
235 case 'r':
236 sb.append('r');
237 break;
238 case 'u':
239 sb.append((char)Integer.parseInt(next(4), 16));
240 break;
241 case 'x' :
242 sb.append((char) Integer.parseInt(next(2), 16));
243 break;
244 default:
245 sb.append(c);
246 }
247 break;
248 default:
249 if (c == quote) {
250 return sb.toString();
251 }
252 sb.append(c);
253 }
254 }
255 }
256
257
258 /** *//**
259 * Get the text up but not including the specified character or the
260 * end of line, whichever comes first.
261 * @param d A delimiter character.
262 * @return A string.
263 */
264 public String nextTo(char d) {
265 StringBuffer sb = new StringBuffer();
266 for (;;) {
267 char c = next();
268 if (c == d || c == 0 || c == 'n' || c == 'r') {
269 if (c != 0) {
270 back();
271 }
272 return sb.toString().trim();
273 }
274 sb.append(c);
275 }
276 }
277
278
279 /** *//**
280 * Get the text up but not including one of the specified delimeter
281 * characters or the end of line, whichever comes first.
282 * @param delimiters A set of delimiter characters.
283 * @return A string, trimmed.
284 */
285 public String nextTo(String delimiters) {
286 char c;
287 StringBuffer sb = new StringBuffer();
288 for (;;) {
289 c = next();
290 if (delimiters.indexOf(c) >= 0 || c == 0 ||
291 c == 'n' || c == 'r') {
292 if (c != 0) {
293 back();
294 }
295 return sb.toString().trim();
296 }
297 sb.append(c);
298 }
299 }
300
301
302 /** *//**
303 * Get the next value. The value can be a Boolean, Double, Integer,
304 * JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object.
305 * @throws JSONException If syntax error.
306 *
307 * @return An object.
308 */
309 public Object nextValue() throws JSONException {
310 char c = nextClean();
311 String s;
312
313 switch (c) {
314 case '"':
315 case ''':
316 return nextString(c);
317 case '{':
318 back();
319 return new JSONObject(this);
320 case '[':
321 case '(':
322 back();
323 return new JSONArray(this);
324 }
325
326 /**//*
327 * Handle unquoted text. This could be the values true, false, or
328 * null, or it can be a number. An implementation (such as this one)
329 * is allowed to also accept non-standard forms.
330 *
331 * Accumulate characters until we reach the end of the text or a
332 * formatting character.
333 */
334
335 StringBuffer sb = new StringBuffer();
336 char b = c;
337 while (c >= ' ' && ",:]}/"[{;=#".indexOf(c) < 0) {
338 sb.append(c);
339 c = next();
340 }
341 back();
342
343 /**//*
344 * If it is true, false, or null, return the proper value.
345 */
346
347 s = sb.toString().trim();
348 if (s.equals("")) {
349 throw syntaxError("Missing value");
350 }
351 if (s.equalsIgnoreCase("true")) {
352 return Boolean.TRUE;
353 }
354 if (s.equalsIgnoreCase("false")) {
355 return Boolean.FALSE;
356 }
357 if (s.equalsIgnoreCase("null")) {
358 return JSONObject.NULL;
359 }
360
361 /**//*
362 * If it might be a number, try converting it. We support the 0- and 0x-
363 * conventions. If a number cannot be produced, then the value will just
364 * be a string. Note that the 0-, 0x-, plus, and implied string
365 * conventions are non-standard. A JSON parser is free to accept
366 * non-JSON forms as long as it accepts all correct JSON forms.
367 */
368
369 if ((b >= '0' && b <= '9') || b == '.' || b == '-' || b == '+') {
370 if (b == '0') {
371 if (s.length() > 2 &&
372 (s.charAt(1) == 'x' || s.charAt(1) == 'X')) {
373 try {
374 return new Integer(Integer.parseInt(s.substring(2),
375 16));
376 } catch (Exception e) {
377 /**//* Ignore the error */
378 }
379 } else {
380 try {
381 return new Integer(Integer.parseInt(s, 8));
382 } catch (Exception e) {
383 /**//* Ignore the error */
384 }
385 }
386 }
387 try {
388 return new Integer(s);
389 } catch (Exception e) {
390 try {
391 return new Long(s);
392 } catch (Exception f) {
393 try {
394 return new Double(s);
395 } catch (Exception g) {
396 return s;
397 }
398 }
399 }
400 }
401 return s;
402 }
403
404
405 /** *//**
406 * Skip characters until the next character is the requested character.
407 * If the requested character is not found, no characters are skipped.
408 * @param to A character to skip to.
409 * @return The requested character, or zero if the requested character
410 * is not found.
411 */
412 public char skipTo(char to) {
413 char c;
414 int index = this.myIndex;
415 do {
416 c = next();
417 if (c == 0) {
418 this.myIndex = index;
419 return c;
420 }
421 } while (c != to);
422 back();
423 return c;
424 }
425
426
427 /** *//**
428 * Skip characters until past the requested string.
429 * If it is not found, we are left at the end of the source.
430 * @param to A string to skip past.
431 */
432 public boolean skipPast(String to) {
433 this.myIndex = this.mySource.indexOf(to, this.myIndex);
434 if (this.myIndex < 0) {
435 this.myIndex = this.mySource.length();
436 return false;
437 }
438 this.myIndex += to.length();
439 return true;
440
441 }
442
443
444 /** *//**
445 * Make a JSONException to signal a syntax error.
446 *
447 * @param message The error message.
448 * @return A JSONException object, suitable for throwing
449 */
450 public JSONException syntaxError(String message) {
451 return new JSONException(message + toString());
452 }
453
454
455 /** *//**
456 * Make a printable string of this JSONTokener.
457 *
458 * @return " at character [this.myIndex] of [this.mySource]"
459 */
460 public String toString() {
461 return " at character " + this.myIndex + " of " + this.mySource;
462 }
463}
作者:dudu 来源:http://www.cnblogs.com/dudu 标题:解读System.Web.UI.Page中关键方法ProcessRequestMain()
为了更好地优化博客园程序的性能,最近我在优化代码的同时,更深入地去研究asp.net的源代码。asp.net的源代码通过Reflector工具一鉴无遗, 虽然不是原版的代码, 但已经足够了,其中的原理与思想已经清楚地摆在我们面前。这是.NET开发人员的幸运!
在我们开发asp.net应用程序时, System.Web.UI.Page是我们最熟悉并用的最多的一个类。但有多少人真正对这个类的源代码仔细研究过? 从相关搜索中可以看出并不是很多, 比如,用Google搜索ProcessRequestMain方法中开始的“OnPageStartSessionObjects”,结果只有四个。
今天我花了半天时间,研究了Page中处理请求的最关键的方法:ProcessRequestMain(),在这里我将自己的理解写出来与大家共享,欢迎大家批评并指正。一切尽在代码注释 中:
注:为了方便阅读与理解,已去掉源代码中输出Trace信息的部分。
CODE:
public class Page
{
private void ProcessRequestMain()
{
try
{
if (this.IsInAspCompatMode)
{
AspCompatApplicationStep.OnPageStartSessionObjects();
}
//将当前Context的Session中的对象传递给asp的OnStartPage
//通过<%@ ASPCOMPAT="true" %>进行设置
//参考文章: http://samples.gotdotnet.com/quickstart/aspplus/doc/cominterop.aspx
this._requestValueCollection = this.DeterminePostBackMode();
//检查PostBackMode, 如果启用了PostBack, 获取VIEWSTATE数据并赋值给_requestValueCollection
base.InitRecursive(null);
//调用基类的InitRecursive方法通过递归对子控件进行初始化, 比如: 生成控件ID,设置控件的Page属性。
//OnInit()方法将会在此时被调用
if (this.IsPostBack)
{
this.LoadPageViewState();
//从_requestValueCollection通过反序列化载入视图状态数据,
//如果页面的Layout发生了改变,子控件重新递归载入(LoadViewStateRecursive)视图状态
//载入后,从视图状态数据从得到所有要处理PostBack的控件并注册到_controlsRequiringPostBack.
this.ProcessPostData(this._requestValueCollection, true);
//处理PostBack数据, 从PostBack数据中得到所有控件ID并检查每个控件,
//如果不能在当前页面中找到该控件(FindControl), 将其存入_leftoverPostData.
//如果存在该控件,继续检查,若该控件没有实现IPostBackDataHandler,
//但实现了 IPostBackEventHandler,注册该控件进行事件处理。
//若该控件实现了System.Web.UI.IPostBackDataHandler,
//该控件的LoadPostData()方法在此时被调用,并将其加入到_changedPostDataConsumers,
//并从._controlsRequiringPostBack(LoadPageViewState时对它进行了赋值)中移除该控件.
//这样就从_controlsRequiringPostBack中移除了所有实现IPostBackDataHandler接口的控件.
//接着继续对 _controlsRequiringPostBack中余下的控件进行处理,
//但奇怪的是又对这些余下的控件检查是否存在并实现了IPostBackDataHandler, 如果实现,
//调用该控件的LoadPostData()(有点多此一举了, 可能是Relector生成的代码有误)
//并放入_changedPostDataConsumers,如果没实现,放入一个新ArrayList变量,
//检查结束后,将其赋值给_controlsRequiringPostBack.
//那现在_controlsRequiringPostBack中剩下什么呢?没有实现IPostBackDataHandler,
//但实现了 IPostBackEventHandler的控件以及没有被Load的控件,
// 也就是在PostBack数据中存在但FindControl没有找到的控件。
//为什么会有找不到的控件呢?我们这里需要注意的是OnLoad()事件还没执行,
//有些控件还没有被加载.下面的base.LoadRecursive()就是触发OnLoad()事件的。
}
base.LoadRecursive();
//触发页面的OnLoad()事件->递归触发子控件的OnLoad()事件->将
//页面的_controlState状态设置为ControlState.Loaded
if (this.IsPostBack)
{
this.ProcessPostData(this._leftoverPostData, false);
//理解了ProcessPostData(this._requestValueCollection, true)之后,
//这个就很好理解了,就是检查_controlsRequiringPostBack中的控件是否存在并实现了
//IPostBackDataHandler, 如果实现,调用该控件的LoadPostData()方法并将其加入
//到_changedPostDataConsumers.ProcessPostData(this._leftoverPostData, false)
//这个方法就是为OnLoad()之后加载的控件服务的。
}
this.RaiseChangedEvents();
//在_changedPostDataConsumers(在两个ProcessPostData方法中向它添加了数据)
//中没有实现IPostBackDataHandler接口的控件触发RaisePostDataChangedEvent.
this.RaisePostBackEvent(this._requestValueCollection);
//触发_registeredControlThatRequireRaiseEvent及PostBack数据中
//实现IPostBackEventHandler接口的控件的RaisePostBackEvent事件。
base.PreRenderRecursiveInternal();
//首先调用EnsureChildControls,检查子控件是否创建,
//如果没有, 调用进行创建CreateChildControls.
//触发OnPreRende事件.
//递归调用子控件的PreRenderRecursiveInternal方法
//设置._controlState为 ControlState.PreRendered
this.SavePageViewState();
//保存视图状态数据至._viewStateToPersist
base.RenderControl(this.CreateHtmlTextWriter(this.Response.Output));
//输出当前及所有子控件的内容
}
catch (ThreadAbortException)
{
base.UnloadRecursive(true);
return;
}
catch (ConfigurationException)
{
throw;
}
catch (Exception exception1)
{
PerfCounters.IncrementCounter(AppPerfCounter.ERRORS_DURING_REQUEST);
PerfCounters.IncrementCounter(AppPerfCounter.ERRORS_TOTAL);
if (!this.HandleError(exception1))
{
throw;
}
return;
}
}
}
经过很长时间的延迟之后,微软今天终于发布了Silverlight 2的正式版本,也将这个RIA(富互联网应用)开发技术推向了新的一代。
微软.NET开发部副总裁Scott Guthrie表示,Silverlight诞生一年多来,已经走入全球四分之一的电脑,在美国超过30%,部分国家甚至达到了50%以上,并拥有150多家合作伙伴和数万个应用程序。
在北京奥运会期间,基于Silverlight技术的NBCOlympics.com接待了5000多万访客,创造了13亿PV,播放了7000万条视频流,总计长达1000万小时,网站的平均访问时间也从3分钟增至27分钟。法国的France Televisions SA、荷兰的NOS、俄罗斯的Sportbox.ru、意大利的RAI也都选择了Silverlight来在线提供奥运会报道。
Silverlight 2的主要新特性有:
1、广泛支持.NET Framework基础类库,亦即整个.NET框架的兼容子集。
2、强大的内置控件,包括DataGrid、ListBox、Slider、ScrollViewer、Calendar等等。
3、支持高级皮肤和模版,可以更轻松地创建应用程序界面和体验。
4、深度缩放(Deep Zoom):在查看高分辨率图片时只将当前显示部分发送到浏览器里而不是全部下载。
5、广泛的网络支持:标准HTTP、REST、WS*/SOAP、POX、RSS。
6、扩展.NET Framework语言支持:Visual Basic、C#、JavaScript、IronPython、IronRuby。
7、高级内容保护:集成基于PlayReady的Silverlight DRM数字版权管理技术。
8、跨平台跨浏览器支持:支持Windows和Mac OS操作系统,支持IE、Firefox和Safari浏览器。
9、流式下载能力、搜索引擎优化、新一代In-Stream广告技术。
Silverlight 2正式版下载地址:
http://www.microsoft.com/silverlight/default.aspx
作者:佚名 来源:ITPUB 标题:妙用异步Servlet扩展AJAX应用程序
作为Web应用程序模型的AJAX的出现使服务器端的面貌发生了巨大的变化。用户对着Web页面填写表单并单击提交按钮转到下一个链接的典型Web使用模式现在正在转变为更先进的客户端JavaScript以及功能更丰富的用户界面,只要对表单进行操作,比如单击一个复选框、按下一个键或将鼠标移到一个选项卡上,该用户界面就会不断地与服务器交互。
考虑一下从客户端传输到服务器的数据量有多大。从可用性的角度来看,用户在一个薄客户端浏览器上获得了富用户界面,无需安装任何东西。但是,当在服务器端扩展这些应用程序时就要付出代价了。AJAX应用程序的典型容量规划数可能会是标准Web应用程序的3到4倍。
有人可能会问:这对WebLogic Server有何影响?每个发送给WebLogic的HTTP请求都要使用一个执行线程。根据AJAX编程的性质以及许多短期的请求会以轮询的形式不断发送的情况,该行为模式可能造成大量客户端请求不断冲击服务器的局面。多年来,WebLogic都将这一问题考虑在内,并构建了一个相当棒的特性,即FutureResponseServlet。该范型构建于异步servlet理念的基础之上。从版本6.1开始,该功能就允许开发人员提供真正异步的来自服务器的通知,而无需对事件进行客户端轮训并在服务器端使用执行线程。在9.x之前,BEA还不急于公开该类。
如何在现实中利用该类呢?我们来看一个例子。假定业务需求是要构建一个基于Web的应用程序,该应用程序以近乎实时的方式向服务器发送数据而无需刷新浏览器。这样的应用程序可以向服务器提交一个需要花很长时间处理的请求,而仍然能够接收到关于其状态的异步事件并监听事件。从技术角度来看,这有许多实现方法。其中一种方法就是使用一个与Java Servlet通信的Java Applet来获得异步信息。这是一种不错的方法,但是对于用户来说有些不太方便,因为他们必须下载一个JVM,还要下载一个applet到浏览器。此外,还必须维护一个从客户端到服务器的持久性套接字连接,以便接收异步消息。设想一下,如果有1000个用户使用该applet,那么就有1000个执行线程几乎是在空等着发送事件通知到客户端。当然了,还有其它方法,比如从applet或AJAX应用程序构建轮询机制来定期检查新数据。而如果不经常接收到数据,那么轮询就显得无用了,而且还浪费了服务器资源,占用了执行线程。反之,服务器可以定期轮询,将事件传播回客户端,并维护套接字线程,而无需使用持久性执行线程。这非常类似于Java NIO的运行方式。理想情况下,我们都希望构建一个从服务器“异步”接收事件通知而无需在服务器端使用持久性执行线程的应用程序,不管它是一个applet还是一个基于AJAX的薄Web应用程序。
此问题的一种解决方案是创建一个扩展FutureResponseServlet类的servlet。浏览器建立了到FutureResponseServlet类的单一连接,并在另一个线程中将它自身注册为一个监听程序。只要在服务器端接收到一个事件,线程就向客户端通知该事件。服务器与客户端保持异步,无需使用持久性执行线程。该模型可扩展用于多个并发用户的情况。
本文并不打算介绍如何构建AJAX应用程序。这方面的文章已经有很多了。本文的重点在于讨论表示层(比如AJAX、applet或者任何前端应用程序)的异步处理的重要性。清单1展示了一个例子。
CODE:File Name
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.Stack;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import weblogic.servlet.FutureResponseServlet;
import weblogic.servlet.FutureServletResponse;
// An AsynchronousServlet that handles HTTP requests from a "separate" thread and
// not the execute thread used to invoke this servlet.
public class AsynchronousServerResponseServlet extends FutureResponseServlet {
private final Notifier notifier;
public AsynchronousServerResponseServlet() {
this.notifier = new Notifier();
this.notifier.start();
}
public void service(HttpServletRequest request, FutureServletResponse response)
throws IOException,ServletException {
// push this client's request to a buffer and return immediately.
// asynchronous processing occurs in the run method of the Notifier Thread
notifier.poll(request, response);
}
}
class Notifier extends Thread {
private static Stack clients = new Stack();
void poll (HttpServletRequest request, FutureServletResponse response) {
clients.push(new Client(request, response));
}
public void run() {
while (!clients.empty()) {
Client client = null;
try{
client = (Client) clients.pop();
PrintWriter pw = client.response.getWriter();
for(int j = 0; j < 10; j++) {
pw.println("Time is:" + new Date() + "");
pw.flush();
}
pw.close();
}
catch(Throwable t) {
t.printStackTrace();
}
finally {
try {
client.response.send();
}
catch(IOException ioe) {
ioe.printStackTrace();
}
}
}
}
}
// inner class that holds o-n to the clients http request and response
class Client {
private HttpServletRequest request;
private FutureServletResponse response;
private Client(HttpServletRequest request, FutureServletResponse response) {
this.request = request;
this.response = response;
}
}
可以看出,该例子非常简单。AsynchronousServerResponseServlet类扩展了FutureResponseServlet,并重写了service方法。只使用一个线程(即Notifier类)来处理所有的客户端连接响应。对于每个HTTP请求,servlet向Notifier线程注册套接字连接,然后返回。异步事件被交付给客户端,而持久性套接字连接被维持。
单个线程可管理多个客户端连接!run()方法可用于根据某种消息选择条件回调事件到客户端。该例子只执行了一个服务器端的push操作,有些过分简单了。线程池可被用于某些类型的事件处理。
总而言之,在处理长期运行的任务时,FutureResponseServlet是一个好特性,它允许开发人员提高性能,在独立的线程中处理响应,并将开销降至最低。在构建异步应用程序时,该方法支持可伸缩性.
来源:老赵点滴 作者:Jeffrey Zhao
想调用一个方法很容易,直接代码调用就行,这人人都会。其次呢,还可以使用反射。
不过通过反射调用的性能会远远低于直接调用——至少从绝对时间上来看的确是这样。
虽然这是个众所周知的现象,我们还是来写个程序来验证一下。比如我们现在新建一个Console应用程序,编写一个最简单的Call方法。
class Program
{
static void Main(string[] args)
{
}
public void Call(object o1, object o2, object o3) { }
}
Call方法接受三个object参数却没有任何实现,这样我们就可以让测试专注于方法调用,
而并非方法实现本身。于是我们开始编写测试代码,比较一下方法的直接调用与反射调用的性能差距:
static void Main(string[] args)
{
int times = 1000000;
Program program = new Program();
object[] parameters = new object[] { new object(), new object(), new object() };
program.Call(null, null, null); // force JIT-compile
Stopwatch watch1 = new Stopwatch();
watch1.Start();
for (int i = 0; i < times; i++)
{
program.Call(parameters[0], parameters[1], parameters[2]);
}
watch1.Stop();
Console.WriteLine(watch1.Elapsed + " (Directly invoke)");
MethodInfo methodInfo = typeof(Program).GetMethod("Call");
Stopwatch watch2 = new Stopwatch();
watch2.Start();
for (int i = 0; i < times; i++)
{
methodInfo.Invoke(program, parameters);
}
watch2.Stop();
Console.WriteLine(watch2.Elapsed + " (Reflection invoke)");
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
}
执行结果如下:
00:00:00.0119041 (Directly invoke)
00:00:04.5527141 (Reflection invoke)
Press any key to continue...
通过各调用一百万次所花时间来看,两者在性能上具有数量级的差距。
因此,很多框架在必须利用到反射的场景中,都会设法使用一些较高级的替代方案来改善性能。
例如,使用CodeDom生成代码并动态编译,或者使用Emit来直接编写IL。
不过自从.NET 3.5发布了Expression相关的新特性,我们在以上的情况下又有了更方便并直观的解决方案。
了解Expression相关特性的朋友可能知道,System.Linq.Expressions.Expression<TDelegate>
类型的对象在调用了它了Compile方法之后将得到一个TDelegate类型的委托对象,
而调用一个委托对象与直接调用一个方法的性能开销相差无几。那么对于上面的情况,
我们又该得到什么样的Delegate对象呢?
为了使解决方案足够通用,我们必须将各种签名的方法统一至同样的委托类型中,如下:
public Func<object, object[], object> GetVoidDelegate()
{
Expression<Action<object, object[]>> exp = (instance, parameters) =>
((Program)instance).Call(parameters[0], parameters[1], parameters[2]);
Action<object, object[]> action = exp.Compile();
return (instance, parameters) =>
{
action(action, parameters);
return null;
};
}
如上,我们就得到了一个Func<object, object[], object>类型的委托,
这意味它接受一个object类型与object[]类型的参数,以及返回一个object类型的结果——等等,
朋友们有没有发现,这个签名与MethodInfo类型的Invoke方法完全一致?
不过可喜可贺的是,我们现在调用这个委托的性能远高于通过反射来调用了。
那么对于有返回值的方法呢?那构造一个委托对象就更方便了:
public int Call(object o1, object o2) { return 0; }
public Func<object, object[], object> GetDelegate()
{
Expression<Func<object, object[], object>> exp = (instance, parameters) =>
((Program)instance).Call(parameters[0], parameters[1]);
return exp.Compile();
}
至此,我想朋友们也已经能够轻松得出调用静态方法的委托构造方式了。
可见,这个解决方案的关键在于构造一个合适的Expression,
那么我们现在就来编写一个DynamicExecuter类来作为一个较为完整的解决方案:
public class DynamicExecutor
{
private Func<object, object[], object> m_execute;
public DynamicExecutor(MethodInfo methodInfo)
{
this.m_execute = this.GetExecuteDelegate(methodInfo);
}
public object Execute(object instance, object[] parameters)
{
return this.m_execute(instance, parameters);
}
private Func<object, object[], object> GetExecuteDelegate(MethodInfo methodInfo)
{
// parameters to execute
ParameterExpression instanceParameter = Expression.Parameter(typeof(object), "instance");
ParameterExpression parametersParameter = Expression.Parameter(typeof(object[]), "parameters");
// build parameter list
List<Expression> parameterExpressions = new List<Expression>();
ParameterInfo[] paramInfos = methodInfo.GetParameters();
for (int i = 0; i < paramInfos.Length; i++)
{
// (Ti)parameters[i]
BinaryExpression valueObj = Expression.ArrayIndex(parametersParameter, Expression.Constant(i));
UnaryExpression valueCast = Expression.Convert(valueObj, paramInfos[i].ParameterType);
parameterExpressions.Add(valueCast);
}
// non-instance for static method, or ((TInstance)instance)
Expression instanceCast = methodInfo.IsStatic ? null :
Expression.Convert(instanceParameter, methodInfo.ReflectedType);
// static invoke or ((TInstance)instance).Method
MethodCallExpression methodCall = Expression.Call(instanceCast, methodInfo, parameterExpressions);
// ((TInstance)instance).Method((T0)parameters[0], (T1)parameters[1], ...)
if (methodCall.Type == typeof(void))
{
Expression<Action<object, object[]>> lambda = Expression.Lambda<Action<object, object[]>>(
methodCall, instanceParameter, parametersParameter);
Action<object, object[]> execute = lambda.Compile();
return (instance, parameters) =>
{
execute(instance, parameters);
return null;
};
}
else
{
UnaryExpression castMethodCall = Expression.Convert(methodCall, typeof(object));
Expression<Func<object, object[], object>> lambda = Expression.Lambda<Func<object, object[], object>>(
castMethodCall, instanceParameter, parametersParameter);
return lambda.Compile();
}
}
}
DynamicExecutor的关键就在于GetExecuteDelegate方法中构造Expression Tree的逻辑。
如果您对于一个Expression Tree的结构不太了解的话,
不妨尝试一下使用Expression Tree Visualizer来对一个现成的Expression Tree进行观察和分析。
我们将一个MethodInfo对象传入DynamicExecutor的构造函数之后,
就能将各组不同的实例对象和参数对象数组传入Execute进行执行。
这一切就像使用反射来进行调用一般,不过它的性能就有了明显的提高。例如我们添加更多的测试代码:
DynamicExecutor executor = new DynamicExecutor(methodInfo);
Stopwatch watch3 = new Stopwatch();
watch3.Start();
for (int i = 0; i < times; i++)
{
executor.Execute(program, parameters);
}
watch3.Stop();
Console.WriteLine(watch3.Elapsed + " (Dynamic executor)");
现在的执行结果则是:
00:00:00.0125539 (Directly invoke)
00:00:04.5349626 (Reflection invoke)
00:00:00.0322555 (Dynamic executor)
Press any key to continue...
事实上,Expression类型的Compile方法正是使用Emit来生成委托对象。
不过现在我们已经无需将目光放在更低端的IL上,只要使用高端的API来进行Expression Tree的构造,这无疑是一种进步。
不过这种方法也有一定局限性,例如我们只能对公有方法进行调用,
并且包含out/ref参数的方法,或者除了方法外的其他类型成员,我们就无法如上例般惬意地编写代码了。
补充
木野狐兄在评论中引用了Code Project的文章《A General Fast Method Invoker》,其中通过Emit构建了FastInvokeHandler委托对象
(其签名与Func<object, object[], object>完全相同)的调用效率似乎较“方法直接”调用的性能更高(虽然从原文示例看来并非如此)。
事实上FastInvokeHandler其内部实现与DynamicExecutor完全相同,居然有如此令人不可思议的表现实在让人啧啧称奇。
我猜测,FastInvokeHandler与DynamicExecutor的性能优势可能体现在以下几个方面:
范型委托类型的执行性能较非范型委托类型略低(求证)。
多了一次Execute方法调用,损失部分性能。
生成的IL代码更为短小紧凑。
木野狐兄没有使用Release模式编译。:P
不知道是否有对此感兴趣的朋友能够再做一个测试,不过请注意此类性能测试一定需要在Release编译下进行(这点很容易被忽视),否则意义其实不大。
此外,我还想强调的就是,本篇文章进行是纯技术上的比较,并非在引导大家追求点滴性能上的优化。
有时候看到一些关于比较for或foreach性能优劣的文章让许多朋友都纠结与此,甚至搞得面红耳赤,我总会觉得有些无可奈何。
其实从理论上来说,提高性能的方式有许许多多,记得当时在大学里学习Introduction to Computer System这门课时得一个作业就是为一段C程序作性能优化,
当时用到不少手段,例如内联方法调用以减少CPU指令调用次数、调整循环嵌套顺序以提高CPU缓存命中率,
将一些代码使用内嵌ASM替换等等,可谓“无所不用其极”,大家都在为几个时钟周期的性能提高而发奋图强欢呼雀跃……
那是理论,是在学习。但是在实际运用中,我们还必须正确对待学到的理论知识。
我经常说的一句话是:“任何应用程序都会有其性能瓶颈,只有从性能瓶颈着手才能做到事半功倍的结果。”
例如,普通Web应用的性能瓶颈往往在外部IO(尤其是数据库读写),
要真正提高性能必须从此入手(例如数据库调优,更好的缓存设计)。
正因如此,开发一个高性能的Web应用程序的关键不会在语言或语言运行环境上,.NET、RoR、PHP、Java等等在这一领域都表现良好。
Powered by Haiwit