谷哥

努力读书不如论坛看贴

博客园 首页 新随笔 联系 订阅 管理
  25 Posts :: 0 Stories :: 29 Comments :: 1 Trackbacks

2008年7月19日 #

刚看了一下自己的博客,最近的一次写文章还是去年6月,到现在也1年多了。这一年来也时常打开看看,有的时候也真的把平时工作的点滴积累记录一下,一来可以在以后用到的时候翻翻作为参考,二来也可以给一些新入门的朋友一些帮助吧。

这一年来其实自己在技术上也没有很长足的长进。期间换了份工作,也想了很多以后的路怎么走。所以在换工作的时候也就特别慎重。挑了很多公司,有做网络的,有网站的,有行业应用的。有做服务的。有做外包的...也一度让我迷惘了很久。综合考虑了很久。结果现在是做Microsoft Dynamics CRM的扩展开发工作。Dynamics CRM目前在中国国内应用还比较少。所以开发过程中也遇到不少问题国内的论坛及搜索引擎也极少有介绍。于是看了不少国外的技术性网站。结合微软给的不太健全的SDK帮助文档到现在总算对部分扩展开发应用还有点了解。只是想深入我想还需要继续努力。正由于经常看老外的技术性文章对自己的英文阅读能力也有所提高。虽然接触Dynamics CRM时间还不是很长但我真的被它强大的可配置功能及扩展应用功能深深吸引。也因为国内搞这方面开发的人还真的很少很少。所以目前也有一点意向决定以后就顺这这条路走下去了。国外公司应用的还比较多,不知道未来微软CRM在中国国内市场的开发力度和他们对这款产品的支持力度如何了。可真的不能让我失望。之前做过网站,做过外包。做过自己的产品...感觉都比较迷惘,或许也是国内软件行业都这么让人迷惘的原因吧。放眼几大招聘网搜索一下职位,什么 中软,海辉,微创,软通,文思创新,惠普...这些人才外包的公司招聘职位占了七成。找来找去,换来换去,最后的命运也就是被卖来卖去。这些公司从中赚取血汗钱。这也就是中国廉价人力资本吸引国外一些公司的最大原因吧。软件行业更也不是例外。所以我们这些从业人员也就难免经常会感到迷惘而不清楚今后的路怎么走。而且中国有个怪现状。那就是招聘要求里明明白白的表明必须35岁以下。虽然自己还要若干年后才达到这一个无聊的门槛,但也非常抱怨及难过的想问问那些公司,难道过了35岁就一文不值了吗?那些新入行的小弟们真的能挑得起大梁比那些走过接近十年的前辈们更有能力些吗?还是从人力资本上考虑继续压榨而获取更多的利润?哎,不说了,说多了让人感觉我像个愤青, 做好当前自己要做的事,努力提高自己,充实自己才是最重要。有时间我会陆续发一些关于自己在Microsoft Dynamics CRM开发方面的经验。也希望和同行们一道共同提高。大家共同探讨! 明知道被剥削也不能忘记提高自己的脚步啊。这就是资本主义!

posted @ 2008-07-19 21:12 ktgu 阅读(42) | 评论 (1)编辑

2007年6月19日 #

限定符的概念:

 非显式限定符(3 个):
      *:出现0或多次
      +:出现1或多次
      ?:出现0或1次

 显式限定符:
     使用显式限定符则可准确指定数字、范围或数字集,  显式限定符使用花括号 {} 及其中的数字值表示模式出现次数的上下限

   a{5} : 准确匹配5个字符"a"
   a{,5}: 0到5个字符"a"
   a{5,} 5到任意个字符"a"
   a{2,3} 2到3个字符"a"

元字符的概念:

 在正则表达式中,有一种意义特殊的构造,即元字符 。如:* ? +  { } $ ^ . [ ( | ) ] \

 .:                  它可匹配任何单字符
 ^ :                   可指定字符串(或行)的开始
 $ :                   可指定字符串(或行)的结束
 \ (反斜杠):      如果要匹配元字符,必须使用反斜杠进行“转义”。
 | (管道):          a|b 将匹配包含“a”或“b”的任何输入内容
 括号():            用于给模式分组,它允许使用限定符让一个完整模式出现多次,如:(ab){2,3}模式匹配abab,ababab

字符类的概念:
 在方括号 [ ] 中定义, 格式如:[字符表],它仅匹配字符表中的一个字符
 
 指定任何数值数字: [0123456789]
 使用连字符(-) 来定义字符的范围
 [0-9],[a-z],[A-Z]
 仅在连字符不是第一个字符时,连字符才在字符类中有特殊含义,如果需要在范围中包括连字符,将它指定为第一个字符

注意,
      1.正则表达式元字符在字符类中不做特殊处理,所以这些元字符不需要转义

字符类是与其他正则表达式语言分开的一种语言,字符类有自己的规则和语法:
字符 ^ :   表示否定此类, 如:[^123456]匹配除123456以外的字符.
注:
      1. ^ 在字符类中的作用与它在正则表达式模式中的作用完全不同。
      2. 如果要否定连字符(-),应将连字符作为字符类的第二个字符,如 ^[^-][0-9]$   匹配 0、1、2、... (不匹配 -0、-1、 -2 等)

资源

正则表达式库 http://www.regexlib.com/

正则表达式讨论列表 http://aspadvice.com/login.aspx?ReturnUrl=%2fSignUp%2flist.aspx%3fl%3d68%26c%3d16&l=68&c=16

正则表达式论坛 http://forums.regexadvice.com/

正则表达式 Web 日志 http://blogs.regexadvice.com/

Mastering Regular Expressions (O'Reilly),作者 Jeffrey Friedl http://www.regex.info/

.NET 正则表达式参考 http://msdn.microsoft.com/library/en-us/cpref/html/frlrfSystemTextRegularExpressions.asp

Jscript 正则表达式语法 http://www.msdn.microsoft.com/library/en-us/script56/html/js56jsgrpRegExpSyntax.asp

正则表达式信息 http://www.regular-expressions.info/

posted @ 2007-06-19 15:15 ktgu 阅读(151) | 评论 (0)编辑

2007年3月31日 #

A:请写一个文件拷贝函数。
Q:你说的“拷贝”是什么意思?
A:嗯。。。。就是把一个文件的内容拷贝到新的文件
Q:考不考虑日期/时间?
A:不用,那些不用被拷贝。
Q:目标文件可以和源文件同名么?
A:嗯。。。不行
Q:那我不用担心假名攻击(name spoofing)?比如说土耳其语的I。(注意哈,土耳其语的I有四种写法,和英语的I相似而不同)。
A:不用担心。
Q:文件属性呢?
A:新文件和老文件的属性一样
Q:那我应该修改老文件的属性么?如果这个拷贝操作时备份或者存档操作的一部分,那可能不应该保留’Archive’这个属性。
A:不用,保持原样就行了。
Q:那万一源文件的’Archive’属性被关掉了呢?如果新文件的这个属性也被我关掉,可能会搞坏用户的备份软件。
A:就让它们一样。我不在乎用户的备份软件。
Q:这样为用户设计软件好像不好吧?
A:。。。
Q:文件压缩怎么办?这是个文件属性,但拷贝目的地不一定支持压缩。
A:不用管文件压缩。
Q:哪怕源文件被压缩了,而拷贝目的地不支持压缩?
A:对头!
Q:那加密呢?如果源文件被加了密,而拷贝目的地不支持加密?
A:如果目的地不支持加密就不要加密。
Q:哎呀不好意思,我不是想岔开话题。不过。。。这样不是很大的安全隐患么?特别当这个文件拷贝函数支持任意多个参数的时候(直接或者间接)。
A:靠!他妈的把文件拷贝过去就行了!
Q:创建文件的用户呢?
A:不用管。
Q:那文件的所有人呢?
A:不用管。
Q:那文件权限呢?有没有啥么方法来处理继承的权限和赋予的权限?
A:不要管权限了。
Q:那这个函数会在什么系统上运行?
A:Windows XP
Q:Home, Pro, Media Center,或者多于一个版本?
A:Pro
Q:哪一个Service Pack?
A:SP2
Q:也就是说我们不用支持其它的Service Pack?
A:对阿
Q:咋个提供源文件名?
A:用参数传进去。
Q:那则个参数十一个以null结尾的字符串,一个计数的字符串(学Pascal的都知道哈),还是一个对象?
A:以Null计数的字符串。
Q:Null指针可能被传进去么?
A:不可能。
Q:那文件名的编码呢?
A:Unicode。
Q:不好意思,这个这个。。。Unicode不能算编码。如果我们用Unicode数据,我们必须知道具体的编码,比如UTF-8, UCS-2, UTF-16,等等。
A:你够狠!UTF-8。
Q:好嘛。我只是想说把UTF-8转换成UTF-16,好让Windows API调用工作,还是有点痛苦的。
A:射!UTF-8!
Q:Big-endian还是small-endian?
A:啊―――随便你丫的!
Q:那我们接受相对路径还是绝对路径?
A:就绝对路径。
Q:那些路径有没有什么需要过滤的特征?
A:没有。用户自己搞定。
Q:怎么生成目标文件名?或者用户提供?
A:。。。
Q:要不要(或者允不允许)我提供异步拷贝操作?
A:不。
Q:我该怎么报错?Exception?Error code?
A:随便。
Q:我是该在被调用的函数内部处理错误呢,还是把错误传给调用者?
A:嗯。。。传出去。
Q:如果目标文件已经存在怎么办?
A:不会的。
Q:也就是调用人确保这点?
A:对。
Q:也就是说如果目标文件的确存在,我可以立刻终结程序运行?但这个明显违背了前置条件,而且鬼才知道会出什么问题。
A:射。随你丫的。
Q:那轮换数据流呢?
A:随便你!!
Q:老大,我真地不好意思,如果你觉得被我挑衅了。不要生气哈。我只是想在动手前得到一个清晰完整的规格。很明显如果我要写一个文件拷贝函数,而不是用各种库里现成的文件函数,这个新的函数需要满足某套特殊需求,所以我需要知道那些问题的确切答案。如果你无所谓,我可以在一分钟内整出一个函数来,但肯定有很多问题都没有解决。
A:啊!!!!!!!!!!!!!!!!!!!!!!!!
posted @ 2007-03-31 16:06 ktgu 阅读(261) | 评论 (2)编辑

2006年12月1日 #

      好久前就听说过微软提出的智能客户端的概念,当时总以为微软又推出什么新的替代现有技术的新技术,是不是又会引起什么新的技术革命,心想作一个忠实的微软Fans也不太容易啊,也真够累的.本也想关注一下,但一直工作也忙,也由于别的方面学的还不够扎实,所以也没有太多的时间来研究这个东东.

      直到最近这几个月的时间内总算很清闲,倒也没什么事,于是花了点时间研究研究.才算对智能客户端有了一些认识.  我们从.NET Framework和利用Visual Studio.NET,微软在Smart Client的设计、开发、测试和部署等各个阶段都提供了全面的支持可以看出微软还是力推Smart Clien的,未来几年很有发展前途.

      智能客户端定义:
https://thesource.ofallevil.com/china/msdn/developercenter/smartclient/SmartClientDefinition.aspx

      要想了解Smart Client到底是何方神圣,微软有专门的专题介绍以及系列教程,写这篇文章目的只是希望和朋友们有机会能共同探讨的机会!

微软网站有关于Smart Client的详细介绍

MSDN 智能客户端开发人员中心
https://thesource.ofallevil.com/china/msdn/developercenter/SmartClient/default.mspx

微软Smart Client系列教程
http://www.microsoft.com/china/msdn/events/webcasts/shared/webcast/consyscourse/smartclient.aspx
posted @ 2006-12-01 23:50 ktgu 阅读(1291) | 评论 (2)编辑

2006年11月29日 #

1.匿名方法

在C#1.0中典型的给一个委托添加一个方法调用代码如下:
private void ctrl_Click (object sender,EventArgs e)
txt.Click += new MyDelegate(ctrl_Click);
private ctrl_Click(object sender,EventArgs e)
{
 Message.Show(...);
}
哪怕只有这么一条语句也必须得按上面的形式给事件的调用列表添加方法,还得创建一个委托的实例

在C#2.0中引入了匿名方法,大大简化了上述操作
可以改写为
txt.Click += delegate {Message.Show();}
或是这样:
txt.Click += ctrl_Click也是允许的.

C#编译器对上述的定义自动隐式转化,只要匿名方法和委托的定义兼容.
符合下列条件可以兼容
1.参数兼容
如果匿名方法没有参数,委托中没有out参数
如果匿名方法和委托的参数在数量,类型,顺序上都一致
2.返回值兼容
如果委托没有返回值,匿名方法中也没有返回值或匿名方法中只有return不带返回值
如果两者都有返回值,并且匿名方法的返回值可以隐式转化为委托定义的类型

符合参数和返回值兼容的就可以使用匿名方法


匿名方法的捕获变量(capture variable)

如果局部变量或参数的作用范围内包含匿名方法声明,则该局部变量或参数称为该匿名方法的外部变量或捕获变量

public void method1(bool enabled)
{
 string b;
 this.txt.Click += delegate
 {
  this.txt.enabled = enabled;
  this.txt.Text = b;
 }
}

对于这个匿名方法来说:参数enabled和变量a是它的捕获变量或叫外部变量.
捕获变量的生命周期直到此匿名方法的资源被回收而结束


2.泛型
关于泛型的定义及如何使用网上资料已经很多,请参见MSDN


3.迭代器(iterators)

在C#1.0中若想要使得类型成为可枚举的类型(即象使用数组一样用foreach一样枚举数组中的成员),那么这个类中必须实现IEnumerable接口的GetEnumerator()方法返回IEnumerator
public IEnumerator GetEnumerator()
{..}
一般来说实现GetEnumerator是不容易的.

在C#2.0中引入了的新的语法扩充:迭代器,它能够很好的简单方便的让我们实现GetEnumerator()方法
如:
public IEnumerator GetEnumerator()
{
 for ( int i = 0; i < 10; i ++)
 {
  yield return i;
 }
}

假设类Class1中实现了上述的GetEnumertor方法
那我们就可以用foreach对类Class1进行枚举
Class1 c = new Class1;
foreach ( int i in c)
{
 Console.WriteLine(i);
}

yield return产生迭代的下一个值,yield break说明迭代完成,用迭代器实现就是这么简单.

定义和使用命名迭代器

     class Class1
    {
        public IEnumerator GetEnumerator()
        {
            for (int i = 0; i < 10; i++)
            {
                yield return i;
            }
        }

        // 定义一个命名的迭代器,并可以提供参数
        public IEnumerable MaxToMin(int min, int max)
        {
            for (int i = max; i >= min; i--)
            {
                yield return i;
            }
        }

        // 定义一个迭代器类型的属性,
        public IEnumerable MinToMax
        {
            // this表示该类实例,因为该类实现了GetEnumerator(),它是可枚举的
            get { yield return this; }
        }

        public IEnumerable GetDescriptions()
        {
            yield return "this is my test";
            yield return "class name is class1";
            yield return "ktgu";
        }
    }

         static void Main(string[] args)
        {
           
            Class1 c = new Class1();

            foreach (int i in c)
            {
                Console.WriteLine(i);
            }

            foreach (int i in c.MaxToMin(1, 10))
            {
                Console.WriteLine(i);
            }

            foreach (int i in c.MinToMax)
            {
                Console.WriteLine(i);
            }

            foreach (string s in c.GetDescriptions())
            {
                Console.WriteLine(s);
            }
      }

4.不完整代码
C#2.0中引入了一个"不全代码"的概念,即你可以将一个类的定义放在别的文件中.这样给大项目,大文件的维护带来方便.
声明:
[modifiers] partial type
modifier: [public/private/protected/internal] abstract new override static virtual extern
type:类/结构/接口


以上主要是偏向于介绍如何快速的应用这些新的语法点,详细概念及要领请参见MSDN

posted @ 2006-11-29 15:14 ktgu 阅读(826) | 评论 (2)编辑

2006年11月28日 #

委托的声明

public delegate void MyDelegate(string str);

1.委托的定义和方法的定义类似,只是在前面加了一个delegate,但委托不是方法,它是一种类型。是一种特殊的类型,看成是一种新的对象类型比较好理解。用于对与该委托有相

同签名的方法调用。
2.委托相当于C++中的函数指针,但它是类型安全的。
3.委托是从System.Delegate派生,但不能象定义常规类型一样直接从System.Delegate派生,对委托的声明只能通过上面的声明格式进行定义。关键字delegate通知编译器这是一

个委托类型,从而在编译的时候对该类进行封装,对这一过程C#定义了专门的语法来处理这一过程。
4.不能从一个委托类型进行派生,因为它也是默认sealed的
5.委托即可以对静态方法进行调用也可以对实例方法进行调用。
6.每个委托类型包含一个自己的调用列表,当组合一个委托或从一个委托中删除一个委托时都将产生个新的调用列表。
7.两个不同类型的委托即使它们有相同的签名和返回值,但还是两个不同类型的委托。但其实在使用中可看作是相同的。


委托的比较

C#中对委托定义了两个操作符 == 和 !=
在以下情况下两个委托是相等的:
1.当两个委托都同时为null的时候
2.当两个委托都不为null时,下列情况下是相等的。
a.当两个委托的各自的调用列表只含有一个入口点的时候
   在下列情况下是相等的
   (1) 调用同一对象的同一静态方法
   (2) 调用同一对象的同一实例方法
b.当两个委托具有多个入口点时
   在下列情况下是相等的
   (1)只有当它们调用列表中的调用的方法按顺序都一一对应相同的对象及对象的同一方法的时候

如上所述的两个不同类型的委托但是它们具有相同的签名和返回值时,只要满足上述条件的,即使它们类型不同,但比较的结果也是相同的。

委托的异常处理

当调用该委托的方法中发生了异常时,首先在调用该委托的方法中搜寻catch语句块。如果没有,则去该委托调用的方法中去寻找有没有catch语句块,这和调用方法发生异常的处

理是一样的。

当调用一个为null的委托即委托中列表中不存在调用方法时,将发生NullRefrenceException

委托的注意点:
当一个委托有多个入口点的时候,调用委托将依该委托的调用列表中的方法的顺序依次调用.这些方法共享一个参数集合,所以当委托有返回值的时候调用完这个委托后的返回值是最

后一个方法的返回值或是有out参数.如果该委托的参数为ref(引用类型),那么在招待第一个方法的时候如果对这个参数的值有所改变,那么这个改变将会影响到后面的方法调用.

委托的一个例子

using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            // 创建一个委托实例,封装C类的静态方法M1
            MyDelegate d1 = new MyDelegate(C.M1);
            d1("D1"); // M1

            // 创建一个委托实例,封装C类的静态方法M2
            MyDelegate d2 = new MyDelegate(C.M2);
            d2("D2"); // M2

            // 创建一个委托实例,封装C类的实例方法M3
            MyDelegate d3 = new MyDelegate(new C().M3);
            d3("D3"); // M3

            // 从一个委托d3创建一个委托实例
            MyDelegate d4 = new MyDelegate(d3);
            d4("D4"); // M3

            // 组合两个委托
            MyDelegate d5 = d1 + d2;
            d5 += d3;
            d5("D5"); // M1,M2,M3

            // 从组合委托中删除d3
            MyDelegate d6 = d5 - d3;
            d6("D6"); // M1,M2
            d6 -= d3; // 虽然d6调用列表中已经没有d3了,但这样只是不可能的移除没有错误发生
            d6("D6"); // M1,M2
            d6 -= d6;
            //d6("D6"); 此时d6的调用列表为空,d6为null,所以引发System.NullReferenceException

            MyDelegate d7 = new MyDelegate(C1.P1);
            d7("D7"); // C1.P1

            MyDelegate d8 = new MyDelegate(new C2().P1);
            d8("D8"); // C2.P1

        }
    }

    // 声明一个委托MyDelegate
    public delegate void MyDelegate(string str);

    public class C
    {
        public static void M1(string str)
        {
            Console.WriteLine("From:C.M1:   {0}", str);
        }

        public static void M2(string str)
        {
            Console.WriteLine("From:C.M2:   {0}", str);
        }

        public void M3(string str)
        {
            Console.WriteLine("From:C.M3:   {0}", str);
        }
    }

    public class C1
    {
        public static void P1(string str)
        {
            Console.WriteLine("From:C1.P1:   {0}", str);
        }
    }

    public class C2
    {
        public void P1(string str)
        {
            Console.WriteLine("From:C2.P1:   {0}", str);
        }
    }   
}

事件委托

事件概述

事件就是当对象或类状态发生改变时,对象或类发出的信息或通知。发出信息的对象或类称为"事件源",对事件进行处理的方法称为"接收者",通常事件源在发出状态改变信息时,它

并不知道由哪个事件接收者来处理.这就需要一种管理机制来协调事件源和接收者,C++中通过函数指针来完成的.在C#中事件使用委托来为触发时将调用的方法提供类型安全的封装


事件的声明

1.声明一个委托
public delegate void EventHandler(object sender, System.EventArgs e);

2.声明一个事件
public event EventHandler Changed;

3.引发一个事件
public OnChanged(EnventArgs e)
{
 if ( Changed != null)
 {
  Changed(this,e);
 }
}

4.定义事件处理程序
public MyText_OnChanged(Object sender,EventArgs e)
{
 ...
}

5.订阅事件(将事件处理程序添加到事件的调用列表中)

myText.Changed += EventHandler(MyText_OnChanged);

下面的一个小例子说明了怎样定义一个完整的事件机制:

using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {       
        static void Main(string[] args)
        {             
            MyText myText = new MyText();

            // 将事件处理程序添加到事件的调用列表中(即事件布线)
            myText.Changed += new MyText.ChangedEventHandler(myText_Changed);        
           
            string str = "";
            while (str != "quit")
            {
                Console.WriteLine("please enter a string:");
                str = Console.ReadLine();
                myText.Text = str;
            }
        }

        // 对Change事件处理的程序
        private static void myText_Changed(object sender, EventArgs e)
        {
            Console.WriteLine("text has been changed  :{0}\n" ,((MyText)sender).Text);
        }       
    } 

    public class MyText
    {
        private string _text = "";

        // 定义事件的委托
        public delegate void ChangedEventHandler(object sender, EventArgs e);

        // 定义一个事件
        public event ChangedEventHandler Changed;

        // 用以触发Change事件
        protected virtual void OnChanged(EventArgs e)
        {
            if (this.Changed != null)
                this.Changed(this, e);
        }

        // Text属性
        public string Text
        {
            get { return this._text; }
            set
            {
                this._text = value;
                // 文本改变时触发Change事件
                this.OnChanged(new EventArgs());
            }
        }
    }
}  

不足之处,还请大家多多指正!

posted @ 2006-11-28 16:15 ktgu 阅读(2062) | 评论 (5)编辑

2006年11月20日 #

大家喝的是啤酒。这时你入座了。

你给自己倒了杯可乐,这叫低配置。
你给自已倒了杯啤酒,这叫标准配置。

你给自己倒了杯茶水,这茶的颜色还跟啤酒一样,这叫木马。
你给自己倒了杯可乐,还滴了几滴醋,不仅颜色跟啤酒一样,而且不冒热气还有泡泡,这叫超级木马。

你的同事给你倒了杯白酒,这叫推荐配置。

人到齐了,酒席开始了。

你先一个人喝了一小口,这叫单元测试。
你跟旁边的人说哥们咱们随意,这叫交叉测试。
但是他说不行,这杯要干了,这叫压力测试。
于是你说那就大家一起来吧,这叫内部测试。
这个时候boss向全场举杯了,这叫集成测试。

菜过三巡,你就不跟他们客气了。
你向对面的人敬酒,这叫p2p.
你向对面的人敬酒,他回敬你,你又再敬他……,这叫tcp.
你向一桌人挨个敬酒,这叫令牌环。
你说只要是兄弟就干了这杯,这叫广播。

可是你的女上司听了不高兴了:只有兄弟么,罚酒三杯。这叫BoB!!!。
可是你的女下属听了不高兴了:我喝一口,你喝一杯,这叫恶意攻击。

有一个人过来向这桌敬酒,你说不行你先过了我这关,这叫防火墙。
你的小弟们过来敬你酒,这叫一对多。
你是boss,所有人过来敬你酒,这叫服务器。

酒是一样的,可是喝法是不同的。
你喝了一杯,boss喝了一口,这叫c#。
你喝了一杯,mm喝了一口,这叫vb。
你喝了一杯,你大哥喝了半杯,这叫c++。
你喝了半杯,你小弟喝了一杯,这叫汇编。
你喝了一杯,你的搭档也喝了一杯,这叫c。

酒是一样的,可是喝酒的人是不同的。
你越喝脸越红,这叫资源释放。
你越喝脸越白,这叫资源独占。
你已经醉了,却说我还能喝,叫做虚拟内存。
你明明能喝,却说我已经醉了,叫做资源保留。
你喝一段时间就上厕所,这叫cache。

酒过三巡,你也该活动活动了。
你一桌一桌的走,这叫轮巡。
你突然看到某一桌的漂亮mm,走了过去,这叫激活事件。
你去了坐下来就不打算走了,这叫死循环。
你的老大举杯邀你过去,你只好过去,这叫优先级。
你向一桌敬酒,他们说不行不行我们都喝白的,于是你也喝白的,这叫本地化。

你向boss敬酒,可是boss被围了起来,你只能站在外圈,这叫队列。
你终于到了内圈,小心翼翼的向前一步,这叫访问临界区。
你拍着boss的肩膀说哥们咱们喝一杯,这叫越界。

你不知喝了几圈了,只会说两个字,干了,这叫udp。
可是还有人拿着酒瓶跑过来说,刚才都没跟你喝,这叫丢包。

喝酒喝到最后的结果都一样
你突然跑向厕所,这叫捕获异常错误。
你在厕所吐了,反而觉得状态不错,这叫释放内存。
你在台面上吐了,觉得很惭愧,这叫实时错误。
你在boss面前吐了,觉得很害怕,这叫灾难性错误。
你吐到了boss身上,只能索性晕倒了,这叫ShutDown。

你找boss喝酒,boss说我喝不下了,这叫超过最大连接数。
你继续劝boss喝酒,这叫刷新。
boss说喝不了了,不喝了,这叫访问拒绝。
然后boss说:小伙子,我们换个话题,这叫页面重定向。
boss问你:小伙子,你叫什么?这叫登录验证。
boss说:你等等,我去下wc。结果左等右等就是等不回来,这叫连接超时。
你到处找boss,结果就是找不到,这叫该页无法显示。

一个人拿着啤酒到你们部门那桌,对你们经理说:我敬你们部门一杯。然后你们部门一个喝啤酒的人和他干了这杯。
另一个人拿着白酒也到你们那,对你们经理说:我也敬你们部门一杯。然后你们部门一个喝白酒的人和他干了这杯。
这叫多态。

一个人拿着两杯酒到你们部门那桌,把其中一杯酒放到经理面前,说:我敬你们部门一杯你们谁喝我不管,只要把这杯喝了就行了。
这叫封装。

一个人拿着酒到你们部门那桌,对你们经理说:我敬你一杯。然后经理点名:xxx,帮我喝这杯,你喝就等于我喝了。
这叫继承。

你拿个空杯子喝酒,这叫虚函数。

别人向你敬酒,你拿个小杯准备喝,他说:“不行,我们要大杯”,这叫需求变更。

你拿个大杯敬酒,他说:“我们换小杯的”,这叫简化版本。

posted @ 2006-11-20 22:48 ktgu 阅读(278) | 评论 (0)编辑

没事的时候总喜欢泡技术社区,记得在2005年的时候社区里突然冒出个AJAX的新名词,开始还以为又出来什么新语言了.是不是又要掀起技术革命,感叹程序员的命真的是苦啊,一项技术还没有学好,新的技术又随之出现,于是时常会想起老了以后学不动了怎么办?开始见到AJAX并没有引起我对它的注意,后来经过时间不是很长好像这东西发展还真的挺快的。各论坛讨论的呼声越来越大,很多人把它说的神乎其神,在众多人高呼WEB2.0时代到来之时,AJAX也似乎有取代传统WEB开发的趋势,于是不得不在闲下来的时候对AJAX进行必要得了解。

        很早就知道AJAX其实就是html + javascript + xml + dom + Dhtml 说白了就是对老技术得灵活运用,偏偏老技术还没有学精谈何灵活运用呢,为了使技术能够得到提高也为了能够灵活运用AJAX跟随技术潮流,计划在闲着的时候学习一下ajax。

        有空的时候将学习的笔记发布并整理成BLOG文章,希望得到大家的帮助!共同提高!

Ajax 应用程序所用到的基本技术
1.html
    组成web页面所用到的基本元素
2.javascript
    javascript代码是AJAX应用程序核心的代码,帮助ajax程序改进与服务器通讯以实现不一样的用户体验
3.Dynamic HTML
    用于动态更新web页面
4.DOM(文档对象模型)
    用于通过javascrip代码处理HTML或服务器返回的XML

javascript与服务器端通信的最核心的对象
xmlHttp对象:传送XML格式数据的超文本传输协议
实际上XMLHTTP传输的数据可以是XML格式数据,也可以是字符串,流,或者一个无符号整数数组。还可以是URL的参数,它下达的结果可以是XML格式数据,也可以是字符串,流,或者一个无符号整数数组。

调用步骤
1、创建XMLHTTP对象
2、打开与服务端的连接,同时定义指令发送方式,服务网页(URL)和请求权限等。  
3、发送指令。 
4、等待并接收服务端返回的处理结果。 
5、释放XMLHTTP对象

方法
open(数据传送方式(GET/POST/HEAD),服务器URL,是否异步执行,[用户名],[口令])
如:
open("GET","http://www.sohu.com",true)

send(content)
可以是XML格式数据,也可以是字符串,流,或者一个无符号整数数组。也可以省略,让指令通过Open方法的URL参数代入。
如:send(null);

setRequestHeader(HTTP 头,HTTP 头值)
如:xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")

abort()取消当前 HTTP 请求

getAllResponseHeaders ()
从响应信息中检索所有的HTTP 头字段

getResponseHeader(HTTP 头)
从响应信息正文中获得一个 HTTP 标头值

属性
onreadystatechange:用以状态改变后所要作的处理的事件句柄。
readyState 异步操作的状态:未初始化(0),正在加载(1),已加载(2),交互(3),已完成(4)
responseBody:返回为无符号整数数组。
responseStream:返回为IStream流。
responseText :返回字符串。
responseXML:返回为XML格式数据。
status:服务器返回的HTTP状态码
statusText :服务器HTTP响应行状态

说明
1.同步和异步
        同步状态下发送http请求后,只有当客户端接收到来自服务端的全部应答数据或协议栈超时返回!反之异步状态下,直接返回。在异步方式下数据包一旦发送完毕就结束send进程客户端执行其他的操作,而在同步方式下客户端要等到服务器返回确认消息后才结束send进程。实际运用中我们根据实际情况使用同步或异步,注意了如果设为同步状态可能因为服务器返回数据量大或响应慢而导致不必要的长时间等待!

2.POST和GET
        用"POST"方式发送数据.可以大到4MB "GET"只能256KB


创建一个XMLHTTP对象
Microsoft Internet Explorer浏览器使用MSXML解析器处理XML,MSXML实际上有两种不同的版本xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
对于非 Microsoft 浏览器(Mozilla、Firefox、Safari、Opera):
xmlHttp = new XMLHttpRequest();

function getXmlHttp()
{
 var xmlHttp = null; 
 
 if ( window.XMLHttpRequest)
 {
  xmlHttp = new XMLHttpRequest();
  if (xmlHttp.overrideMimeType)
   xmlHttp.overrideMimeType("text/xml");
 }
 else if ( window.ActiveXObject)
 {
  try
  {
   xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
  }
  catch(e)
  {
   xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
  }
 }
 
 if ( !xmlHttp)
 {
  window.alert("XmlHttp not be Supported!");  
 }
 
 return xmlHttp; 
}

下面的代码说明了如何从创建到初始化XMLHTTP到发送数据的过程,并指定处理返回数据的事件句柄
var xmlHttp = null;
  
function callServer(url)
{
 xmlHttp = getXmlHttp();
 xmlHttp.onReadyStateChange = setPage;
 xmlHttp.open("GET",url,true);
 xmlHttp.send();   
 document.getElementById("loading").innerHTML = "正在加载...";
}

得到返回数据并更新页面
function setPage()
{   
 switch(xmlHttp.readyState)
 {
  case 0:
   document.getElementById("loading").innerHTML = "正在初始化...";
   break;
  case 1:
   document.getElementById("loading").innerHTML = "正在加载...";
   break;
  case 2:
   document.getElementById("loading").innerHTML = "已加载完成...";
   break;
  case 3:
   document.getElementById("loading").innerHTML = "正在接收数据...";
   break;
  case 4:
   document.getElementById("loading").innerHTML = "已完成!";
   break;
 }     
  
 if ( xmlHttp.readyState == 4)
 {
  if ( xmlHttp.status == 200)
  { 
   document.getElementById("content").innerText = xmlHttp.responseText;
  }
  xmlHttp.abort();    
 } 
}

HTML :
<input name="url" id="url" type="text" value="http://www.sohu.com"><input type="button" onclick="callServer(document.getElementById('url').value)" value="get data">&nbsp;<BR>
<div id="loading" style="color:red; font-size:12px;"></div>            
<span id="content"></span>

posted @ 2006-11-20 22:46 ktgu 阅读(267) | 评论 (0)编辑

2006年5月30日 #

最近一个项目中遇到一个转换FileTime的问题.时间是在C#中用DateTime.ToFileTime写入数据库中,这在存储过程中判断年和季度成了问题,怎么样才能把时间转换为正常的时间格式呢?Sql server中又没有FromFileTime对应的方法?其实很简单用C#写一个转换时间的Dll然后在存储过程中调用就可以了.
转换时间的类如下:
[Guid("729ba6af-3eff-4b75-b43b-d951a190dbe6")]
 public class FileTimeConvert
 {
  public FileTimeConvert()
  {
  }
 
  public string ConvertTime(long fileTime)
  {
   string retVal = string.Empty;
   if (fileTime > 0)
   {
    DateTime dt = DateTime.FromFileTime(fileTime);
    retVal = dt.ToString();    
   }
   return retVal;
  }  
 }
注意这个Guid我们在存储过程中引用要用到这个Guid.

为方便可能在多处需要调用,我们专门写一个存储过程
如下:

CREATE  PROCEDURE  spu_ConvertFileTimeToNormal
 @ticks BIGINT,
 @returnval  varchar(40) output
 AS 

DECLARE @src varchar(255)
DECLARE @desc varchar(255)


DECLARE @object int
DECLARE @hr int
EXEC @hr = sp_OACreate '{729ba6af-3eff-4b75-b43b-d951a190dbe6}',@object OUT

IF @hr = 0 --如果创建对象成功
  BEGIN 
  EXEC @hr = sp_OAMethod @object,'ConvertTime',@returnval OUT,@ticks
      print @returnval
      print @hr
  if(@hr <> 0)
   BEGIN
       EXEC sp_OAGetErrorInfo @object, @src OUT, @desc OUT
    SELECT hr=convert(varbinary(4),@hr), Source=@src, Description=@desc 
   END
   
  END

 ELSE
  BEGIN
   --print  @hr
   print 'Create Object ConvertTime failed'
 
     EXEC sp_OAGetErrorInfo @object, @src OUT, @desc OUT
     SELECT hr=convert(varbinary(4),@hr), Source=@src, Description=@desc
     RETURN
  END

 EXEC @hr = sp_OADestroy @object

 IF @hr <> 0
 BEGIN
    EXEC sp_OAGetErrorInfo @object
    RETURN
 END

GO

这个时候我们还差最后一步注册DLL了
在.net 命令行下输入 regasm -codebase path

好了,现在我们就可以在其他存储过程中调用这个存储过程返回正常的时间了.
给个小例子:
EXEC spu_ConvertFileTimeToNormal @CreateTime,@NormalTime OUT    
@CreateTime:FileTime格式
@NormalTime :正常的时间格式字符串(spu_ConvertFileTimeToNormal 存储过程返回值)

这个简单的小例子说明了我们怎么样在存储过程中调用DLL
是不是你解决问题又多了一个选择了呢?

posted @ 2006-05-30 19:00 ktgu 阅读(907) | 评论 (0)编辑

2006年4月14日 #

灵活的运用数据绑定操作
        绑定到简单属性:<%#UserName%>
        绑定到集合:<asp:ListBox id="ListBox1" datasource='<%# myArray%>' runat="server">
        绑定到表达式:<%#(class1.property1.ToString() + "," + class1.property2.ToString())%>
        绑定到方法返回值:<%# GetSafestring(str) %>
        绑定到Hashtable:<%# ((DictionaryEntry)Container.DataItem).Key%>
        绑定到ArrayList:<%#Container.DataItem %>

        若数组里里放的是对象则可能要进行必要的转换后再绑定如:
        <%#((对象类型)Container.DataItem).属性%>

        绑定到DataView,DataTable,DataSet:
        <%#((DataRowView)Container.DataItem)["字段名"]%>或
        <%#((DataRowView)Container.DataItem).Rows[0]["字段名"]%>
        要格式化则:
        <%#string.Format("格式",((DataRowView)Container.DataItem)["字段名"])%>
        <%#DataBinder.Eval(Container.DataItem,"字段名","格式")%>

        绑定到DataReader:
        <%#((IDataReader)Container.DataItem).字段名%>

        当然为了方便一般使用最多的就是DataBinder类的Eval方法了.不过这样对于同时要绑定大量的数据效率要低一些

Sql Server中DateTime值的范围
        1753-01-01 至 9999-12-31
 在做Access程序导入数据到Sql Server 时要注意ACCESS中的日期可能不在此范围内而出现错误.(如日期为207-01-01)

检测到有潜在危险的 Request.Form 值
       solution1:<%@Page ValidateRequest="false" %>
       solution2:
        <configuration>
            <system.web>
                <pages validateRequest="false" />
            </system.web>
        </configuration>
 其实这样做的确有点不安全,我们还应该自己定义一个专门处理这类危险字符的方法来对其进行预处理

ViewState,Session,Cookie作用域
        ViewState值保存在浏览器的html代码中,当浏览器关闭或跳到别的页面,则值消失  
        Session采用键值对的形式,键存放客户端而值放在服务器端,是通过用户的ID去找服务器上对应的值,这种方式值放置在服务器端,有个时间限制,时间到则服务器自动释放  
        Cookies则有两种方法,一种方法是把值保存在浏览器的变量中,当浏览器关闭时结束,另一种方法是保存在硬盘中,只要时间不过期,下次还可使用

Access中的通配符注意了
        DAO: *, ADO: % (是不是有时候在SQL SERVER里能查而用VB在操作ACCESS时有查不出数据来啊?)

(添加中...)

posted @ 2006-04-14 15:50 ktgu 阅读(373) | 评论 (0)编辑

2006年3月28日 #

1.DataGrid动态绑定字段

      有时候我们会遇到在DataGrid中动态绑定某个字段的情况,比如:当显示中文时我们绑定cname,显示英文时我们要绑定ename,此时我们可以这样:
ButtonColumn:
if (language == "cn")
     ((ButtonColumn)this.DataGrid1.Columns[3]).DataTextField = "cname";
else
     ((ButtonColumn)this.DataGrid1.Columns[3]).DataTextField = "ename";

BoundColumn:
((BoundColumn)this.DataGrid1.Columns[3]).DataField = "cname";

HyperLinkColumn同ButtonColumn的写法,不同的是当我们要动态改变TemplateColumn的显示应该怎么办呢?
这样就行了 先新建一个模板:
public class Template1 :ITemplate
 {
    public void InstantiateIn(Control container)
    {
        TextBox txt = new TextBox();
       txt.Text = "this is a added template column";
       container.Controls.Add(txt);
     }
 }
再这样写:
((TemplateColumn)this.DataGrid1.Columns[1]).ItemTemplate = new Template1();

2.动态转换DataGrid中某个Cell中的值

BoundColumn:
if (e.Item.Cells[3].Text == "Ann")
     e.Item.Cells[3].Text = "<b>这一行本来应该显示Ann,现在被转换成这样了!</b>";

ButtonColumn :
LinkButton link = (LinkButton)e.Item.Cells[3].Controls[0];
if (link.Text == "Ann")
     link.Text = "<b>这一行本来应该显示Ann,现在被转换成这样了!</b>";
这段代码写在:OnItemDataBound事件的方法体中就可以了.

HyperLinkColumn:
强类型转换成HyperLink,

Template Column:
通过FindControl方法

3.动态创建DataGrid及添加列

DataGrid dg = new DataGrid();
    
    // BoundColumn
    BoundColumn col1 = new BoundColumn();
    col1.DataField = "au_id";
    col1.HeaderText = "au_id";
    dg.Columns.Add(col1);

    // ButtonColumn
    ButtonColumn col2 = new ButtonColumn();
    col2.DataTextField = "au_fname";
    col2.HeaderText = "au_fname";
    dg.Columns.Add(col2);

    // TemplateColumn
    TemplateColumn col3 = new TemplateColumn();
    col3.ItemTemplate = new Templates.Template1();
    col3.HeaderText = "My Template Column";
    dg.Columns.Add(col3);

    // LinkButtonColumn
    HyperLinkColumn col4 = new HyperLinkColumn();
    col4.HeaderText = "au_lname";
    col4.DataTextField = "au_lname";
    col4.DataNavigateUrlField = "au_lname";    
    dg.Columns.AddAt(0,col4);
    
    SqlConnection conn = new SqlConnection("server=localhost;uid=sa;pwd=;database=pubs"); 
    SqlDataAdapter da = new SqlDataAdapter("select * from authors",conn);
    DataSet ds = new DataSet();
    da.Fill(ds);
    dg.DataSource = ds;
    dg.DataBind();
    Page.Controls[1].Controls.Add(dg);

4.关于.Net中将DataGrid内容导出到Excel乱码的问题
一般常用的方法为:
DataGrid1.DataSource = this.GetDataSource();   
DataGrid1.DataBind();
Response.Clear();
Response.Buffer = true;
Response.ContentType            = "application/vnd.ms-excel";
Response.Charset                    = "gb2312";
EnableViewState                     = false;
System.IO.StringWriter tw       = new System.IO.StringWriter();
System.Web.UI.HtmlTextWriter hw = new System.Web.UI.HtmlTextWriter(tw);
DataGrid1.RenderControl(hw );
Response.Write(tw.ToString());
Response.End();

但是有时导出会出现乱码,有时则不会出现乱码.真是百思不得其解.

我们可以这样解决将
Response.ContentType            = "application/vnd.ms-excel";
Response.Charset                    = "gb2312";
换成:
Response.Write("<meta http-equiv=Content-Type content=text/html;charset=gb2312>");
Response.AppendHeader("content-disposition","attachment;filename=\"" + HttpUtility.UrlEncode("全部销售记录["+DateTime.Now.ToString("yyyy-MM-dd")+"]",System.Text.Encoding.UTF8) + ".xls\"");

为什么直接输出到Excel会出现乱码,而用Excel打开这段Html不会出现乱码呢?暂时能解决问题但还是不明白,希望高手能给予释疑!

posted @ 2006-03-28 19:00 ktgu 阅读(448) | 评论 (2)编辑

2006年1月19日 #

有时候我们经常在编译的时候出现这样的一个错误:未处理的“System.Configuration.ConfigurationException”类型的异常出现在 microsoft.practices.enterpriselibrary.configuration.dll 中。"这是因为在你的输出目录下没有找到这个配置文件的原因。

刚刚明明把配置文件(应用程序名.exe.config & dataconfiguration.config)保存到bin/debug下面了。怎么没找到呢?再调试还是说没有。结果发现每次运行的时候这个文件总是会被自动删除掉了。

原来我们要这样做就可以了。将配置文件存放到项目文件夹下面。然后在在项目中选择 属性|生成事件|生成后事件命令行 输入:copy "$(ProjectDir)\*.config" "$(TargetDir)"这样在每次生成以后都会把这个配置文件拷到目标文件夹下面就不会产生如上的错误了。

posted @ 2006-01-19 16:35 ktgu 阅读(354) | 评论 (0)编辑

2005年11月14日 #

      我们有时候会遇到要访问的数据不只是在本地服务器上,往往另一部分在远程数据库服务器上,比如我们在两个服务器上存放着表结构一样的数据我们要把两数据合并起来一起显示怎么办呢,那么这个时候我们用SQL SERVER提供的OPENROWSET函数了,使用起来很方便,记住像引用表名那样引用OPENROWSET 函数就可以了。

我们可以这样写:
1.SELECT a.* FROM table1 a LEFT JOIN OPENROWSET('MSDASQL','DRIVER={SQL Server};SERVER=192.168.0.1,2412;UID=sa;PWD=bb',DbName.dbo.table2) AS b ON a.id = b.id ORDER BY a.ID DESC
将地址为192.168.0.1端口为2412的SQL SERVER上的table2表和本地服务器上的table1表联接。

2.SELECT * FROM (SELECT a.* FROM table1 a UNION SELECT b.* FROM OPENROWSET('MSDASQL','DRIVER={SQL Server};SERVER=192.168.0.1,2412;UID=aa;PWD=bb',DbName.dbo.table2) AS b) TempTable ORDER BY ID DESC
将地址为192.168.0.1端口为2412的SQL SERVER上的table2表中内容加到table1表中。

      上例中我们用的是ODBC 的OLE DB 提供程序,当然了你还可能用SQL Server 的 Microsoft OLE DB,Jet 的 Microsoft OLE DB等Provider连接。

使用SQL Server 的 Microsoft OLE DB:
OPENROWSET('SQLOLEDB','服务器地址,端口';'用户名';'密码', 'SQL语句')

使用Jet 的 Microsoft OLE DB:
OPENROWSET('Microsoft.Jet.OLEDB.4.0', 'c:\test.mdb';'admin';'pwd', Orders)

注意:以上两种用户名和密码前都是用分号分隔。

今天刚好用到,所以小总结一下,记忆力不好没办法只能写下来。

posted @ 2005-11-14 19:07 ktgu 阅读(1669) | 评论 (3)编辑

2005年11月4日 #

为了方便大家,这里提供中国移动通信互联网短信网关接口协议的下载

中国移动通信互联网短信网关接口协议DOC版(CMPP3.0).rar

中国移动通信互联网短信网关接口协议DOC版(CMPP2.0).rar

中国移动通信互联网短信网关接口协议PDF版(CMPP2.0).rar

如果你有接入号那么你就可以接入移动的真实网关进行测试了,而在实际编程中开始往往是用模拟网关。

中国移动通信CMPP2.0短消息网关模拟器V1.10.rar

中国移动通信CMPP3.0短消息网关模拟器V1.10.rar

当然了要是觉得不好用就自己写一个了,其实就是跟你写的客户端是互为服务器,客户端的。

更多请到天堂鸟论坛里看看

想用C#开发的,可以研究一下这位兄台写的:

CMPP2.0 协议SP端的·NET开发

CMPP SP端 C# 实例

posted @ 2005-11-04 11:12 ktgu 阅读(3110) | 评论 (2)编辑

2005年8月27日 #

模板化控件提供将控制数据和UI分开,控制数据由模板控件提供模板控件本身不提供用户界面(UI),用户界面(UI)是由这个控件的内联模板提供.

开发一个模板化控件我们必须要:
1.创建模板化控件的时候为了使模板中的元素在页面控件树中有唯一的标记符,必须为模板控件实现System.Web.UI.INamingContainer接口。这个接口可以在你的模板控件下创建一个新的命名范围。
public class TemplateControl :Control ,INamingContainer
{...}

2.应用ParseChildren(true)元数据,告诉页面解析器解释该控件时将内部xml标记解析为属性而不是控件,此属性就是模板属性(ITemplate类型)(注:如果你的控件是从WebControl继承,就不需要应用该元数据,因为WebControl已经应用了该元数据属性)。

3.定义一个或多个System.Web.UI.ITemplate类型的属性模板。

4.在每个模板属性(ITemplate类型的属性)上必须定义ystem.Web.UI.TemplateContainerAttribute 类型的元数据属性以指出该属性使用哪种容器(注意:该容器必须实现了INamingContainer接口)
[TemlateContainer(typeof(TemplateContainer))]
public ITemplate TemleteItem
{...}

5.TemplateContainer元数据的参数是“容器控件”,页面中显式提供的用于作为用户界面的内联模板就实例化到该容器。(容器控件本身应该实现INamingContainer接口以保证模板中的元素在控件树中标记是唯一的)。

6.重载CreateChildControls方法以便在模板中创建子控件。

        如果存在"模板属性"(ITemplate类型的属性)代码实现总体步骤为:
        1.那么我们先创建一个容器控件的实例。
        2.实例化模板中的元素并加入到容器中。
        3.将这个容器添加到Controls集合中。
        下面是具体实现细节:

        第一步:
        private Control myTemplateContainer = new TemplateContainer();
        注意:如果要将模板控件本身作为容器控件则不需要这个实例化模板控件的过程.
        
        第二步,是通过模板属性InstantiateIn方的法做到的.我们不需要实现这个方法,因为系统已经可以提供实现。
        假设:TempleteItem是一个模板属性(public ITemplate TemplateItem {...})
        那么第二步是这样实现的:
        TemplateItem.InstantiateIn(myTemplateContainer)
        注意:如果我们要将该模板控件作为该模板的容器那么语句为:
        TemplateItem.InstantialteIn(this)
        并且不需要有第三步的Controls.Add语句。

        第三步:
        Controls.Add(myTemplateContainer)
        问:如果将模板化控件的自身作为这个控件模板容器的话,那么这条语句不需要(见上面红字标志的地方)。

7.重载OnDataBinding方法。
protected override void OnDataBinding(EventArgs e) {
            EnsureChildControls();
            base.OnDataBinding(e);
}

为什么要重载此方法呢?
因为:这样做是为了保证在页面计算模板内的任何元素的数据绑定之前模板中的元素都已经实例化好,否则在模板中的元素还没有实例化之前就如果我们执行模板中元素的绑定是不正确的。

这里我们简要的解释一下EnsureChildControls方法。
EnsureChildControls方法的功能是:确保当前的控件包含有子控件。   该方法首先检查服务器控件的ChildControlsCreated属性的值,若为false,则调用CreateChildrenControls方法创建子控件。

 

 

posted @ 2005-08-27 18:35 ktgu 阅读(605) | 评论 (2)编辑