CSS设计器代码参考.1

星期一, 五月 10th, 2004

这里对前面讲的CSS设计器系统关键代码作一些小结,如果没有看过前面文章请先参看前文
解析CSS样式文件

这段代码主要作用是把CSS文件分解为多个样式类,并按名称/文本属性生产ClassItem对象,并保存在一个ArrayList(cssList)中(C#代码)

//读取文件
 FileInfo theSource= new FileInfo (@m_filePath);
 StreamReader reader = theSource.OpenText();

 //将文件流转化为文本
 m_cssText = reader.ReadToEnd();
 reader.Close();

 //定义CSS文本分割符
 char[] delimiters = new char[] { '{','}'};
 int iCheck = 1;string className = null;

 //将文本转化为ArrayList
 foreach ( string substring in m_cssText.Split(delimiters))
 {
     if (iCheck%2==0)
         //当iCHeck为偶数时,字符串为样式属性内容 
         //将解析的样式名和属性作为ClassItem对象存入cssList        
         cssList.Add( new ClassItem ( className, substring.Trim() ) );

     else
         //当iCHeck为奇数时,字符串为样式名,暂存 
         className = substring.Trim(); iCheck++;
 }
 

交互界面构建

交互界面由Javascript通过XmlDocument读取Xml文件动态生成。

首先要读取XML文件,然后遍历整个XML文件,先遍历样式分类,再对每个分类遍历其下的所有样式属性。比较关键的代码是对XML的遍历,下面是对样式分类的遍历代码。

//LoadXML是XML文件读取函数
var dom = LoadXML("css.xml");

//通过XPath和selectNodes方法返回一个XMLDOMNodeList对象
var oNode = dom.selectNodes("//Category/Name");

//获取该对象长度,即XML文档中该路径节点的数量
var intCategory = oNodes.length;
for (i=0; i<intCategory; i++)
{
//获取集合中的节点
oNode = oNodes.nextNode;

if (oNode != null)
{
//样式分类界面构建代码-略 ……
}
}

样式输入控件构建函数,该函数作用是根据XPath路径查询XML定义,生成交互控件

function BuildInput ( path )
{
var str="";
var aNode=null;
var attValue=null;

//通过selectSingleNode返回符合条件的第一个节点 
var actNode = dom.selectSingleNode(path+"ActionType");
var nameNode = dom.selectSingleNode(path+"CssName");

//如果属性为选择输入,则读取SelectItems,并构建select控件 
if (actNode.text=="select")
{
str += "<select id='"+nameNode.text+"' name='"+nameNode.text+"'class='eSelect'>";

//查询该项的所有选择列表项 
var itemsNodes = dom.selectNodes (path+"SelectItems/Item");
str += "<option value='-1'>未设置</option>";
for (ii=0;ii<itemsNodes.length;ii++){
aNode = dom.selectSingleNode (path+"SelectItems/Item["+ii+"]");

//如果该项含有Name属性则在列表中显示Name属性值
attValue = aNode.getAttribute("Name")
var txtNode = dom.selectSingleNode (path+"SelectItems/Item["+ii+"]");
if (attValue==null)
str += "<option value='"+txtNode.text+"'>"+txtNode.text+"</option>";
else
str += "<option value='"+txtNode.text+"'>"+attValue+"</option>";
}
str += "</select>";
}
else
//如果属性为其他模式,则构建input输入,设置class属性为ActionType
{
str = "<input name='"+nameNode.text+"' id='"+nameNode.text+"' class='"+actNode.text+"'>";
}

return(str);
}

asp.net开发技巧

星期四, 五月 6th, 2004

不断学习的过程中,经常遇到一些代码编写技巧性的东西,虽然通常不是什么特别困难的技术问题,不过也十分重要。

为避免遗忘并方便查证,特记录于此。

在页面中直接发文件到客户端

说明: 将下面代码加入干净的aspx页或隐藏代码页即可(此处假设页面为download.aspx);
效果: 链接到地址[download.aspx?file=filename]直接产生下载;
目的: 与直接链接文件地址下载方式比较,可以在下载前加入代码,统计下载数;另外,根据需要可以改写参数(例如改为数据库中该下载文件记录的id),做简单的代码处理,就可以在一定程度上隐藏下载地址,防止盗链……

private void Page_Load(object sender, System.EventArgs e)
{
string path = Server.MapPath(Request.Params["File"]);
System.IO.FileInfo file = new System.IO.FileInfo(path);

Response.Clear();
Response.AddHeader(“Content-Disposition”, “attachment; filename=” + file.Name);

Response.AddHeader(“Content-Length”, file.Length.ToString());
Response.ContentType = “application/octet-stream”;
Response.WriteFile(file.FullName);
Response.End();
}

一千元的代价

星期五, 四月 30th, 2004

在某个鸡尾酒会上,张先生从口袋里掏出一张千元大钞,向所有的来宾宣布:他要将这张千元大钞拍卖给出价最高的朋友,大家互相竞价,以50元为单位,到没有人再加价为止。出价最高的人只要付给张先生他所开的价码即可获得这张千元大钞,但出价第二高的人,虽无法获得千元大钞,仍需将他所开的价码如数付给张先生。

这个别开生面的‘以钱买钱’的拍卖会,立刻吸引了大家的兴趣。开始时,‘100元’、‘150元’、‘200元’的竞偿声此起彼落,到价码抬高到‘500元’时,步调缓和了下来,只剩下三、四个在竞价。最后只剩下王先生和林先生在那里相持不下。

当王先生喊出‘950元’时,张先生弹一弹他手上的千元大钞,暧昧地看着林先生,林先生似乎不假思索地脱口而出:‘1050元!’这时会场里起了一阵小小的骚动。张先生转而得意地看着王先生,等待他加价或者退出,王先生咬一咬牙说:‘2050元!’人群里起了更大的骚动,林先生摆一摆手,喝口鸡尾酒,表示退出这个‘疯狂的拍卖会’,大家才松了一口气。

结果,王先生付出‘2050元’,买到那张‘1000元’钞票,而林先生则平白付出了‘1050元’。两人‘平分秋色’,各损失的‘1050元’都纳入了张先生的荷包。

陷阱的三个特征

这个游戏是耶鲁大学经济学家苏必克(M.Shubik)发明的,想拍卖钱的人几乎屡试不爽地从这拍卖会里‘赚到钱’。它是一个具体而微的‘人生陷阱’,参与竞价的林先生和王先生在这个‘陷阱’里越陷越深,不能自拔,最后都付出了痛苦的代价。

自古以来,人类为捕杀动物所设的‘陷阱’,通常有下列三个特征:

1.有一个明显的诱饵。

2.通往诱饵之路是单向的,可进不可出。

3.越想挣脱,就越陷越深。

人生道上的大小‘陷阱’多少也与此类似。

社会心理学家泰格(A.Teger)曾对参加‘千元大钞拍卖游戏’的人加以分析,结果发现掉入‘陷阱’的人通常有两个动机,一是经济上的、一是人际关系上的。

经济动机包括渴望赢得那张千元大钞、想赢回他的损失、想避免更多的损失;人际动机包括渴望挽回面子、证明自己是最好的玩家及处罚对手等。千元大钞就是一个明显的诱饵。开始时,大家都想以廉价而容易的方式去赢得它,希望自己所出的价码是最后的价码,大家都这么想,就不断地互相竞价。

当进行一段时间后,也就是出价相当高时,相持不下的两人都发现自己掉进一个陷阱中,但已不能全身而退,他们都已投资了相当多,只有再增加投资以期挣脱困境。

当出价等于‘奖金’时,竞争者开始感到焦虑、不安,发现自己的‘愚蠢’,但已身不由己。

当出价高过奖金时,不管自己再怎么努力都是‘损失者’,不过,为了挽回面子或处 罚对方,他不惜‘牺牲’地再抬高价码,好让‘对手损失得更惨重’。人生到处有陷阱

在日常生活里,大至商场上的竞争,小至等候公车,都有‘陷阱’在等待着你。

譬如公车平常是十五分钟一班,当你花在等待的时间超过十分钟后,你会开始烦躁不安,但通常你会继续等下去,等到超过十五分钟公车还不来时,你除了咒骂外,也开始感到‘后悔’——你应该在十五分钟前就走路或坐计程车去的。

但通常你还会继续等下去,因为你已‘投资了那么多的时间’,不甘心现在改坐计程车,结果就越陷越深,无法自拔,直到公车姗姗来迟,你心理的困境才获得解脱。

但人生有很多‘目标’,并不像公车那样‘必定会来临’,而且投资的也不是你‘个人的时间’而已。如何避免蹈入陷阱

在人生道上,如何避兔蹈入这类‘陷阱’,也是一门不小的学问,心理学家鲁宾(J.E.Rubin)的建议是:

1.确立你投入的极限及预先的约定:譬如投资多少钱或多少时间?

2.极限一经确立,就要坚持到底:譬如邀约异性,自我约定‘一次拒绝就放弃’,不可改为‘五次里面有三次拒绝才放弃。’

3.自己打定主意,不必看别人:事实证明,两个陌生人在一起等公车,‘脱身’的机会就大为减少,因为‘别人也在等!’

4.提醒自己继续投入的代价。

5.保持警觉。

这些方法大家也许都知道,但‘知易行难’,一旦掉进人生的陷阱,抽身是不太容易的。

CSS设计器之界面交互

星期四, 四月 29th, 2004

整个操作交互过程,除了最后保存文件外,其他都是由javascript完成。

首先DesignerBuild函数读取XML样式属性定义文件,构建整个设计器界面。然后Init函数读取服务器端赋给设计元素的Style属性,并把属性作为输入控件ID在设计器中查找并赋值,完成初始化。

在操作过程中,根据输入控件的样式类Class,触发绑定的HTC组件,做相应的客户端操作。

最后再读取设计元素的style属性,保存。

设计器界面

不同的设计元素

不同输入控件的不同class属性(根据XML中ActionType生成)触发不同HTC组件,实现不同输入模式。

由于商业原因,这里不便提供源代码;我将在后面提供部分关键代码供参考。

CSS设计器之XML样式属性定义

星期二, 四月 27th, 2004

CSS样式中包含很多属性,设计器中当然要包含相应的属性类型;那么这些属性信息从哪里来呢?

采用XML定义是一种很自然就会想到的方式。

经常使用DW和VS.NET,所以在交互设计上采用了类似的模式;先将样式属性分类,再设置详细属性。

CSS属性是比较复杂的,如果要完全按照DW或VS.NET的模式,实现会比较复杂。为了简化,我把值的输入简化为两种形式,选择和文本输入。对于选择,直接在XML文件中定义;对于文本输入,抽象几种输入类型,在设计器生成时根据类型设定不同的HTC组件操作。这样就将一些复杂的属性输入封装到 HTC组件中,整个构架就简洁起来。

XML文件描述

首先是属性分类

<cssdesign>
<category>
<name>文字</name>
<style>
<name>字体</name>
......
</style>
<style>
<name>样式</name>
......
</style>
......
</category>
<category>
<name>背景</name>
<style>
<name>颜色</name>
......
</style>
......
</category>
</cssdesign>

系统分为文字、背景、文本、位置、布局、方框、边框和其他,每种类型有一个Name子元素和若干Style子元素。

每个Style子元素表示一个Style属性,结构如下

<style>
<name>字体</name>
<cssName>font-family</cssName>
<actionType>select</actionType>
<selectItems>
<item>verdana,arial</item>
<item Name="宋体">SimSun</item>
<item Name="黑体">SimHei</item>
</selectItems>
</style>
<style>
<name>大小</name>
<cssName>font-size</cssName>
<actionType>select</actionType>
<selectItems>
<item>12px</item>
<item>14px</item>
<item>9px</item>
</selectItems>
</style>
<style>
<name>颜色</name>
<cssName>background</cssName>
<actionType>input_ColorSelect</actionType>
</style>

Name为该属性的描述名称,在设计器中为文本描述;

CssName为属性名,在设计器中即输入字段的ID;

ActionType为属性设置方法,在设计器中为输入字段的样式类名,该样式中含有Behavior属性,制定HTC组件;

SelectItems为选择项,如果ActionType为Select,将会在此列出选择项;其子元素Item如果含有Name属性,将显示在设计器中,否则直接显示该元素的文本内容

框架图

XML源文件

CSS设计器之样式表操作类

星期一, 四月 26th, 2004

为了操作样式表,设计了一个简单的样式表操作类。功能主要是解析操作指定样式表文件,实现对样式类的添加、修改、删除、保存。

机制:读取Web服务器上某样式表文件,将文本转化为一个ArrayList,数组元素为自定义的ClassItem对象,包含Name和Text属性(Name即样式名称,Text即样式的内容);然后通过对ArrayList操作,控制样式,最后保存。

由于在服务器段我们不作具体样式定义,因此该类只操作到样式类级别,不涉及样式属性和值。

下面提供该类的UML图 ClassItem 是一个结构体,仅包含两个属性;

CSS设计器之流程

星期五, 四月 23rd, 2004

最近做了一个CSS设计器,主要功能是在web界面上操作设计CSS样式表,目的是方便用户自定义系统界面。

其实我个人看法这个东西并没有太大必要,对于最终用户来说,一般不熟悉网页制作,是不可能进行这种操作的,而且就系统整体来考虑,也不应该给用户这种权限。另外,相对于本来就比较紧张时间资源来讲,花这么多时间,实现这种用户需求优先度较低的功能,实在不合算……

奈何项目经理雄心勃勃,在大而全的方针指导下,不得不做啊。

月初就作的差不多,来总结一下吧

流程再简单说明一下

C#的四个基本技巧

星期四, 四月 22nd, 2004

1.如果可能尽量使用接口来编程

.NET框架包括类和接口,在编写程序的时候,你可能知道正在用.NET的哪个类。然而,在这种情况下如果你用.NET支持的接口而不是它的类来编程时,代码会变得更加稳定、可用性会更高。请分析下面的代码:

private void LoadList (object [] items, ListBox l)
{
 for (int i = 0; i < items.Length;i++)
  l.Items.Add (items[i].ToString ());
}

这个函数从一个可为任何对象的数组中加载ListBox,这段代码被限定为只能使用数组。假想过些时候你发现那些对象存在数据库中,或别的集合中。那么你需要修改程序来使用不同的集合类型。如果你用ICollection接口来写那段程序,你就不用修改那段程序了,对于任何实现 ICollection接口的类型它都能很好的工作:

private void LoadList (ICollection items,ListBox l)
{
  foreach (object o in items)
  l.Items.Add (o.ToString ());
}

ICollection被数组和所有System.Collection中的集合实现。此外,多维数组也支持ICollection接口。如果那还不够的话,数据库.NET类同样支持ICollection接口。用接口写的这个函数不用需改就可以才许多中情况下使用。

2. 使用属性代替原始数据

因为属性已经成为语言本身的元素,所以声明数据元素时它的作用域等级没有必要大于private。因为代码本身会把属性看成数据元素,你并没有失去使用简单数据类型的便利性 。相反它会使你的代码更加灵活功能更加强大。属性使你的数据元素封装性更好。属性可以让你使用lazy evaluation来返回数据。lazy evaluation的意思是当用户请求时才计算它的值,而不是一直保留着它。

最后,属性可以是virtual也可以是abstract。你也可以在接口中定义属性。

这里还有维护方面的因素应当注意:尽管操作两者的方法是一样的,但是你把一个数据元素变成属性,那么原先客户端的程序便不能访问服务端的新版本程序了。实际上对于在Web service中你想实现序列化的值你可以把它们变成属性来使用:

private int TheMonth = 0;

[XmlAttribute ("Month")]
public int Month
{
 get {
  return TheMonth;
 }
 set {
  TheMonth = value;
 }
}

简单通过属性就可以使你的所有数据元素私有化。

3. 在Producer/Consumer 的Idiom中使用Delegate

当你生成一个实现producer idiom类的时候,使用deletate来通知consumer。这种方法相对于用接口更加灵活。Delegate是多点传送的,所以不用加额外的代码你就何以支持多用户。相对于用接口这样做可使类之间的耦合性降低。

下面的类处理键盘输入并把它传给所有的registered listeners:

public class KeyboardProcessor
{
private OnGetLine theFunc = null;

public OnGetLine OnGetLineCallback {
 get {
  return theFunc;
 }
 set {
  theFunc = value;
 }
}

public void Run (){
// Read input.
// If there is any listeners, publish:
string s;
do {
 s = Console.ReadLine ();
 if (s.Length == 0)
  break;
 if (theFunc != null){
  System.Delegate [] funcs =theFunc.GetInvocationList();
  foreach (OnGetLine f in funcs) {
   try {
    f (s);
   } catch (Exception e) {
    Console.WriteLine
    (“Caught Exception: {0}”, e.Message);
   }
  }
 }
} while (true);
}

任何数目的listeners都可注册到producer,它们所要做的只是提供一个特定的函数:deletate。

4. 注意初始化顺序

C#中对于一些变量声明加入了initializer的概念。它们在构造函数之前被执行,实际上变量在基类的构造函数执行前之前被初始化。

所以,在初始化变量的时候不要用基类中的数据,因为它们还没有被构造。

生命中不能承受之痛 2

星期四, 四月 15th, 2004

下面也是一种

………

门口响起了钥匙在锁孔里转动的声音,先生回来了。他没有象往常一样地一进门就喊:妞妞,妞妞,我回来了!饿死了!吃什么呀?他坐在沙发里发呆,我喊了他几声,他没有反应,我走过去一看,他神情黯然地委顿在沙发的一角,衣服上血迹斑斑。我大吃一经,忙问:“发生什么事情了?”他摇摇头说:“没什么,下班前处理了一个交通事故,心情不好。你先吃饭吧,回头跟你说。”“你呢?”“我不想吃。”

这可是没有过的事情。先生是个交通警察,在事故科工作已经五、六年了,对于生离死别、阴阳两隔,用他自己的话说是已经有些麻木了;不用说他,就连我,对那些卷宗里血淋淋的照片都已经有些漠然。他的办公室常有悲悲切切的人来哭诉,他却总能在复议时做到不掺杂感情。我是个爱哭的女人,偏偏先生对于眼泪早已有了职业的免疫力,他说要是每个事故他都要为每个逝者陪眼泪的话,他早就活不下去了,但是今天不同,他分明是掉过泪了。

接下来的这个故事就来自于我的先生,一个交警的口述。

我是在4点03分接到指挥中心的报告:在解放路距离交通指挥信号灯400米处,有一辆自备桑塔纳2000和一辆载货微型卡车发生猛烈的追尾碰撞事故。因为事故发生地点离我们很近,我和小王很快就赶到了现场,等我们到的时候,120还没有来,我们就赶紧救人。肇事车的司机早已不知去向,车门洞开,追尾车里有两个人,一男一女,男的血流满面,样子很恐怖,恐怕是所戴的眼镜片扎伤了双眼,女的看起来还好,正和过路的人一起把受伤的男人往外抱。由于猛烈的碰撞,桑塔纳的车头严重变形,男人被卡在驾驶位上,估计是腿断了,不能动弹。我叫小王先把女人送往医院救治,女人不肯,只是发疯似的抱住男人的上半身。我和小王拿来撬杠,总算把男人弄出来了。

这时我发现女人的嘴角溢出血来,唇色苍白。凭我的经验,这恐怕不是什么好征兆。
去医院的路上,刚好碰上下班高峰,路有些堵,女人坐在后座上抱着那个男人,男人痛苦地呻吟着,两个人的手指紧紧地纠结在一起。女人的嘴角不断地有血沫涌出,顺着下巴往下滴在男人的衣服上。她紧紧地抿住嘴,泪不停地往下掉,却什么也没有说,脸上的神色有痛苦也有不舍。

医院的急救人员早已在大门口待命,就在医护人员抱着男人往外抬的时候,女人一头栽倒在水泥地上,大口大口的鲜血从她的嘴里涌出来。我和小王立刻去抱她起来,我可以断定她肯定是肋骨断裂,并且已经刺伤了内脏。她这样的伤势却还能挺到这里,我不得不为人的潜能的张力叹服。她有些神志不清了,她一把捏住我的手,说了一句话:亲爱的,用我的眼睛去看世界。我的鼻子一酸,落泪了。两个人都被推进去了,我叮嘱小王通知家属,办理手续,我立刻驱车赶回现场勘察。现场满地的玻璃和车身上散落下来的碎片,斑斑的血迹说明了这个事故的惨烈。经现场勘察,我发现事故有些蹊跷。从刹车印和碰撞的痕迹来看,这个事故有着不平常的地方。第一,一般来说,追尾事故车头受损位置应该在右边,也就是副驾驶室的位置,因为司机往往是最先觉察危险的人,因为处于保护自己的本能会往左打方向,以减少事故对自己的伤害,但是这辆车的碰撞位置是中间偏左,致使驾驶位受损严重。

这种情况只会发生在来不及避让的情况下,但是从长长的刹车印来看,他完全有时间避险。第二,刹车印和散落的碎片的分布位置说明男人在前车刹车灯未正常工作而停止的时候,他已经本能地往左打了方向,但是他最后还是往右打了方向,把自己撞了上去。而后几个现场的目击者证实了我的推断。这只能说明一个问题:男人先是出于本能往左边打了方向,以期避开危险,但是,他立刻意识到这样他会伤害到身边这个女人,于是,他又猛烈地往右打方向,试图把女人往生的方向推一把,但是人的反应速度根本及不上车速,在他还没有完全打过方向之前,车已经撞到了。据我刚才在医院门口见到的一幕,恐怕事情没有男人想象的那么乐观。这个女人在车上的表现,恐怕她已经知道自己不能生还,可能她那时侯就是紧紧抿住嘴不让翻涌的血喷出来呢。

这时小王打来电话,女的刚死,男的还在抢救。女的是因为折了的肋骨刺穿了肺还有脾脏破裂引发的大出血。男的双眼扎伤,肋骨断了一根,双腿也折了。院方正考虑根据女的遗愿,把角膜移植给幸存者。

先生说完了,看着我:“我从来没有遇到过这样的事故,这让我对人有了新的认识。”

我的眼睛湿了。

这是从网上转来的,让我莫名感动……故事看来似乎真实的,其中女的说得那句话有些文学化,估计是写的人过于修饰了一些。

gf年纪不算小了,不过是一个很单纯的人,经常遇到一些不顺利的事情就有些情绪化,总说人生太过艰难,随口说些生生死死之类的言语;虽然我很理解她的心情,体谅她的情绪,总是开导劝解,但是心里难免难受一下……

生死之事,不是这么随意说的……

生命中不能承受之痛

星期一, 四月 12th, 2004

最近,父亲60寿就快来了……

家里似乎没有过什么生日,从小就没有关于过生日的记忆,小时候甚至不清楚我的生日是什么时候。模糊中有个记忆似乎是10月某天,直到高考填报时看见户口才发现原来是9月某天……

前段时间母亲提及父亲60寿,让我感到惊异……恍惚中父亲似乎还当壮年,怎么就寿至甲子了?电话里,母亲提到父亲最近时间多病,和我记忆中身体康健胜比年轻人,从来少病的记忆不符……心里算算,自大学离开父母身边,忽忽然已经8年有余了……

昨晚给家里电话,问及母亲银行账户。不能陪在父母身边孝顺,只能以微薄之资聊表心意。很少遇到父亲先接电话,问及身体状况,我的语气故作正经状,严厉“批评”了几句,劝他多出去运动,不要老是呆在家里。父亲只是笑呵呵的感谢我关心,然后和母亲说了几句,千万叮咛……最后末了,电话那头似乎还传来父亲的笑声。

父亲还是和以前一样豁达乐观,微微的笑,我心里这样想着……

清晨,难得很早就醒来,躺在床上,视线指向窗外,天气阴阴的,今天又是一个没有阳光的日子……

胡思乱想,思绪回到昨晚的电话……不知不觉中我的生命已经过去27个年头,父母都已不再是以往了……

想到母亲说起父亲身体患病的话,懞懞中似乎看见父亲的病容……蓦的,跳出来一个画面,父亲的眼睛,透过玻璃从镶着框的的黑白相片中看着我,慈祥的温暖的,那伴随我二十多年生命岁月目光啊……

…………

一阵撕裂的痛楚从我身体某个莫可名状的部位突然炸开来,身体不堪承受的激促的颤动着,卷缩在一起,视线变得昏暗起来,空气被莫名的压力迫离我的周围,被我揉碎变形的枕头里传出沉闷粗重的鼻吸声音,痛苦的酸涩袭偏我的全身……

良久,泪水从眼眶里溢出,浸湿了枕头……

16 of 18«first...«1415161718»