雷's profileAbbeyGong's SpacesPhotosBlog Tools Help

Blog


    3/31/2008

    Visual Studio 2005 开发WPF应用程序系列文章——什么是WPF

          你也许听说过Avalon(现在被称为Windows Presentation Foundation,或WPF),也许看过相关的屏幕截图或demo,但是现在你可以亲手尝试了。让我们开始创建下一代Windows应用程序吧。

      微软公司早在2003年洛杉矶的PDC上就公布了Avalon,他们将其视为下一代用户界面技术,并且得到了开发者和用户的一致赞同。

      在2005年的PDC上,微软公司展示了比2003年更加完整的Avalon版本,并给它取了一个官方新名称:Windows Presentation Foundation(WPF)。在此之前,它已经完成了从演示软件到开始阶段alpha版本的API的转变。到了几个月之后的今天,它又成长成为更加先进的beta版本--你可以使用它来开发你的下一代用户界面程序了。

      那么,WPF是什么,为什么它那么重要呢?

      首先,它清晰而又有效的将用户界面和程序实现分开。它使得设计可视化的用户界面的设计者和编写内部核心代码的开发人员可以并行工作。这是非常重要的:

      ·将两者分开,软件开发公司可以使得设计者们集中精力将设计工作做得更好,同时让开发者支持他们。

      ·随着软件外包和订购的逐渐风行,WPF使得一些商业的设计者们能够更好的从事界面设计工作,并集成一些简单的功能,而购买的核心代码能够独立的完成内部的一些关键逻辑而不干扰设计过程。

      ·它更好的支持应用软件的国际化。不同的独立的界面可以使用不同的本地化方案,而内部的代码是通用的。

      ·它支持软件的"空标签":可以为不同的用户采用定制的界面而保持核心的逻辑不变。开发者们创建程序逻辑,然后为不同的用户使用不同的界面并贴上他们的商标等。

      WPF使用一种基于XML的语言来定义用户界面从而完成上述的工作。这种语言被称为XAML,XML应用程序标记语言。

      其次,WPF使用一种基于向量而不是基于光栅的绘制引擎,这和曹其的Windows的绘制引擎是截然不同的。光栅绘制引擎通过在屏幕上绘制象素点来绘制表面。象素只是点;这样的话,如果屏幕分辨率(DPI,每英寸点)增加了,它的效果就会变差。随着现在屏幕都采用超高DPI的分辨率,字体必须使用成百上千个DPI来达到一定的浏览效果。比如微软Word里缺省的英文字体12号的Times New Roman,在现在的普通分辨率情况下效果还可以但是到了超高分辨率的显示器上效果就不行了。管理这些基于光栅的图像的点将会消耗大量的处理能力,同时也是很浪费的。而采用基于向量的方式来替代象素,在一个可扩展的坐标系里绘制字体和其他线型,使得它们可以独立于DPI。想想Windows Metafile(WMF)和位图文件(BMP)之间的差距你就明白了。同时,向量图也使得一些变换如3D,旋转和动画变得更加方便和易于操作。

      好,下面开始我们的第一个基于WPF的应用程序之旅吧。

    首先你需要安装一下一些软件:
    1. 首先你需要安装.NET Framework 3.0。
    2. 你需要安装WinFX runtime components。
    3. 还需要安装VS2005
    4. 最后你需要下载Visual Studio development tools(Orcas)来进行WinFX开发。它包含了VS里的"Cider"设计器来编辑XAML。
    5. 最后你需要下载Expression Designer for XAML

      作为程序员你可以使用Cider工具来在VS.NET里创建基本的XAML用户界面,这样的方式你会感到很熟悉,和在VS中进行一般的Windows 窗体设计差不多。但是,如果要是用一些XAML提供的高级特性,我建议你还是研究一下Expression Designer for XAML。

    第一个WPF Windows Application:

      如果所有的工具都安装正确,你就可以开发你的第一个WPF程序了。打开VS2005,选择文件->新建工程。你将会看到工程对话框,如图1所示。


      在图1中,你可以看到一套新的工程类型,名为Windows Application,包括Windows Application(WPF),服务库,XAML Browser Application (WPF)浏览器程序和控件库。它们分别用来创建XAML客户端程序,Indigo服务,XAML浏览器(Web窗体)程序,和控件库。
      这篇文章里,我主要讲解创建一个Windows windows应用程序的流程,所以我们选择和其对应的工程模板。

      当你第一次创建这个程序的时候,你将会看到和标准的VS设计环境类似的界面,但是事实上它是一个VS的新的XAML设计器,代号"Cider"。如图2所示。


      如果你仔细看图2,你会发现在设计面板的下部有一个新tab,名为"Xaml"。点击它,你会看到当前设计的XAML,这个XAML包含了一个button,一个textbox:

      当你改变Cider可视化编辑器里的对话框的布局的时候,工具会自动更新XAML的内容。

      对控件的基于设计者的事件添加机制还没有被Cider所支持,不过如果手工对XML进行一些修改就可以很容易的增加一些事件。比如,你可以手工为"Click"属性增加一个点击事件处理:

    <Button Margin="124,125,93,119" Name="btnClick" Click="ButtonClick"  >I Click</Button>

      你可以看到,这里做的就是为按钮增加了一个新的"Click"属性,并且给出了点击按键事件句柄的名称。如果你选择了"Source"那个tab,你可以为这个事件创建处理句柄。

      Avalon使用一种被称为"Routed Events"的机制来绑定XAML和后端代码,如同其名--事件在运行时在独立的XAML UI和代码之间相互传递。

      这样的话,你需要声明事件句柄来使用RoutedEventArgs参数:

    void ButtonClick(object sender, RoutedEventArgs e)
    {
    System.Windows.MessageBox.Show("Hello World to:" +
    textBox1.Text);
    }
      如果你此时运行程序,你将看到WPF基于向量的引擎已经开始工作了,如图3所示。


      这样你就完成了你的第一次Avalon的学习之旅,也许它没有想象中的激动人心,但是毕竟你已经开始掌握这一先进技术了。
      Microsoft Expression是一个比基本的Cider工具更加强大的XAML设计工具,它包含在VS.NET的WinFX工具集中。有兴趣的朋友可以自己 使用Expression来设计XAML 这个应用程序。

    在C#隐藏主窗口的几种方法

    写过一个程序,要求在程序启动的时候主窗口隐藏,只在系统托盘里显示一个图标。一直以来采用的方法都是设置窗口的ShowInTaskBar=false, WindowState=Minimized。但是偶然发现尽管这样的方法可以使主窗口隐藏不见,但是在用Alt+Tab的时候却可以看见这个程序的图标并把这个窗口显示出来。因此这种方法其实并不能满足要求。

    经过研究,又找到两个方法。

    方法一: 重写setVisibleCore方法

    protected override void SetVisibleCore(bool value)
    {
         
    base.SetVisibleCore(false);
    }

    这个方法比较简单,但是使用了这个方法后主窗口就再也不能被显示出来,而且在退出程序的时候也必须调用Application.Exit方法而不是Close方法。这样的话就要考虑一下,要把主窗口的很多功能放到其他的地方去。

    方法二: 不创建主窗口,直接创建NotifyIcon和ContextMenu组件
    这种方法比较麻烦,很多代码都必须手工写

    static void Main()
    {
                 Application.EnableVisualStyles();
                 Application.SetCompatibleTextRenderingDefault(
    false);

                 System.Resources.ResourceManager resources
    =
                    
    new System.Resources.ResourceManager("myResource",   System.Reflection.Assembly.GetExecutingAssembly());
                 NotifyIcon ni
    = new NotifyIcon();

                 ni.BalloonTipIcon
    = System.Windows.Forms.ToolTipIcon.Warning;
                 ni.BalloonTipText
    = "test!";
                 ni.BalloonTipTitle
    = "test.";
                
    //ni.ContextMenuStrip = contextMenu;
                 ni.Icon = ((System.Drawing.Icon)(resources.GetObject("ni.Icon")));
                 ni.Text
    = "Test";
                 ni.Visible
    = true;
                 ni.MouseClick
    += delegate(object sender, MouseEventArgs e)
                 {
                     ni.ShowBalloonTip(
    0);
                 };

                 Application.Run();
    }

    如果需要的组件太多,这个方法就很繁琐,因此只是做为一种可行性研究。

    方法三:前面两种方法都有一个问题,主窗口不能再显示出来。现在这种方法就没有这个问题了

    private bool windowCreate=true;
    ...
    protected override void OnActivated(EventArgs e)
             {
                
    if (windowCreate)
                 {
                    
    base.Visible = false;
                     windowCreate
    = false;
                 }

                
    base.OnActivated(e);
             }

    private void notifyIcon1_DoubleClick(object sender, EventArgs e)
             {
                
    if (this.Visible == true)
                 {
                    
    this.Hide();
                    
    this.ShowInTaskbar = false;
                 }
                
    else
                 {
                    
    this.Visible = true;
                    
    this.ShowInTaskbar = true;
                    
    this.WindowState = FormWindowState.Normal;
                    
    //this.Show();
                    this.BringToFront();
                 }

    3/29/2008

    SqlServer函数小结

      之前处理数据都是用程序来处理,但数据量大的时候,速度很不理想,于是便将大数据量计算的函数写成了Sql函数,将Sql函数基本语法整理了一下,希望对大家有用

    建立函数
        create function [functionName]
        (--参数声明区
            @myVar1 varchar(10)
            @myVar2 int
        )
        --指定返回类型--返回参数
        returns int
        as
        begin
            declare @myInt
            --赋值后
            ...
            --返回值
            return @myInt
        end
        --指定返回类型--返回表
        returns @myTabel Table (myFld1 varchar(10),myFld2 int,myFld3 float)
        as
        begin
            declare @myFld1 varchar(10)
            declare @myFld2 int
            declare @myFld3 float
            --赋值后
            Insert Into @myTable (fld1,fld2,fld3) values (@myFld1,@myFld2,@myFld3)
            return
        end
    修改函数:Alter Function ……
    变量声明:declare [变量名] [变量类型]
        declare @myVar1 varchar(10)
    返回单个值
        set @myVar1 = (Select myFld1 From table1 Where myFld2=@myFld2)
    返回多个值
        declare TableTmp cursor for select myFld1,myFld2 From table1 Where myFld2 = @myFld3
        open TableTmp
        fetch next from TableTmp Into @myFld1,@myFld2
        --关闭游标
        close TableTmp
        deallocate TableTmp
    返回值并添充到临时表
        declare TableTmp cursor for select myFld1,myFld2 From table1 Where myFld2 = @myFld3
        open TableTmp
        fetch next from TableTmp Into @myFld1,@myFld2
        while @@fetch_status = 0
        begin
            insert into @myTable1 (myFld1,myFld2) values (@myFld1,@myFld2)
            fetch next from TableTmp Into @myFld1,@myFld2
        end
        --关闭游标
        close TableTmp
        deallocate TableTmp
    读取函数
        [dbo].[tableName]   
        跨库读函数:[DataBaseName].[dbo].[tableName]
    语法
    if :
        if (条件表达式)
        begin
            ……
        end
        else if (条件表达式)
        begin
            ……
        end
        else
        begin
            ……
        end
    case when:
        set @myFld1 =(
            case
                when [条件表达式] then [运算式]
                when [条件表达式] then [运算式]
                ……
                else [运算式]
            end)
    while:
        while [条件表达式]
        begin
            ……
            [break]
            [continue]
        end
    GoTo:
        myLabel1:
            ……
        GoTo myLabel1

    外键的设置及作用

    外键的作用:

    保持数据一致性,完整性,主要目的是控制存储在外键表中的数据。 使两张表形成关联,外键只能引用外表中的列的值!

    例如:

    a b 两个表

    a表中存有客户号,客户名称

    b表中存有每个客户的订单

    有了外键后

    你只能在确信b 表中没有客户x的订单后,才可以在a表中删除客户x

    建立外键的前提: 本表的列必须与外键类型相同(外键必须是外表主键)。

    指定主键关键字: foreign key(列名)

    引用外键关键字: references <外键表名>(外键列名)

    事件触发限制: on delete和on update , 可设参数cascade(跟随外键改动), restrict(限制外表中的外键改动),set Null(设空值),set Default(设默认值),[默认]no action

    例如:

    outTable表 主键 id 类型 int

    创建含有外键的表:

    create table temp(

    id int,

    name char(20),

    foreign key(id) references outTable(id) on delete cascade on update cascade);

    说明:把id列 设为外键 参照外表outTable的id列 当外键的值删除 本表中对应的列筛除 当外键的值改变 本表中对应的列值改变。

    今天有朋友问我"外键的作用是什么"

    当朋友问我外键的作用是什么时,我也愣了一下,平常都是在这么用,还没有真正的总结过,外分键的作用呢.下面,我总结了一下外键的作用:

    外键 (FK) 是用于建立和加强两个表数据之间的链接的一列或多列。通过将保存表中主键值的一列或多列添加到另一个表中,可创建两个表之间的链接。这个列就成为第二个表的外键。

    FOREIGN KEY 约束的主要目的是控制存储在外键表中的数据,但它还可以控制对主键表中数据的修改。例如,如果在 publishers 表中删除一个出版商,而这个出版商的 ID 在 titles 表中记录书的信息时使用了,则这两个表之间关联的完整性将被破坏,titles 表中该出版商的书籍因为与 publishers 表中的数据没有链接而变得孤立了。FOREIGN KEY 约束防止这种情况的发生。如果主键表中数据的更改使之与外键表中数据的链接失效,则这种更改是不能实现的,从而确保了引用完整性。如果试图删除主键表中的行或更改主键值,而该主键值与另一个表的 FOREIGN KEY 约束值相关,则该操作不可实现。若要成功更改或删除 FOREIGN KEY 约束的行,可以先在外键表中删除外键数据或更改外键数据,然后将外键链接到不同的主键数据上去。

    外键是用来控制数据库中数据的数据完整性的

    就是当你对一个表的数据进行操作

    和他有关联的一个或更多表的数据能够同时发生改变

    这就是外键的作用

    [精] 谈谈外键

    外键 (FK) 是用于建立和加强两个表数据之间的链接的一列或多列。通过将保存表中主键值的一列或多列添加到另一个表中,可创建两个表之间的链接。这个列就成为第二个表的外键。

    FOREIGN KEY 约束的主要目的是控制存储在外键表中的数据,但它还可以控制对主键表中数据的修改。例如,如果在 publishers 表中删除一个出版商,而这个出版商的 ID 在 titles 表中记录书的信息时使用了,则这两个表之间关联的完整性将被破坏,titles 表中该出版商的书籍因为与 publishers 表中的数据没有链接而变得孤立了。FOREIGN KEY 约束防止这种情况的发生。如果主键表中数据的更改使之与外键表中数据的链接失效,则这种更改是不能实现的,从而确保了引用完整性。如果试图删除主键表中的行或更改主键值,而该主键值与另一个表的 FOREIGN KEY 约束值相关,则该操作不可实现。若要成功更改或删除 FOREIGN KEY 约束的行,可以先在外键表中删除外键数据或更改外键数据,然后将外键链接到不同的主键数据上去。

    外键是用来控制数据库中数据的数据完整性的

    就是当你对一个表的数据进行操作

    和他有关联的一个或更多表的数据能够同时发生改变

    这就是外键的作用


    主键和外键是把多个表组织为一个有效的关系数据库的粘合剂。主键和外键的设计对物理数据库的性能和可用性都有着决定性的影响。

    必须将数据库模式从理论上的逻辑设计转换为实际的物理设计。而主键和外键的结构是这个设计过程的症结所在。一旦将所设计的数据库用于了生产环境,就很难对这些键进行修改,所以在开发阶段就设计好主键和外键就是非常必要和值得的。

    主键:

    关系数据库依赖于主键---它是数据库物理模式的基石。主键在物理层面上只有两个用途:

          1. 惟一地标识一行。

          2. 作为一个可以被外键有效引用的对象。

    基于以上这两个用途,下面给出了我在设计物理层面的主键时所遵循的一些原则:

          1. 主键应当是对用户没有意义的。如果用户看到了一个表示多对多关系的连接表中的数据,并抱怨它没有什么用处,那就证明它的主键设计地很好。

          2. 主键应该是单列的,以便提高连接和筛选操作的效率。

         注:使用复合键的人通常有两个理由为自己开脱,而这两个理由都是错误的。其一是主键应当具有实际意义,然而,让主键具有意义只不过是给人为地破坏数据库提供了方便。其二是利用这种方法可以在描述多对多关系的连接表中使用两个外部键来作为主键,我也反对这种做法,理由是:复合主键常常导致不良的外键,即当连接表成为另一个从表的主表,而依据上面的第二种方法成为这个表主键的一部分,然,这个表又有可能再成为其它从表的主表,其主键又有可能成了其它从表主键的一部分,如此传递下去,越靠后的从表,其主键将会包含越多的列了。

          3. 永远也不要更新主键。实际上,因为主键除了惟一地标识一行之外,再没有其他的用途了,所以也就没有理由去对它更新。如果主键需要更新,则说明主键应对用户无意义的原则被违反了。

         注:这项原则对于那些经常需要在数据转换或多数据库合并时进行数据整理的数据并不适用。

          4. 主键不应包含动态变化的数据,如时间戳、创建时间列、修改时间列等。

          5. 主键应当有计算机自动生成。如果由人来对主键的创建进行干预,就会使它带有除了惟一标识一行以外的意义。一旦越过这个界限,就可能产生认为修改主键的动机,这样,这种系统用来链接记录行、管理记录行的关键手段就会落入不了解数据库设计的人的手中。


    外键是数据库一级的一个完整性约束,就是数据库基础理论书中所说的“参照完整性”的数据库实现方式。

    外键属性当然是可以去掉的,如果你不想再用这种约束,对编程当然不会有什么影响,但相应的录入数据的时候就不对录入的数据进行“参照完整性”检查了。  

    例如有两个表

    A(a,b) :a为主键,b为外键(来自于B.b)

    B(b,c,d) :b为主键   

    如果我把字段b的外键属性去掉,对编程没什么影响。

    如上面,A中的b要么为空,要么是在B的b中存在的值,有外键的时候,数据库会自动帮你检查A的b是否在B的b中存在。

    1、外建表达的是参照完整性:这是数据固有的,与程序无关。因此,应该交给DBMS来做。

    2、使用外建,简单直观,可以直接在数据模型中体现,无论是设计、维护等回有很大的好处,特别是对于分析现有的数据库的好处时非常明显的--前不久我分析了一个企业现有的数据库,里面的参照完整性约束有的是外键描述,有的是用触发器实现,感觉很明显。当然,文档里可能有,但是也可能不全,但是外键就非常明显和直观。

    3、既然我们可以用触发器或程序完成的这个工作(指参照完整性约束),DBMS已经提供了手段,为什么我们要自己去做?而且我们做的应该说没有RDBMS做得好。实际上,早期的RDBMS并没有外键,现在都有了,我认为数据库厂商增加这个功能是有道理的。从这个角度来说,外键更方便。

    4、关于方便,根据我带项目的情况来看,程序员确实有反映,主要是在调试时输入数据麻烦:如果数据可以违反参照完整性,那么就是说参照完整性本身就不对名誉业务冲突,此时也不应该用触发期货程序实现;否则,说明数据是错误的,根本就不应该进入数据库!而且,这也应该是测试系统的一个内容:阻止非法数据。实际上,前台程序应该对这种提交失败做出处理。数据是企业的而非程序的,储程序要尽量与数据分离,反之亦然。

    最后说一下,建键几个原则:

    1、 为关联字段创建外键。

    2、 所有的键都必须唯一。

    3、避免使用复合键。

    4、外键总是关联唯一的键字段。

    外键的作用?

    外键是数据库一级的一个完整性约束,就是数据库基础理论书中所说的“参照完整性”的数据库实现方式。

    外键属性当然是可以去掉的,如果你不想再用这种约束,对编程当然不会有什么影响,但相应的录入数据的时候就不对录入的数据进行“参照完整性”检查了。  

    例如有两个表

    A(a,b) :a为主键,b为外键(来自于B.b)

    B(b,c,d) :b为主键   

    如果我把字段b的外键属性去掉,对编程没什么影响。

    如上面,A中的b要么为空,要么是在B的b中存在的值,有外键的时候,数据库会自动帮你检查A的b是否在B的b中存在。

    1、外建表达的是参照完整性:这是数据固有的,与程序无关。因此,应该交给DBMS来做。

    2、使用外建,简单直观,可以直接在数据模型中体现,无论是设计、维护等回有很大的好处,特别是对于分析现有的数据库的好处时非常明显的--前不久我分析了一个企业现有的数据库,里面的参照完整性约束有的是外键描述,有的是用触发器实现,感觉很明显。当然,文档里可能有,但是也可能不全,但是外键就非常明显和直观。

    3、既然我们可以用触发器或程序完成的这个工作(指参照完整性约束),DBMS已经提供了手段,为什么我们要自己去做?而且我们做的应该说没有RDBMS做得好。实际上,早期的RDBMS并没有外键,现在都有了,我认为数据库厂商增加这个功能是有道理的。从这个角度来说,外键更方便。

    4、关于方便,根据我带项目的情况来看,程序员确实有反映,主要是在调试时输入数据麻烦:如果数据可以违反参照完整性,那么就是说参照完整性本身就不对名誉业务冲突,此时也不应该用触发期货程序实现;否则,说明数据是错误的,根本就不应该进入数据库!而且,这也应该是测试系统的一个内容:阻止非法数据。实际上,前台程序应该对这种提交失败做出处理。数据是企业的而非程序的,储程序要尽量与数据分离,反之亦然。

    最后说一下,建键几个原则:

    1、 为关联字段创建外键。

    2、 所有的键都必须唯一。

    3、避免使用复合键。

    4、外键总是关联唯一的键字段。

    主键,外键,唯一,约束区别

    什么是主键?

    在数据库中,常常不只是一个表,这些表之间也不是相互独立的。不同的表之间需要建立一种关系,才能将它们的数据相互沟通。而在这个沟通过程中,就需要表中有一个字段作为标志,不同的记录对应的字段取值不能相同,也不能是空白的。通过这个字段中不同的值可以区别各条记录。就像我们区别不同的人,每个人都有名字,但它却不能作为主键,因为人名很容易出现重复,而身份证号是每个人都不同的,所以可以根据它来区别不同的人。数据库的表中作为主键的字段就要像人的身份证号一样,必须是每个记录的值都不同,这样才能根据主键的值来确定不同的记录。

    什么是外键?
    foreignkey
    说明你的表A中的某项a,是引用表B的某列b
    为什么要使用外键?
    RDBMS的基本概念,可以维护数据库的完整。
    如何来用?
    涉及到数据库的定义,参见tsql help file

    唯一性约束和主键的区别是什么?

    唯一性约束
    1) 唯一性约束所在的列允许空值,但是主键约束所在的列不允许空值。
    (2) 可以把唯一性约束放在一个或者多个列上,这些列或列的组合必须有唯一的只。但是,唯一性约束所在的列并不是表的主键列。
    (3) 唯一性约束强制在指定的列上创建一个唯一性索引。在默认情况下,创建唯一性的非聚簇索引,但是,也可以指定所创建的索引是聚簇索引。
    主键:
    1) 用于标识某行而且与之相关.
    2) 是不可能(或很难)更新.
    3) 不应该允许空(NULL).
    唯一域/字段:
    1) 用于作为访问某行的可选手段.
    2) 只要唯一就可以更新.
    3) 可以为空(NULLs).
    注意唯一和主键的区别,它们都是创建一个唯一的索引,一个表格仅含有一个主键约束列,但是,它有可能在其他列中含有许多的唯一约束。

    代码名称:C#自定义事件

    开发环境:C#

    代码:

    一.含有自定义事件的控件主体代码及对应剖析 (注意,此控件库是由VS.NET的"新建"->"Windows控件库"生成的) 
       
      namespace MyEventTEST 
      { 
       public class LoginEventArgs : System.EventArgs 
       // 上面代码定义了在主程序中引发事件时需要传递给主程序的所有信息,并且注意, 
       // 该类必须派生于System.EventArgs类 
       { 
       public LoginEventArgs(string sUserID, string sPassword, bool bValid) 
       { 
       UserID = sUserID; 
       Password = sPassword; 
       Valid = bValid; 
       } 
       
       public string UserID; 
       public string Password; 
       public bool Valid; 
       } 
       
       public delegate void GoodLoginEventHandler(object sender, LoginEventArgs e); 
       public delegate void FailedThreeTimesEventHandler(object sender, LoginEventArgs e); 
       // 上面两行代码定义了两个多路委托(因此返回类型必须为void),每个委托对应一种类型的事件; 
       // 因为是多路委托,所以每个委托中可以含有多个方法. 
       // 请注意,参数是(object sender, LoginEventArgs e),所以添加到多路委托的方法必须符合这种签名方式. 
       // 此外,为什么这里不使用系统已经定义的多路委托"System.EventHandler(object sender, EventArgs e)", 
       // 而要自己定义新的委托"?????EventHandler()"呢?这是因为我们这里传递给用户程序集的参数不是 
       // "System.EventArgs"类型,而是自己定义的"LoginEventArgs"类型,所以有必要重新定义自己的委托类型. 
       
       
       public class ActiveLogin : System.Windows.Forms.UserControl 
       { 
       private System.Windows.Forms.Label label1; 
       private System.Windows.Forms.Label label2; 
       private System.Windows.Forms.TextBox txtUserID; 
       private System.Windows.Forms.TextBox txtPass; 
       private System.Windows.Forms.Button btnLogin; 
       private System.Windows.Forms.Button btnCancel; 
       private System.ComponentModel.Container components = null; 
       // 上面代码是组成这个控件的一些组件定义,由VS.NET自动生成 
       
       public event GoodLoginEventHandler GoodLogin; 
       public event FailedThreeTimesEventHandler FailedThreeTimes; 
       public event EventHandler Cancel; 
       // 上面三行代码非常之重要,定义了三个事件(event),分别是"GoodLogin","FailedThreeTimes" 
       // 和"Cancel" 
       // 它们的类型分别是"GoodLoginEventHandler","FailedThreeTimesEventHandler" 
       // 和"EventHandler",也就是说添加到这三个事件中的方法必须符合对应的多路委托定义! 
       // 而且注意,因为事件"Cancel"的类型是系统已经定义的多路委托"EventHandler"类型, 
       // 所以上面的多路委托中没有定义类似"CancelEventHandler"的新委托,因为是不需要的. 
       
       public ActiveLogin() 
       { 
       InitializeComponent(); 
       } 
       // 上面代码是控件中类"ActiveLogin"的构造方法,该方法中调用了初始方法InitializeComponent() 
       // 上面代码由VS.NET自动生成 
       
       protected override void Dispose( bool disposing ) 
       { 
       if( disposing ) 
       { 
       if(components != null) 
       { 
       components.Dispose(); 
       } 
       } 
       base.Dispose( disposing ); 
       } 
       // 上面代码是自定义控件中类"ActiveLogin"的析构方法,由VS.NET自动生成. 
       
       private void InitializeComponent() 
       { 
       .... // 这里是对所有引用控件(组件)的初始化代码 
       } 
       // 上面代码是自定义控件中类"ActiveLogin"的初始方法,其中内容由VS.NET自动生成. 
       
       protected virtual void OnGoodLogin(LoginEventArgs e) 
       // 上面一行代码定义了激发"GoodLogin"事件的方法; 
       // 注意签名类型,定义方法是protected virtual,也就是说只能在这个类及它的 
       // 继承类中访问此方法,而且可以重写. 
       // 参数类型是"LoginEventArgs",注意只有这一个参数,因为在本方法中含有对 
       // this的引用,所以这里不需要传递this对象. 
       // 一般地说,这个方法使用场合只有两种: 
       // <1>在本控件内被调用,因为本方法不被调用,就无法激发用户代码在事件"GoodLogin" 
       // 中添加的方法; 
       // <2>在用户的继承代码中重写本方法,虽然重写本方法可能会带来性能的提高,但 
       // 倘若用户代码中忘记调用此方法,那么在用户代码先前在事件"GoodLogin"中 
       // 添加的方法将无法得到激活!!! (避免此问题的方法就是在重写方法中必须含有 
       // 一行"base.GoogLogin(e)",这行将负责调用本方法) 
       // 对于第<2>点需要提出的是,在用户的继承代码中重写本方法的作用相当与在 
       // 事件"GoodLogin"中添加一个方法,此方法的代码内容和重写方法内容相同. 
       // (但是应该绝对没有"base.GoogLogin(e)"这一行) 
       { 
       if (GoodLogin != null) // 如果在事件"GoogLogin"中含有方法,则激发这些方法 
       { 
       GoodLogin(this, e); // 把this对象和参数e传递给所有在事件"GoogLogin" 
       // 中添加的方法,并顺序执行这些方法 (注意,由多路 
       // 委托特性决定:在用户代码中先添加的方法先执行. 
       } 
       } 
       // 上面对OnGoogLogin方法解释已经十分详细了,下面两个ON方法均与上述ON方法同出一辙. 
       
       protected virtual void OnFailedThreeTimes(LoginEventArgs e) 
       { 
       if (FailedThreeTimes != null) 
       { 
       FailedThreeTimes(this, e); 
       } 
       } 
       
       protected virtual void OnCancel(System.EventArgs e) 
       { 
       if (Cancel != null) 
       { 
       Cancel(this, e); 
       } 
       } 
       
       private void btnLogin_Click(object sender, System.EventArgs e) 
       // 上面的定义是由VS.NET自动生成,是当按下控件的"btnLogin"按钮时调用的方法. 
       { 
       if(...) 
       OnGoodLogin(new LoginEventArgs(txtUserID.Text, txtPass.Text, true)); 
       // 上面一行代码调用了OnGoodLogin方法,作用是"当控件中的按钮btnLogin被按下时, 
       // 并且符合上面的if条件时: 
       // 将通过调用OnGoodLogin方法把在用户代码中添加到事件"GoogLogin"中的所有方法 
       // 全部顺序执行一遍. 
       // 为什么不在这里把OnGoodLogin()方法中的代码执行一遍,而还要再单独调用OnGoodLogin 
       // 方法呢? 这是因为有时候用户代码需要重写OnGoodLogin()方法! 
       // 下面调用的OnFailedThreeTimes()方法和OnCancel()方法解释同上. 
       else 
       OnFailedThreeTimes(new LoginEventArgs(txtUserID.Text, txtPass.Text, false)); 
       } 
       
       private void btnCancel_Click(object sender, System.EventArgs e) 
       { 
       OnCancel(new EventArgs()); 
       } 
       } 
      } 
       
       
      二.调用此控件的程序集(注意,此程序集是由VS.NET的"新建"->"Windows应用程序"生成的),也就是"用户代码"部分 
       
      namespace HostApp 
      { 
       public class Form1 : System.Windows.Forms.Form 
       { 
       private MyEventTEST.ActiveLogin activeLogin1; 
       // 上面一行代码引用了自定义控件库的类"ActiveLogin",并用它定义了一个对象"activeLogin1". 
       // 这里的"MyEventTEST"是在自定义的控件库中定义的命名空间,如果在这个程序集中没有出现 
       // "using MyEventTEST"语句,则该名称必须出现在对自定义控件引用的任何代码中! 
       
       private System.ComponentModel.Container components = null; 
       
       public Form1() 
       { 
       InitializeComponent(); 
       } 
       
       protected override void Dispose( bool disposing ) 
       { 
       if( disposing ) 
       { 
       if (components != null) 
       { 
       components.Dispose(); 
       } 
       } 
       base.Dispose( disposing ); 
       } 
       // 上面两个方法都是又VS.NET自动生成,不做另外解释. 
       
       private void InitializeComponent() 
       { 
       this.activeLogin1 = new MyEventTEST.ActiveLogin(); 
       // 上面一行代码用自定义控件库中的类"ActiveLogin"实例化对象"activeLogin1" 
       this.SuspendLayout(); 
       
       // 
       // activeLogin1 
       // 
       this.activeLogin1.Location = new System.Drawing.Point(144, 8); 
       this.activeLogin1.Name = "activeLogin1"; 
       this.activeLogin1.Size = new System.Drawing.Size(280, 184); 
       this.activeLogin1.TabIndex = 0; 
       
       this.activeLogin1.GoodLogin += new MyEventTEST.GoodLoginEventHandler(this.activeLogin1_GoodLogin); 
       this.activeLogin1.Cancel += new System.EventHandler(this.activeLogin1_Cancel); 
       this.activeLogin1.FailedThreeTimes += new MyEventTEST.FailedThreeTimesEventHandler(this.activeLogin1_FailedThreeTimes); 
       // !!! 请注意上面的三行代码,这是用户代码接受自定义控件库中事件的代码 !!! 
       // 上面三行代码分别把用户定义的方法"activeLogin1_GoodLogin","activeLogin1_Cancel" 
       // 和"activeLogin1_FailedThreeTimes"分别添加到自定义控件中的事件"GoogLogin","Cancel" 
       // 和"FailedThreeTimes"中; 这样一来只要自定义控件中的对应事件一被激发,这些 
       // 添加用户自定义方法就会被执行. 
       // 要注意的是,用户自定义方法签名必须符合对应的多路委托的定义(因为事件是由多路委托 
       // 定义的,所以要添加到什么事件,定义就必须符合该事件对应的多路委托的定义) 
       // 而且,这里的Cancel事件类型是系统已经定义的多路委托"EventHandler"类型,所以它的实例化 
       // 与其它两个事件的实例化有所不同,是"System.EventHandler",而不是"MyEventTEST.EventHandler"! 
       // 这些用户自定义方法将在下面列出. 
       // 不过请注意,上面的三行代码虽然在方法InitializeComponent()中,但却是我们自己手工添加的! 
       
       // 
       // Form1 
       // 
       this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); 
       this.ClientSize = new System.Drawing.Size(440, 357); 
       this.Controls.AddRange(new System.Windows.Forms.Control[] { 
       this.activeLogin1, 
       }); 
       this.Name = "Form1"; 
       this.Text = "Form1"; 
       this.ResumeLayout(false); 
       } 
       
       [STAThread] 
       static void Main() 
       { 
       Application.Run(new Form1()); 
       } 
       // 上面的方法分别是Windows Forms程序的入口. 
       
       private void activeLogin1_GoodLogin(object sender, MyEventTEST.LoginEventArgs e) 
       { 
       MessageBox.Show("Good Login! " + e.UserID); 
       } 
       
       private void activeLogin1_FailedThreeTimes(object sender, MyEventTEST.LoginEventArgs e) 
       { 
       MessageBox.Show("Failed to login three times."); 
       } 
       
       private void activeLogin1_Cancel(object sender, System.EventArgs e) 
       { 
       MessageBox.Show("Cancel"); 
       } 
       // 上面的三个方法(activeLogin1_GoogLogin,activeLogin1_Cancel和activeLogin1_FailedThreeTimes) 
       // 就是当自定义控件中对应的事件被激发时在当前程序集中对应的处理方法. 
       // 值得注意的是,签名应该完全符合对应的多路委托的定义! 
       } 
      } 
    
    3/10/2008

    中文真伟大!竟然有只能看,不能读的

    1、赵元任《施氏食狮史》
      石室诗士施氏,嗜狮,誓食十狮。施氏时时适市视狮。十时,适十狮适市。是时,适施氏适市。氏视是十狮,恃矢势,使是十狮逝世。氏拾是十狮尸,适石室。石室湿,氏使侍拭石室。石室拭,氏始试食是十狮。食时,始识是十狮,实十石狮尸。试释是事。
    2、杨富森<<于瑜与余欲渔遇雨>>   
    于瑜欲渔,遇余于寓。语余:“余欲渔于渝淤,与余渔渝欤?”
    余语于瑜:“余欲鬻玉,俞禹欲玉,余欲遇俞于俞寓。”
      余与于瑜遇俞禹于俞寓,逾俞隅,欲鬻玉于俞,遇雨,雨逾俞宇。余语于瑜:“余欲渔于渝淤,遇雨俞寓,雨逾俞宇,欲渔欤?鬻玉欤?”
      于瑜与余御雨于俞寓,俞鬻玉于余禹,雨愈,余与于瑜踽踽逾俞宇,渔于渝淤。
    3、《季姬击鸡记》
      季姬寂,集鸡,鸡即棘鸡。棘鸡饥叽,季姬及箕稷济鸡。鸡既济,跻姬笈,季姬忌,急咭鸡,鸡急,继圾几,季姬急,即籍箕击鸡,箕疾击几伎,伎即齑,鸡叽集几基,季姬急极屐击鸡,鸡既殛,季姬激,即记《季姬击鸡记》。
    4、《遗镒疑医》
    伊姨殪,遗亿镒。伊诣邑,意医姨疫,一医医伊姨。翌,亿镒遗,疑医,以议医。医以伊疑,缢,以移伊疑。伊倚椅以忆,忆以亿镒遗,以议伊医,亦缢。噫!亦异矣!
    5、《易姨医胰》
      易姨悒悒,依议诣夷医。医疑胰疫,遗意易姨倚椅,以异仪移姨胰,弋异蚁一亿,胰液溢,蚁殪,胰以医。易胰怡怡,贻医一夷衣。医衣夷衣,怡怡奕奕。噫!以蚁医胰,异矣!以夷衣贻夷医亦宜矣!
    6、 赵元任《熙戏犀》
    西溪犀,喜嬉戏。席熙夕夕携犀徙,席熙细细习洗犀。犀吸溪,戏袭熙。席熙嘻嘻希息戏。惜犀嘶嘶喜袭熙。
    7、《饥鸡集矶记》
    唧唧鸡,鸡唧唧。几鸡挤挤集矶脊。机极疾,鸡饥极,鸡冀己技击及鲫。机既济蓟畿,鸡计疾机激几鲫。机疾极,鲫极悸,急急挤集矶级际。继即鲫迹极寂寂,继即几鸡既饥,即唧唧。
    8、《侄治痔》
    芝之稚侄郅,至智,知制纸,知织帜,芝痔炙痔,侄至芝址,知之知芷汁治痔,至芷址,执芷枝,蜘至,踯侄,执直枝掷之,蜘止,侄执芷枝至芝,芝执芷治痔,痔止。
    9、 最后也是最变态的:
    《羿裔熠邑彝》
    羿裔熠①,邑②彝,义医,艺诣。熠姨遗一裔伊③,伊仪迤,衣旖,异奕矣。熠意④伊矣,易衣以贻伊,伊遗衣,衣异衣以意异熠,熠抑矣。 伊驿邑,弋一翳⑤,弈毅⑥。毅仪奕,诣弈,衣异,意逸。毅诣伊,益伊,伊怡,已臆⑦毅矣,毅亦怡伊。 翌,伊亦弈毅。毅以蜴贻伊,伊亦贻衣以毅。 伊疫,呓毅,癔异矣,倚椅咿咿,毅亦咿咿。毅诣熠,意以熠,议熠医伊,熠懿⑧毅,意役毅逸。毅以熠宜伊,翼逸。熠驿邑以医伊,疑伊胰痍⑨,以蚁医伊,伊遗异,溢,伊咦。熠移伊,刈薏⑩以医,伊益矣。伊忆毅,亦呓毅矣,熠意伊毅已逸,熠意役伊。伊异,噫,缢。熠癔,亦缢。
        注解:
    ①熠:医生,据说为后羿的后裔。
    ②邑:以彝为邑,指居住在一个彝族聚居的地方。
    ③伊:绝世佳丽,仪态万方,神采奕奕。
    ④意:对伊有意思,指熠爱上了伊。
    ⑤翳:有遮蔽的地方,指伊游弋到了一个阴凉的地方。
    ⑥毅:逍遥不羁的浪人,善于下棋,神情坚毅,目光飘逸。
    ⑦臆:主观的感觉,通“意”,指对毅有好感。
    ⑧懿:原意为“懿旨”,此处引申为要挟,命令。
    ⑨胰痍:胰脏出现了疮痍。
    ⑩刈:割下草或者谷物一类。薏:薏米,白色,可供食用,也可入药