C#基礎教程/適合初學者

C#基礎教程

第一章       C#語言基礎

本章介紹C#語言的基礎知識,但願具備C語言的讀者可以基本掌握C#語言,並以此爲基礎,可以進一步學習用C#語言編寫window應用程序和Web應用程序。固然僅靠一章的內容就徹底掌握C#語言是不可能的,如需進一步學習C#語言,還須要認真閱讀有關C#語言的專著。html

1.1      C#語言特色

Microsoft.NET(如下簡稱.NET)框架是微軟提出的新一代Web軟件開發模型,C#語言是.NET框架中新一代的開發工具。C#語言是一種現代、面向對象的語言,它簡化了C++語言在類、命名空間、方法重載和異常處理等方面的操做,它摒棄了C++的複雜性,更易使用,更少出錯。它使用組件編程,和VB同樣容易使用。C#語法和C++和JAVA語法很是類似,若是讀者用過C++和JAVA,學習C#語言應是比較輕鬆的。git

用C#語言編寫的源程序,必須用C#語言編譯器將C#源程序編譯爲中間語言(MicroSoft Intermediate Language,MSIL)代碼,造成擴展名爲exe或dll文件。中間語言代碼不是CPU可執行的機器碼,在程序運行時,必須由通用語言運行環境(Common Language Runtime,CLR)中的既時編譯器(JUST IN Time,JIT)將中間語言代碼翻譯爲CPU可執行的機器碼,由CPU執行。CLR爲C#語言中間語言代碼運行提供了一種運行時環境,C#語言的CLR和JAVA語言的虛擬機相似。這種執行方法使運行速度變慢,但帶來其它一些好處,主要有:程序員

l  通用語言規範(Common Language Specification,CLS):.NET系統包括以下語言:C#、C++、VB、J#,他們都遵照通用語言規範。任何遵照通用語言規範的語言源程序,均可編譯爲相同的中間語言代碼,由CLR負責執行。只要爲其它操做系統編制相應的CLR,中間語言代碼也可在其它系統中運行。web

l  自動內存管理:CLR內建垃圾收集器,當變量實例的生命週期結束時,垃圾收集器負責收回不被使用的實例佔用的內存空間。沒必要象C和C++語言,用語句在堆中創建的實例,必須用語句釋放實例佔用的內存空間。也就是說,CLR具備自動內存管理功能。正則表達式

l  交叉語言處理:因爲任何遵照通用語言規範的語言源程序,均可編譯爲相同的中間語言代碼,不一樣語言設計的組件,能夠互相通用,能夠從其它語言定義的類派生出本語言的新類。因爲中間語言代碼由CLR負責執行,所以異常處理方法是一致的,這在調試一種語言調用另外一種語言的子程序時,顯得特別方便。sql

l  增長安全:C#語言不支持指針,一切對內存的訪問都必須經過對象的引用變量來實現,只容許訪問內存中容許訪問的部分,這就防止病毒程序使用非法指針訪問私有成員。也避免指針的誤操做產生的錯誤。CLR執行中間語言代碼前,要對中間語言代碼的安全性,完整性進行驗證,防止病毒對中間語言代碼的修改。數據庫

l  版本支持:系統中的組件或動態聯接庫可能要升級,因爲這些組件或動態聯接庫都要在註冊表中註冊,由此可能帶來一系列問題,例如,安裝新程序時自動安裝新組件替換舊組件,有可能使某些必須使用舊組件才能夠運行的程序,使用新組件運行不了。在.NET中這些組件或動態聯接庫沒必要在註冊表中註冊,每一個程序均可以使用自帶的組件或動態聯接庫,只要把這些組件或動態聯接庫放到運行程序所在文件夾的子文件夾bin中,運行程序就自動使用在bin文件夾中的組件或動態聯接庫。因爲不須要在註冊表中註冊,軟件的安裝也變得容易了,通常將運行程序及庫文件拷貝到指定文件夾中就能夠了。編程

l  徹底面向對象:不象C++語言,即支持面向過程程序設計,又支持面向對象程序設計,C#語言是徹底面向對象的,在C#中再也不存在全局函數、全局變量,全部的函數、變量和常量都必須定義在類中,避免了命名衝突。C#語言不支持多重繼承。小程序

1.2      編寫控制檯應用程序

                使用SDK命令行工具編寫控制檯程序

第一個程序老是很是簡單的,程序首先讓用戶經過鍵盤輸入本身的名字,而後程序在屏幕上打印一條歡迎信息。程序的代碼是這樣的:c#

using System;//導入命名空間。//爲C#語言新增解釋方法,解釋到本行結束

class Welcome//類定義,類的概念見下一節

{ /*解釋開始,和C語言解釋用法相同

解釋結束*/

static void Main()//主程序,程序入口函數,必須在一個類中定義

{ Console.WriteLine("請鍵入你的姓名:");//控制檯輸出字符串

Console.ReadLine();//從鍵盤讀入數據,輸入回車結束

Console.WriteLine("歡迎!");

}

}

能夠用任意一種文本編輯軟件完成上述代碼的編寫,而後把文件存盤,假設文件名叫作welcome.cs,C#源文件是以cs做爲文件的擴展名。和C語言相同,C#語言是區分大小寫的。高級語言老是依賴於許多在程序外部預約義的變量和函數。在C或C++中這些定義通常放到頭文件中,用#include語句來導入這個頭文件。而在C#語言中使用using語句導入名字空間,using System語句意義是導入System名字空間,C#中的using語句的用途與C++中#include語句的用途基本相似,用於導入預約義的變量和函數,這樣在本身的程序中就能夠自由地使用這些變量和函數。若是沒有導入名字空間的話咱們該怎麼辦呢?程序還能保持正確嗎?答案是確定的,那樣的話咱們就必須把代碼改寫成下面的樣子:

class Welcome

{ static void Main()

{ System.Console.WriteLine("請鍵入你的姓名:");

System.Console.ReadLine();

System.Console.WriteLine("歡迎!");

}

}

也就是在每一個Console前加上一個前綴System.,這個小原點表示Console是做爲System的成員而存在的。C#中拋棄了C和C++中繁雜且極易出錯的操做符象::和->等,C#中的複合名字一概經過.來鏈接。System是.Net平臺框架提供的最基本的名字空間之一,有關名字空間的詳細使用方法將在之後詳細介紹,這裏只要學會怎樣導入名字空間就足夠了。

程序的第二行class Welcome聲明瞭一個類,類的名字叫作Welcome。C#程序中每一個變量或函數都必須屬於一個類,包括主函數Main(),不能象C或C++那樣創建全局變量。C#語言程序老是從Main()方法開始執行,一個程序中不容許出現兩個或兩個以上的Main()方法。請牢記C#中Main()方法必須被包含在一個類中,Main第一個字母必須大寫,必須是一個靜態方法,也就是Main()方法必須使用static修飾。static void Main()是類Welcome中定義的主函數。靜態方法意義見之後章節。

程序所完成的輸入輸出功能是經過Console類來完成的,Console是在名字空間System中已經定義好的一個類。Console類有兩個最基本的方法WriteLine和ReadLine。ReadLine表示從輸入設備輸入數據,WriteLine則用於在輸出設備上輸出數據。

若是在電腦上安裝了Visual Studio.Net,則能夠在集成開發環境中直接選擇快捷鍵或菜單命令編譯並執行源文件。若是您不具有這個條件,那麼至少須要安裝Microsoft.Net Framework SDK,這樣纔可以運行C#語言程序。Microsoft.Net Framework SDK中內置了C#的編譯器csc.exe,下面讓咱們使用這個微軟提供的命令行編譯器對程序welcome.cs進行編譯。假設已經將welcome.cs文件保存在d:\Charp目錄下,啓動命令行提示符,在屏幕上輸入一行命令:d:回車,cd Charp回車,鍵入命令:

C:\WINNT\Microsoft.NET\Framework\v1.0.3705\csc welcome.cs

若是一切正常welcome.cs文件將被編譯,編譯後生成可執行文件Welcome.exe。能夠在命令提示符窗口運行可執行文件Welcome.exe,屏幕上出現一行字符提示您輸入姓名:請鍵入你的姓名:輸入任意字符並按下回車鍵,屏幕將打印出歡迎信息:歡迎!

注意,和咱們使用過的絕大多數編譯器不一樣,在C#中編譯器只執行編譯這個過程,而在C和C++中要通過編譯和連接兩個階段。換而言之C#源文件並不被編譯爲目標文件.obj,而是直接生成可執行文件.exe或動態連接庫.dll,C#編譯器中不須要包含連接器。

                使用Visual Studio.Net創建控制檯程序

(1)    運行Visual Studio.Net程序,出現如圖1.2.2A界面。

(2)    單擊新建項目按鈕,出現如圖1.2.2B對話框。在項目類型(P)編輯框中選擇Visual C#項目,在模板(T)編輯框中選擇控制檯應用程序,在名稱(N)編輯框中鍵入e1,在位置(L)編輯框中鍵入D:\csarp,必須預先建立文件夾D:\csarp。也能夠單擊瀏覽按鈕,在打開文件對話框中選擇文件夾。單擊肯定按鈕,建立項目。出現如圖1.2.2C界面。編寫一個應用程序,可能包含多個文件,才能生成可執行文件,全部這些文件的集合叫作一個項目。

(3)    修改class1.cs文件以下,有陰影部分是新增長的語句,其他是集成環境自動生成的。

using System;

namespace e1

{

    /// <summary>

    /// Class1 的摘要說明。

    /// </summary>

    class Class1

    {

        /// <summary>

        /// 應用程序的主入口點。

        /// </summary>

        [STAThread]

        static void Main(string[] args)

        {

            //

            // TODO: 在此處添加代碼以啓動應用程序

            //

            Console.WriteLine("請鍵入你的姓名:");

            Console.ReadLine();

            Console.WriteLine("歡迎!");

        }

    }

}

(4) 按CTRL+F5鍵,運行程序,如右圖,和1.2.1節運行效果相同。屏幕上出現一行字符,提示您輸入姓名:請鍵入你的姓名:輸入任意字符並按下回車鍵,屏幕將打印出歡迎信息:歡迎!輸入回車退出程序。

 

 

 

 

圖1.2.2A

 

圖1.2.2B

 

 

1.3      類的基本概念

C#語言是一種現代、面向對象的語言。面向對象程序設計方法提出了一個全新的概念:類,它的主要思想是將數據(數據成員)及處理這些數據的相應方法(函數成員)封裝到類中,類的實例則稱爲對象。這就是咱們常說的封裝性。

                類的基本概念

類能夠認爲是對結構的擴充,它和C中的結構最大的不一樣是:類中不但能夠包括數據,還包括處理這些數據的函數。類是對數據和處理數據的方法(函數)的封裝。類是對某一類具備相同特性和行爲的事物的描述。例如,定義一個描述我的狀況的類Person以下:

using System;

class Person//類的定義,class是保留字,表示定義一個類,Person是類名

{   private string name="張三";//類的數據成員聲明

private int age=12;//private表示私有數據成員

public void Display()//類的方法(函數)聲明,顯示姓名和年齡

{   Console.WriteLine("姓名:{0},年齡:{1}",name,age);

}

public void SetName(string PersonName)//修改姓名的方法(函數)

{     name=PersonName;

}

public void SetAge(int PersonAge)

{     age=PersonAge;

}

}

Console.WriteLine("姓名:{0},年齡:{1}",name,age)的意義是將第二個參數變量name變爲字符串填到{0}位置,將第三個參數變量age變爲字符串填到{1}位置,將第一個參數表示的字符串在顯示器上輸出。

你們注意,這裏咱們實際定義了一個新的數據類型,爲用戶本身定義的數據類型,是對我的的特性和行爲的描述,他的類型名爲Person,和int,char等同樣爲一種數據類型。用定義新數據類型Person類的方法把數據和處理數據的函數封裝起來。類的聲明格式以下:

屬性 類修飾符 class 類名{類體}

其中,關鍵字class、類名和類體是必須的,其它項是可選項。類修飾符包括new、public、protected、internal、private、abstract和sealed,這些類修飾符之後介紹。類體用於定義類的成員。

1.3.2  類成員的存取控制

通常但願類中一些數據不被隨意修改,只能按指定方法修改,既隱蔽一些數據。一樣一些函數也不但願被其它類程序調用,只能在類內部使用。如何解決這個問題呢?可用訪問權限控制字,經常使用的訪問權限控制字以下:private(私有),public(公有)。在數據成員或函數成員前增長訪問權限控制字,能夠指定該數據成員或函數成員的訪問權限。

私有數據成員只能被類內部的函數使用和修改,私有函數成員只能被類內部的其它函數調用。類的公有函數成員能夠被類的外部程序調用,類的公有數據成員能夠被類的外部程序直接使用修改。公有函數實際是一個類和外部通信的接口,外部函數經過調用公有函數,按照預先設定好的方法修改類的私有成員。對於上述例子,name和age是私有數據成員,只能經過公有函數SetName()和SetAge()修改,既它們只能按指定方法修改。

這裏再一次解釋一下封裝,它有兩個意義,第一是把數據和處理數據的方法同時定義在類中。第二是用訪問權限控制字使數據隱蔽。

1.3.3  類的對象

Person類僅是一個用戶新定義的數據類型,由它能夠生成Person類的實例,C#語言叫對象。用以下方法聲明類的對象:Person OnePerson=new Person();此語句的意義是創建Person類對象,返回對象地址賦值給Person類變量OnePerson。也能夠分兩步建立Person類的對象:Person OnePerson;OnePerson=new Person();OnePerson雖然存儲的是Person類對象地址,但不是C中的指針,不能象指針那樣能夠進行加減運算,也不能轉換爲其它類型地址,它是引用型變量,只能引用(表明)Person對象,具體意義參見之後章節。和C、C++不一樣,C#只能用此種方法生成類對象。

在程序中,能夠用OnePerson.方法名或OnePerson.數據成員名訪問對象的成員。例如:OnePerson.Display(),公用數據成員也能夠這樣訪問。注意,C#語言中不包括C++語言中的->符號。

1.3.4  類的構造函數和析構函數

在創建類的對象時,需作一些初始化工做,例如對數據成員初始化。這些能夠用構造函數來完成。每當用new生成類的對象時,自動調用類的構造函數。[終於明白了1] 所以,能夠把初始化的工做放到構造函數中完成。構造函數和類名相同,沒有返回值。例如能夠定義Person類的構造函數以下:

public Person(string Name,int Age)//類的構造函數,函數名和類同名,無返回值。

{     name=Name;

age=Age;

}

當用Person OnePerson=new Person(「張五」,20)語句生成Person類對象時,將自動調用以上構造函數。請注意如何把參數傳遞給構造函數。

變量和類的對象都有生命週期,生命週期結束,這些變量和對象就要被撤銷。類的對象被撤銷時,將自動調用析構函數。一些善後工做可放在析構函數中完成。析構函數的名字爲~類名,無返回類型,也無參數。Person類的析構函數爲~ Person()。C#中類析構函數不能顯示地被調用,它是被垃圾收集器撤銷不被使用的對象時自動調用的。

1.3.5  類的構造函數的重載

在C#語言中,同一個類中的函數,若是函數名相同,而參數類型或個數不一樣,認爲是不一樣的函數,這叫函數重載。僅返回值不一樣,不能看做不一樣的函數。這樣,能夠在類定義中,定義多個構造函數,名字相同,參數類型或個數不一樣。根據生成類的對象方法不一樣,調用不一樣的構造函數。例如能夠定義Person類沒有參數的構造函數以下:

public Person()//類的構造函數,函數名和類同名,無返回值。

{   name="張三";

age=12;

}

用語句Person OnePerson=new Person("李四",30)生成對象時,將調用有參數的構造函數,而用語句Person OnePerson=new Person()生成對象時,調用無參數的構造函數。因爲析構函數無參數,所以,析構函數不能重載。

1.3.6  使用Person類的完整的例子

下邊用一個完整的例子說明Person類的使用:(VisualStudio.Net編譯經過)

using System;

namespace e1//定義如下代碼所屬命名空間,意義見之後章節

{   class Person

{   private String name="張三";//類的數據成員聲明

private int age=12;

public void Display()//類的方法(函數)聲明,顯示姓名和年齡

{   Console.WriteLine("姓名:{0},年齡:{1}",name,age);

}

public void SetName(string PersonName)//指定修改姓名的方法(函數)

{   name=PersonName;

}

public void SetAge(int PersonAge)//指定修改年齡的方法(函數)

{   age=PersonAge;

}

public Person(string Name,int Age)//構造函數,函數名和類同名,無返回值

{   name=Name;

age=Age;

}

public Person()//類的構造函數重載

{   name="田七";

age=12;

}

}

class Class1

{   static void Main(string[] args)

{   Person OnePerson=new Person("李四",30);//生成類的對象

OnePerson.Display();

//下句錯誤,在其它類(Class1類)中,不能直接修改Person類中的私有成員。

//OnePerson.name="王五";

//只能經過Person類中公有方法SetName修改Person類中的私有成員name。

OnePerson.SetName("王五");

OnePerson.SetAge(40);

OnePerson.Display();

OnePerson=new Person();

OnePerson.Display();

}

}

}

鍵入CTRL+F5運行後,顯示的效果是:

姓名: 李四,年齡:30

姓名: 王五,年齡:40

姓名: 田七,年齡:12

1.4      C#的數據類型

從大的方面來分,C#語言的數據類型能夠分爲三種:值類型,引用類型,指針類型,指針類型僅用於非安全代碼中。本節重點討論值類型和引用類型。

1.4.1  值類型和引用類型區別

在C#語言中,值類型變量存儲的是數據類型所表明的實際數據,值類型變量的值(或實例)存儲在棧(Stack)中,賦值語句是傳遞變量的值。引用類型(例如類就是引用類型)的實例,也叫對象,不存在棧中,而存儲在可管理堆(Managed Heap)中,堆其實是計算機系統中的空閒內存。引用類型變量的值存儲在棧(Stack)中,但存儲的不是引用類型對象,而是存儲引用類型對象的引用,即地址,和指針所表明的地址不一樣,引用所表明的地址不能被修改,也不能轉換爲其它類型地址,它是引用型變量,只能引用指定類對象,引用類型變量賦值語句是傳遞對象的地址。見下例:

using System;

class MyClass//類爲引用類型

{   public int a=0;

}

class Test

{   static void Main()

{   f1();

}

static public void f1()

{   int v1=1;//值類型變量v1,其值1存儲在棧(Stack)中

int v2=v1;//將v1的值(爲1)傳遞給v2,v2=1,v1值不變。

v2=2;//v2=2,v1值不變。

MyClass r1=new MyClass();//引用變量r1存儲MyClass類對象的地址

MyClass r2=r1;//r1和r2都表明是同一個MyClass類對象

r2.a=2;//和語句r1.a=2等價

}

}

存儲在棧中的變量,當其生命週期結束,自動被撤銷,例如,v1存儲在棧中,v1和函數f1同生命週期,退出函數f1,v1不存在了。但在堆中的對象不能自動被撤銷。所以C和C++語言,在堆中創建的對象,不使用時必須用語句釋放對象佔用的存儲空間。.NET系統CLR內建垃圾收集器,當對象的引用變量被撤銷,表示對象的生命週期結束,垃圾收集器負責收回不被使用的對象佔用的存儲空間。例如,上例中引用變量r1及r2是MyClass類對象的引用,存儲在棧中,退出函數f1,r1和r2都不存在了,在堆中的MyClass類對象也就被垃圾收集器撤銷。也就是說,CLR具備自動內存管理功能。[終於明白了2] 

1.4.2  值類型變量分類

C#語言值類型能夠分爲如下幾種:

l  簡單類型(Simple types)

簡單類型中包括:數值類型和布爾類型(bool)。數值類型又細分爲:整數類型、字符類型(char)、浮點數類型和十進制類型(decimal)。

l  結構類型(Struct types)

l  枚舉類型(Enumeration types)

C#語言值類型變量不管如何定義,老是值類型變量,不會變爲引用類型變量。

1.4.3  結構類型

結構類型和類同樣,能夠聲明構造函數、數據成員、方法、屬性等。結構和類的最根本的區別是結構是值類型,類是引用類型。和類不一樣,結構不能從另一個結構或者類派生,自己也不能被繼承,所以不能定義抽象結構,結構成員也不能被訪問權限控制字protected修飾,也不能用virtual和abstract修飾結構方法。在結構中不能定義析構函數。雖然結構不能從類和結構派生,但是結構可以繼承接口,結構繼承接口的方法和類繼承接口的方法基本一致。下面例子定義一個點結構point:

using System;

struct point//結構定義

{   public int x,y;//結構中也能夠聲明構造函數和方法,變量不能賦初值

}

class Test

{   static void Main()

{   point P1;

P1.x=166;

P1.y=111;

point P2;

P2=P1;//值傳遞,使P2.x=166,P2.y=111

point P3=new point();//用new生成結構變量P3,P3仍爲值類型變量

}//用new生成結構變量P3僅表示調用默認構造函數,使x=y==0。

}

1.4.4  簡單類型

簡單類型也是結構類型,所以有構造函數、數據成員、方法、屬性等,所以下列語句int i=int.MaxValue;string s=i.ToString()是正確的。即便一個常量,C#也會生成結構類型的實例,所以也能夠使用結構類型的方法,例如:string s=13.ToString()是正確的。簡單類型包括:整數類型、字符類型、布爾類型、浮點數類型、十進制類型。見下表:

保留字

System命名空間中的名字

字節數

取值範圍

sbyte

System.Sbyte

1

-128~127

byte

System.Byte

1

0~255

short

System.Int16

2

-32768~32767

ushort

System.UInt16

2

0~65535

int

System.Int32

4

-2147483648~2147483647

uint

System.UInt32

4

0~4292967295

long

System.Int64

8

-9223372036854775808~9223372036854775808

ulong

System.UInt64

8

0~18446744073709551615

char

System.Char

2

0~65535

float

System.Single

4

3.4E-38~3.4E+38

double

System.Double

8

1.7E-308~1.7E+308

bool

System.Boolean

 

(true,false)

decimal

System.Decimal

16

正負 1.0×10-28 到7.9×1028之間

C#簡單類型使用方法和C、C++中相應的數據類型基本一致。須要注意的是:

l  和C語言不一樣,不管在何種系統中,C#每種數據類型所佔字節數是必定的。

l  字符類型採用Unicode字符集,一個Unicode標準字符長度爲16位。

l  整數類型不能隱式被轉換爲字符類型(char),例如char c1=10是錯誤的,必須寫成:char c1=(char)10,char c='A',char c='\x0032';char c='\u0032'。

l  布爾類型有兩個值:false,true。不能認爲整數0是false,其它值是true。bool x=1是錯誤的,不存在這種寫法,只能寫成x=true 或x=false。

l  十進制類型(decimal)也是浮點數類型,只是精度比較高,通常用於財政金融計算。

1.4.5  枚舉類型

C#枚舉類型使用方法和C、C++中的枚舉類型基本一致。見下例:

using System;

class Class1

{   enum Days {Sat=1, Sun, Mon, Tue, Wed, Thu, Fri};

    //使用Visual Studio.Net,enum語句添加在[STAThread]前邊

    static void Main(string[] args)

    {   Days day=Days.Tue;

        int x=(int)Days.Tue;//x=2

        Console.WriteLine("day={0},x={1}",day,x);//顯示結果爲:day=Tue,x=4

    }

}

在此枚舉類型Days中,每一個元素的默認類型爲int,其中Sun=0,Mon=1,Tue=2,依此類推。也能夠直接給枚舉元素賦值。例如:

enum Days{Sat=1,Sun,Mon,Tue,Wed,Thu,Fri,Sat};

[終於明白了3] 在此枚舉中,Sun=1,Mon=2,Tue=3,Wed=4,等等。和C、C++中不一樣,C#枚舉元素類型能夠是byte、sbyte、short、ushort、int、uint、long和ulong類型,但不能是char類型。見下例:

enum Days:byte{Sun,Mon,Tue,Wed,Thu,Fri,Sat};//元素爲字節類型

1.4.6  值類型的初值和默認構造函數

全部變量都要求必須有初值,如沒有賦值,採用默認值。對於簡單類型,sbyte、byte、short、ushort、int、uint、long和ulong默認值爲0,char類型默認值是(char)0,float爲0.0f,double爲0.0d,decimal爲0.0m,bool爲false,枚舉類型爲0,在結構類型和類中,數據成員的數值類型變量設置爲默認值,引用類型變量設置爲null。

能夠顯示的賦值,例如int i=0。而對於複雜結構類型,其中的每一個數據成員都按此種方法賦值,顯得過於麻煩。因爲數值類型都是結構類型,可用new語句調用其構造函數初始化數值類型變量,例如:int j=new int()。請注意,用new語句並非把int變量變爲引用變量,j還是值類型變量,這裏new僅僅是調用其構造函數。全部的數值類型都有默認的無參數的構造函數,其功能就是爲該數值類型賦初值爲默認值。對於自定義結構類型,因爲已有默認的無參數的構造函數,不能再定義無參數的構造函數,但能夠定義有參數的構造函數。

1.4.7  引用類型分類

C#語言中引用類型能夠分爲如下幾種:

l  類:C#語言中預約義了一些類:對象類(object類)、數組類、字符串類等。固然,程序員能夠定義其它類。

l  接口。

l  表明。

C#語言引用類型變量不管如何定義,老是引用類型變量,不會變爲值類型變量。C#語言引用類型對象通常用運算符new創建,用引用類型變量引用該對象。本節僅介紹對象類型(object類型)、字符串類型、數組。其它類型在其它節中介紹。

1.4.8  對象類(object類)

C#中的全部類型(包括數值類型)都直接或間接地以object類爲基類。對象類(object類)是全部其它類的基類。任何一個類定義,若是不指定基類,默認object爲基類。繼承和基類的概念見之後章節。C#語言規定,基類的引用變量能夠引用派生類的對象(注意,派生類的引用變量不能夠引用基類的對象),所以,對一個object的變量能夠賦予任何類型的值:

int x =25;

object obj1;

obj1=x;

object obj2= 'A';

object關鍵字是在命名空間System中定義的,是類System.Object的別名。

1.4.9  數組類

在進行批量處理數據的時候,要用到數組。數組是一組類型相同的有序數據。數組按照數組名、數據元素的類型和維數來進行描述。C#語言中數組是類System.Array類對象,好比聲明一個整型數數組:int[] arr=new int[5];實際上生成了一個數組類對象,arr是這個對象的引用(地址)。

在C#中數組能夠是一維的也能夠是多維的,一樣也支持數組的數組,即數組的元素仍是數組。一維數組最爲廣泛,用的也最多。咱們先看一個一維數組的例子:

using System;

class Test

{ static void Main()

{ int[] arr=new int[3];//用new運算符創建一個3個元素的一維數組

for(int i=0;i<arr.Length;i++)//arr.Length是數組類變量,表示數組元素個數

arr[i]=i*i;//數組元素賦初值,arr[i]表示第i個元素的值

for (int i=0;i<arr.Length;i++)//數組第一個元素的下標爲0

Console.WriteLine("arr[{0}]={1}",i,arr[i]);

}

}

這個程序建立了一個int類型3個元素的一維數組,初始化後逐項輸出。其中arr.Length表示數組元素的個數。注意數組定義不能寫爲C語言格式:int arr[]。程序的輸出爲:

arr[0] = 0

arr[1] = 1

arr[2] = 4

上面的例子中使用的是一維數組,下面介紹多維數組:

string[] a1;//一維string數組類引用變量a1

string[,] a2;//二維string數組類引用變量a2

a2=new string[2,3];

a2[1,2]="abc";

string[,,] a3;//三維string數組類引用變量a3

string[][] j2;//數組的數組,即數組的元素仍是數組

string[][][][] j3;

在數組聲明的時候,能夠對數組元素進行賦值。看下面的例子:

int[] a1=new int[]{1,2,3};//一維數組,有3個元素。

int[] a2=new int[3]{1,2,3};//此格式也正確

int[] a3={1,2,3};//至關於int[] a3=new int[]{1,2,3};

int[,] a4=new int[,]{{1,2,3},{4,5,6}};//二維數組,a4[1,1]=5

int[][] j2=new int[3][];//定義數組j2,有三個元素,每一個元素都是一個數組

j2[0]=new int[]{1,2,3};//定義第一個元素,是一個數組

j2[1]=new int[]{1, 2, 3, 4, 5, 6};//每一個元素的數組能夠不等長

j2[2]=new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9};

1.4.10 字符串類(string類)

C#還定義了一個基本的類string,專門用於對字符串的操做。這個類也是在名字空間System中定義的,是類System.String的別名。字符串應用很是普遍,在string類的定義中封裝了許多方法,下面的一些語句展現了string類的一些典型用法:

l  字符串定義

string s;//定義一個字符串引用類型變量s

s="Zhang";//字符串引用類型變量s指向字符串"Zhang"

string  FirstName="Ming";

string  LastName="Zhang";

string  Name=FirstName+"  "+LastName;//運算符+已被重載

string  SameName=Name;

char[] s2={'計','算','機','科','學'};

string s3=new String(s2);

l  字符串搜索

string s="ABC科學";

int i=s.IndexOf("科");

搜索"科"在字符串中的位置,因第一個字符索引爲0,因此"A"索引爲0,"科"索引爲3,所以這裏i=3,如沒有此字符串i=-1。注意C#中,ASCII和漢字都用2字節表示。

l  字符串比較函數

string s1="abc";

string s2="abc";

int n=string.Compare(s1,s2);//n=0

n=0表示兩個字符串相同,n小於零,s1<s2,n大於零,s1>s2。此方法區分大小寫。也可用以下辦法比較字符串:

string s1="abc";

string s="abc";

string s2="不相同";

if(s==s1)//還可用!=。雖然String是引用類型,但這裏比較兩個字符串的值

s2="相同";

l  判斷是否爲空字符串

string s="";

string s1="不空";

if(s.Length==0)

s1="空";

l  獲得子字符串或字符

string s="取子字符串";

string sb=s.Substring(2,2);//從索引爲2開始取2個字符,Sb="字符",s內容不變

char sb1=s[0];//sb1='取'

Console.WriteLine(sb1);//顯示:取

l  字符串刪除函數

string s="取子字符串";

string sb=s.Remove(0,2);//從索引爲0開始刪除2個字符,Sb="字符串",s內容不變

l  插入字符串

string s="計算機科學";

string s1=s.Insert(3,"軟件");//s1="計算機軟件科學",s內容不變

l  字符串替換函數

string s="計算機科學";

string s1=s.Replace("計算機","軟件");//s1="軟件科學",s內容不變

l  把String轉換爲字符數組

string S="計算機科學";

char[] s2=S.ToCharArray(0,S.Length);//屬性Length爲字符類對象的長度

l  其它數據類型轉換爲字符串

int i=9;

string s8=i.ToString();//s8="9"

float n=1.9f;

string s9=n.ToString();//s8="1.9"

其它數據類型均可用此方法轉換爲字符類對象

l  大小寫轉換

string s="AaBbCc";

string s1=s.ToLower();//把字符轉換爲小寫,s內容不變

string s2=s.ToUpper();//把字符轉換爲大寫,s內容不變

l  刪除全部的空格

string s="A   bc ";

s.Trim();//刪除全部的空格

string類其它方法的使用請用幫助系統查看,方法是打開Visual Studio.Net的代碼編輯器,鍵入string,將光標移到鍵入的字符串string上,而後按F1鍵。

1.4.11 類型轉換

在編寫C#語言程序中,常常會碰到類型轉換問題。例如整型數和浮點數相加,C#會進行隱式轉換。詳細記住那些類型數據能夠轉換爲其它類型數據,是不可能的,也是沒必要要的。程序員應記住類型轉換的一些基本原則,編譯器在轉換髮生問題時,會給出提示。C#語言中類型轉換分爲:隱式轉換、顯示轉換、加框(boxing)和消框(unboxing)等三種。

一.隱式轉換

隱式轉換就是系統默認的、不須要加以聲明就能夠進行的轉換。例如從int類型轉換到long類型就是一種隱式轉換。在隱式轉換過程當中,轉換通常不會失敗,轉換過程當中也不會致使信息丟失。例如:

int i=10;

long l=i;

二.顯示轉換

顯式類型轉換,又叫強制類型轉換。與隱式轉換正好相反,顯式轉換須要明確地指定轉換類型,顯示轉換可能致使信息丟失。下面的例子把長整形變量顯式轉換爲整型:

long l=5000;

int i=(int)l;//若是超過int取值範圍,將產生異常

三.加框(boxing)和消框(unboxing)

加框(boxing)和消框(unboxing)是C#語言類型系統提出的核心概念,加框是值類型轉換爲object(對象)類型,消框是object(對象)類型轉換爲值類型。有了加框和消框的概念,對任何類型的變量來講最終咱們均可以看做是object類型。

1 加框操做

把一個值類型變量加框也就是建立一個object對象,並將這個值類型變量的值複製給這個object對象。例如:

int i=10;

object obj=i;//隱式加框操做,obj爲建立的object對象的引用。

咱們也能夠用顯式的方法來進行加框操做,例如:

int i =10;

object obj=object(i);//顯式加框操做

值類型的值加框後,值類型變量的值不變,僅將這個值類型變量的值複製給這個object對象。咱們看一下下面的程序:

using System

class Test

{   public static void Main()

{   int n=200;

object o=n;

o=201;//不能改變n

Console.WriteLine("{0},{1}",n,o);

}

}

輸出結果爲:200,201。這就證實了值類型變量n和object類對象o都獨立存在着。

2. 消框操做

和加框操做正好相反,消框操做是指將一個對象類型顯式地轉換成一個值類型。消框的過程分爲兩步:首先檢查這個object對象,看它是否爲給定的值類型的加框值,如是,把這個對象的值拷貝給值類型的變量。咱們舉個例子來看看一個對象消框的過程:

int i=10;

object obj=i;

int j=(int)obj;//消框操做

能夠看出消框過程正好是加框過程的逆過程,必須注意加框操做和消框操做必須遵循類型兼容的原則。

  1. 3.  加框和消框的使用

定義以下函數:

void Display(Object o)//注意,o爲Object類型

{   int x=(int)o;//消框

System.Console.WriteLine("{0},{1}",x,o);

}

調用此函數:int y=20;Display(y);在此利用了加框概念,虛參被實參替換:Object o=y,也就是說,函數的參數是Object類型,能夠將任意類型實參傳遞給函數。

1.5      運算符

C#語言和C語言的運算符用法基本一致。如下重點講解兩者之間不一致部分。

1.5.1  運算符分類

與C語言同樣,若是按照運算符所做用的操做數個數來分,C#語言的運算符能夠分爲如下幾種類型:

l  一元運算符:一元運算符做用於一個操做數,例如:-X、++X、X--等。

l  二元運算符:二元運算符對兩個操做數進行運算,例如:x+y。

l  三元運算符:三元運算符只有一個:x? y:z。

C#語言運算符的詳細分類及操做符從高到低的優先級順序見下表。

類別

操做符

初級操做符

(x) x.y f(x) a[x] x++ x-- new type of sizeof checked unchecked

一元操做符

+ - ! ~ ++x –x (T)x

乘除操做符

* / %

加減操做符

+ -

移位操做符

<< >>

關係操做符

< > <= >= is as

等式操做符

== !=

邏輯與操做符

&

邏輯異或操做符

^

邏輯或操做符

|

條件與操做符

&&

條件或操做符

||

條件操做符

?:

賦值操做符

= *= /= %= += -= <<= >>= &= ^= |=

1.5.2  測試運算符is

is操做符用於動態地檢查表達式是否爲指定類型。使用格式爲:e is T,其中e是一個表達式,T是一個類型,該式判斷e是否爲T類型,返回值是一個布爾值。例子:

using System;

class Test

{ public static void Main()

{   Console.WriteLine(1 is int);

Console.WriteLine(1 is float);

Console.WriteLine(1.0f is float);

Console.WriteLine(1.0d is double);

}

}

輸出爲:

True

False

True

True

1.5.3  typeof運算符

typeof操做符用於得到指定類型在system名字空間中定義的類型名字,例如:

using System;

class Test

{   static void Main()

{   Console.WriteLine(typeof(int));

Console.WriteLine(typeof(System.Int32));

        Console.WriteLine(typeof(string));

    Console.WriteLine(typeof(double[]));

}

}

產生以下輸出,由輸出可知int和System.int32是同一類型。

System.Int32

System.Int32

System.String

System.Double[]

1.5.4  溢出檢查操做符checked和unchecked

在進行整型算術運算(如+、-、*、/等)或從一種整型顯式轉換到另外一種整型時,有可能出現運算結果超出這個結果所屬類型值域的狀況,這種狀況稱之爲溢出。整型算術運算表達式能夠用checked或unchecked溢出檢查操做符,決定在編譯和運行時是否對錶達式溢出進行檢查。若是表達式不使用溢出檢查操做符或使用了checked操做符,常量表達式溢出,在編譯時將產生錯誤,表達式中包含變量,程序運行時執行該表達式產生溢出,將產生異常提示信息。而使用了unchecked操做符的表達式語句,即便表達式產生溢出,編譯和運行時都不會產生錯誤提示。但這每每會出現一些不可預期的結果,因此使用unchecked操做符要當心。下面的例子說明了checked和unchecked操做符的用法:

using System;

class Class1

{   static void Main(string[] args)

    {   const int x=int.MaxValue;

        unchecked//不檢查溢出

        {   int z=x*2;//編譯時不產生編譯錯誤,z=-2

            Console.WriteLine("z={0}",z);//顯示-2

        }

        checked//檢查溢出

        {   int z1=(x*2);//編譯時會產生編譯錯誤

            Console.WriteLine("z={0}",z1);

        }

    }

}

1.5.5  new運算符

new操做符能夠建立值類型變量、引用類型對象,同時自動調用構造函數。例如:

int x=new int();//用new建立整型變量x,調用默認構造函數

Person C1=new Person ();//用new創建的Person類對象。Person 變量C1對象的引用

int[] arr=new int[2];//數組也是類,建立數組類對象,arr是數組對象的引用

需注意的是,int x=new int()語句將自動調用int結構不帶參數的構造函數,給x賦初值0,x還是值類型變量,不會變爲引用類型變量。

1.5.6  運算符的優先級

當一個表達式包含多種操做符時,操做符的優先級控制着操做符求值的順序。例如,表達式x+y*z按照x+(y*z)順序求值,由於*操做符比+操做符有更高的優先級。這和數學運算中的先乘除後加減是一致的。1.5.1節中的表總結了全部操做符從高到低的優先級順序。

當兩個有相同優先級的操做符對操做數進行運算時,例如x+y-z,操做符按照出現的順序由左至右執行,x+y-z按(x+y)-z進行求值。賦值操做符按照右接合的原則,即操做按照從右向左的順序執行。如x=y=z按照x=(y=z)進行求值。建議在寫表達式的時候,若是沒法肯定操做符的實際順序,則儘可能採用括號來保證運算的順序,這樣也使得程序一目瞭然,並且本身在編程時可以思路清晰。

1.6      程序控制語句

C#語言控制語句和C基本相同,使用方法基本一致。C#語言控制語句包括:if語句、swith語句、while語句、do…while語句、for語句、foreach語句、break語句、continue語句、goto語句、return語句、異常處理語句等,其中foreach語句和異常語句是C#語言新增長控制語句。本節首先介紹一下這些語句和C語言的不一樣點,而後介紹C#語言新增的控制語句。

1.6.1  和C語言的不一樣點

l  與C不一樣,if語句、while語句、do…while語句、for語句中的判斷語句,必定要用布爾表達式,不能認爲0爲false,其它數爲true。

l  switch語句再也不支持遍歷,C和C++語言容許switch語句中case標籤後不出現break語句,但C#不容許這樣,它要求每一個case標籤項後使用break語句或goto跳轉語句,即不容許從一個case自動遍歷到其它case,不然編譯時將報錯。switch語句的控制類型,即其中控制表達式的數據類型能夠是sbyte、byte、short、ushort、uint、long、ulong、char、string或枚舉類型。每一個case標籤中的常量表達式必須屬於或能隱式轉換成控制類型。若是有兩個或兩個以上case標籤中的常量表達式值相同,編譯時將會報錯。執行switch語句,首先計算switch表達式,而後與case後的常量表達式的值進行比較,執行第一個與之匹配的case分支下的語句。若是沒有case常量表達式的值與之匹配,則執行dafault分支下的語句,若是沒有dafault語句,則退出switch語句。switch語句中能夠沒有dafault語句,但最多隻能有一個dafault語句。見下例:

using System;

class class1

{   static void Main()

{   System.Console.WriteLine("請輸入要計算天數的月份");

string s=System.Console.ReadLine();

string s1="";

switch(s)

{   case "1": case "3": case "5":

        case "7": case "8": case "10":

        case "12"://共用一條語句

            s1="31";break;

        case "2":

            s1="28";break;

case "4": case "6": case "9":

        goto case "11";//goto語句僅爲說明問題,無此必要

        case "11":

            s1="30";break;

default:

        s1="輸入錯誤";break;

}

System.Console.WriteLine(s1);

}

}

1.6.2  foreach語句

foreach語句是C#語言新引入的語句,C和C++中沒有這個語句,它借用Visual Basic中的foreach語句。語句的格式爲:

foreach(類型 變量名 in 表達式) 循環語句

其中表達式必須是一個數組或其它集合類型,每一次循環從數組或其它集合中逐一取出數據,賦值給指定類型的變量,該變量能夠在循環語句中使用、處理,但不容許修改變量,該變量的指定類型必須和表達式所表明的數組或其它集合中的數據類型一致。例子:

using System;

class Test()

{   public static void Main()

{   int[] list={10,20,30,40};//數組

foreach(int m in list)

    Console.WriteLine("{0}",m);

}

}

對於一維數組,foreach語句循環順序是從下標爲0的元素開始一直到數組的最後一個元素。對於多維數組,元素下標的遞增是從最右邊那一維開始的。一樣break和continue能夠出如今foreach語句中,功能不變。

1.6.3  異常語句

在編寫程序時,不只要關心程序的正常操做,還應該考慮到程序運行時可能發生的各種不可預期的事件,好比用戶輸入錯誤、內存不夠、磁盤出錯、網絡資源不可用、數據庫沒法使用等,全部這些錯誤被稱做異常,不能由於這些異常使程序運行產生問題。各類程序設計語言常常採用異常處理語句來解決這類異常問題。

C#提供了一種處理系統級錯誤和應用程序級錯誤的結構化的、統一的、類型安全的方法。C#異常語句包含try子句、catch子句和finally子句。try子句中包含可能產生異常的語句,該子句自動捕捉執行這些語句過程當中發生的異常。catch子句中包含了對不一樣異常的處理代碼,能夠包含多個catch子句,每一個catch子句中包含了一個異常類型,這個異常類型必須是System.Exception類或它的派生類引用變量,該語句只撲捉該類型的異常。能夠有一個通用異常類型的catch子句,該catch子句通常在事先不能肯定會發生什麼樣的異常的狀況下使用,也就是能夠撲捉任意類型的異常。一個異常語句中只能有一個通用異常類型的catch子句,並且若是有的話,該catch子句必須排在其它catch子句的後面。不管是否產生異常,子句finally必定被執行,在finally子句中能夠增長一些必須執行的語句。

異常語句捕捉和處理異常的機理是:當try子句中的代碼產生異常時,按照catch子句的順序查找異常類型。若是找到,執行該catch子句中的異常處理語句。若是沒有找到,執行通用異常類型的catch子句中的異常處理語句。因爲異常的處理是按照catch子句出現的順序逐一檢查catch子句,所以catch子句出現的順序是很重要的。不管是否產生異常,必定執行finally子句中的語句。異常語句中沒必要必定包含全部三個子句,所以異常語句能夠有如下三種可能的形式:

l  try –catch語句,能夠有多個catch語句

l  try -finally語句

l  try -catch-finally語句,能夠有多個catch語句

請看下邊的例子:

1. try–catch-finally語句

using System

using System.IO//使用文件必須引用的名字空間

public class Example

{   public static void Main()

{   StreamReader sr=null;//必須賦初值null,不然編譯不能經過

try

    {  sr=File.OpenText("d:\\csarp\\test.txt");//可能產生異常

       string s;

       while(sr.Peek()!=-1)

       {  s=sr.ReadLine();//可能產生異常

          Console.WriteLine(s);

        }

     }

    catch(DirectoryNotFoundException e)//無指定目錄異常

    {   Console.WriteLine(e.Message);

    }

    catch(FileNotFoundException e)//無指定文件異常

    {   Console.WriteLine("文件"+e.FileName+"未被發現");

    }

    catch(Exception e)//其它全部異常

    {  Console.WriteLine("處理失敗:{0}",e.Message);

    }

    finally

    {   if(sr!=null)

           sr.Close();

    }

}

}

2. try -finally語句

上例中,其實能夠不用catch語句,在finally子句中把文件關閉,提示用戶是否正確打開了文件,請讀者本身完成。

3. try -catch語句

請讀者把上例修改成使用try-catch結構,注意在每一個catch語句中都要關閉文件。

1.7      類的繼承

在1.3節,定義了一個描述我的狀況的類Person,若是咱們須要定義一個僱員類,固然能夠從頭開始定義僱員類Employee。但這樣不能利用Person類中已定義的函數和數據。比較好的方法是,以Person類爲基類,派生出一個僱員類Employee,僱員類Employee繼承了Person類的數據成員和函數成員,既Person類的數據成員和函數成員成爲Employee類的成員。這個Employee類叫以Person類爲基類的派生類,這是C#給咱們提出的方法。C#用繼承的方法,實現代碼的重用。

1.7.1  派生類的聲明格式

派生類的聲明格式以下:

屬性 類修飾符 class 派生類名:基類名 {類體}

僱員類Employee定義以下:

class Employee:Person//Person類是基類

{   private string department;//部門,新增數據成員

private decimal salary;//薪金,新增數據成員

public Employee(string Name,int Age,string D,decimal S):base(Name,Age)

{//注意base的第一種用法,根據參數調用指定基類構造函數,注意參數的傳遞

    department=D;

    salary=S;

    }

    public new void Display()//覆蓋基類Display()方法,注意new,不可用override

    {   base.Display();//訪問基類被覆蓋的方法,base的第二種用法

        Console.WriteLine("部門:{0}  薪金:{1}",department,salary);

    }

}

修改主函數以下:

class Class1

{   static void Main(string[] args)

{   Employee OneEmployee=new Employee("李四",30,"計算機系",2000);

OneEmployee.Display();

}

}

Employee類繼承了基類Person的方法SetName()、SetAge(),數據成員name和age,即認爲基類Person的這些成員也是Employee類的成員,但不能繼承構造函數和析構函數。添加了新的數據成員department和salary。覆蓋了方法Display()。請注意,雖然Employee類繼承了基類Person的name和age,但因爲它們是基類的私有成員,Employee類中新增或覆蓋的方法不能直接修改name和age,只能經過基類原有的公有方法SetName()和SetAge()修改。若是但願在Employee類中能直接修改name和age,必須在基類中修改它們的屬性爲protected。

1.7.2 base 關鍵字

base關鍵字用於從派生類中訪問基類成員,它有兩種基本用法:

l  在定義派生類的構造函數中,指明要調用的基類構造函數,因爲基類可能有多個構造函數,根據base後的參數類型和個數,指明要調用哪個基類構造函數。參見上節僱員類Employee構造函數定義中的base的第一種用法。

l  在派生類的方法中調用基類中被派生類覆蓋的方法。參見上節僱員類Employee的Display()方法定義中的base的第二種用法。

1.7.3 覆蓋基類成員

在派生類中,經過聲明與基類徹底相同新成員,能夠覆蓋基類的同名成員,徹底相同是指函數類型、函數名、參數類型和個數都相同。如上例中的方法Display()。派生類覆蓋基類成員不算錯誤,但會致使編譯器發出警告。若是增長new修飾符,表示承認覆蓋,編譯器再也不發出警告。請注意,覆蓋基類的同名成員,並非移走基類成員,只是必須用以下格式訪問基類中被派生類覆蓋的方法:base.Display()。

1.7.4 C#語言類繼承特色

C#語言類繼承有以下特色:

l  C#語言只容許單繼承,即派生類只能有一個基類。

l  C#語言繼承是能夠傳遞的,若是C從B派生,B從A派生,那麼C不但繼承B的成員,還要繼承A中的成員。

l  派生類能夠添加新成員,但不能刪除基類中的成員。

l  派生類不能繼承基類的構造函數、析構函數和事件。但能繼承基類的屬性。

l  派生類能夠覆蓋基類的同名成員,若是在派生類中覆蓋了基類同名成員,基類該成員在派生類中就不能被直接訪問,只能經過base.基類方法名訪問。

l  派生類對象也是其基類的對象,但基類對象卻不是其派生類的對象。例如,前邊定義的僱員類Employee是Person類的派生類,全部僱員都是人類,但不少人並非僱員,多是學生,自由職業者,兒童等。所以C#語言規定,基類的引用變量能夠引用其派生類對象,但派生類的引用變量不能夠引用其基類對象。

1.8      類的成員

因爲C#程序中每一個變量或函數都必須屬於一個類或結構,不能象C或C++那樣創建全局變量,所以全部的變量或函數都是類或結構的成員。類的成員能夠分爲兩大類:類自己所聲明的以及從基類中繼承來的。

1.8.1  類的成員類型

類的成員包括如下類型:

l 局部變量:在for、switch等語句中和類方法中定義的變量,只在指定範圍內有效。

l 字段:即類中的變量或常量,包括靜態字段、實例字段、常量和只讀字段。

l 方法成員:包括靜態方法和實例方法。

l 屬性:按屬性指定的get方法和Set方法對字段進行讀寫。屬性本質上是方法。

l 事件:表明事件自己,同時聯繫事件和事件處理函數。

l 索引指示器:容許象使用數組那樣訪問類中的數據成員。

l 操做符重載:採用重載操做符的方法定義類中特有的操做。

l 構造函數和析構函數。

包含有可執行代碼的成員被認爲是類中的函數成員,這些函數成員有方法、屬性、索引指示器、操做符重載、構造函數和析構函數。

1.8.2  類成員訪問修飾符

訪問修飾符用於指定類成員的可訪問性,C#訪問修飾符有private、protected、public和internal4種。Private聲明私有成員,私有數據成員只能被類內部的函數使用和修改,私有函數成員只能被類內部的函數調用。派生類雖然繼承了基類私有成員,但不能直接訪問它們,只能經過基類的公有成員訪問。protected聲明保護成員,保護數據成員只能被類內部和派生類的函數使用和修改,保護函數成員只能被類內部和派生類的函數調用。public聲明公有成員,類的公用函數成員能夠被類的外部程序所調用,類的公用數據成員能夠被類的外部程序直接使用。公有函數實際是一個類和外部通信的接口,外部函數經過調用公有函數,按照預先設定好的方法修改類的私有成員和保護成員。internal聲明內部成員,內部成員只能在同一程序集中的文件中才是能夠訪問的,通常是同一個應用(Application)或庫(Library)。

1.9      類的字段和屬性

通常把類或結構中定義的變量和常量叫字段。屬性不是字段,本質上是定義修改字段的方法,因爲屬性和字段的緊密關係,把它們放到一塊兒敘述。

1.9.1  靜態字段、實例字段、常量和只讀字段

用修飾符static聲明的字段爲靜態字段。無論包含該靜態字段的類生成多少個對象或根本無對象,該字段都只有一個實例,靜態字段不能被撤銷。必須採用以下方法引用靜態字段:類名.靜態字段名。若是類中定義的字段不使用修飾符static,該字段爲實例字段,每建立該類的一個對象,在對象內建立一個該字段實例,建立它的對象被撤銷,該字段對象也被撤銷,實例字段採用以下方法引用:實例名.實例字段名。用const修飾符聲明的字段爲常量,常量只能在聲明中初始化,之後不能再修改。用readonly修飾符聲明的字段爲只讀字段,只讀字段是特殊的實例字段,它只能在字段聲明中或構造函數中從新賦值,在其它任何地方都不能改變只讀字段的值。例子:

public class Test

{     public const int intMax=int.MaxValue;//常量,必須賦初值

public int x=0;//實例字段

public readonly int y=0;//只讀字段

public static int cnt=0;//靜態字段

public Test(int x1,int y1)//構造函數

{     //intMax=0;//錯誤,不能修改常量

       x=x1;//在構造函數容許修改實例字段

       y=y1;//在構造函數容許修改只讀字段

       cnt++;//每建立一個對象都調用構造函數,用此語句能夠記錄對象的個數

}

public void Modify(int x1,int y1)

{     //intMax=0;//錯誤,不能修改常量

    x=x1;

    cnt=y1;

    //y=10;//不容許修改只讀字段

}

}

class Class1

{   static void Main(string[] args)

{   Test T1=new Test(100,200);

    T1.x=40;//引用實例字段採用方法:實例名.實例字段名

      Test.cnt=0;//引用靜態字段採用方法:類名.靜態字段名

        int z=T1.y;//引用只讀字段

      z=Test.intMax;//引用常量

}

}

1.9.2  屬性

C#語言支持組件編程,組件也是類,組件用屬性、方法、事件描述。屬性不是字段,但必然和類中的某個或某些字段相聯繫,屬性定義了獲得和修改相聯繫的字段的方法。C#中的屬性更充分地體現了對象的封裝性:不直接操做類的數據內容,而是經過訪問器進行訪問,藉助於get和set方法對屬性的值進行讀寫。訪問屬性值的語法形式和訪問一個變量基本同樣,使訪問屬性就象訪問變量同樣方便,符合習慣。

在類的基本概念一節中,定義一個描述我的狀況的類Person,其中字段name和age是私有字段,記錄姓名和年齡,外部經過公有方法SetName和SetAge修改這兩個私有字段。如今用屬性來描述姓名和年齡。例子以下:

using System;

public class Person

{   private string P_name="張三";//P_name是私有字段

    private int P_age=12;//P_age是私有字段

    public void Display()//類的方法聲明,顯示姓名和年齡

    {   Console.WriteLine("姓名:{0},年齡:{1}",P_name,P_age);

    }

    public string Name//定義屬性Name

       {     get

              {     return  P_name;}

              set

              {     P_name=value;}

       }

    public int Age//定義屬性Age

       {     get

              {     return  P_age;}

              set

              {     P_age=value;}

       }

}

public class Test

{   public static void Main()

{   Person OnePerson= new Person();

        OnePerson.Name="田七";//value="田七",經過set方法修改變量P_Name

        string s=OnePerson.Name;//經過get方法獲得變量P_Name值

        OnePerson.Age=20;//經過定義屬性,既保證了姓名和年齡按指定方法修改

        int x=OnePerson.Age;//語法形式和修改、獲得一個變量基本一致,符合習慣

OnePerson.Display();

}

}

在屬性的訪問聲明中,只有set訪問器代表屬性的值只能進行設置而不能讀出,只有get訪問器代表屬性的值是隻讀的不能改寫,同時具備set訪問器和get訪問器代表屬性的值的讀寫都是容許的。

雖然屬性和字段的語法比較相似,但因爲屬性本質上是方法,所以不能把屬性當作變量那樣使用,也不能把屬性做爲引用型參數或輸出參數來進行傳遞。

1.10  類的方法

方法是類中用於執行計算或其它行爲的成員。全部方法都必須定義在類或結構中。

1.10.1      方法的聲明

方法的聲明格式以下:

屬性 方法修飾符 返回類型方法名(形參列表){方法體}

方法修飾符包括new、public、protected、internal、private、static、virtual、sealed、override、abstract和extern。這些修飾符有些已經介紹過,其它修飾符將逐一介紹。返回類型能夠是任何合法的C#數據類型,也能夠是void,即無返回值。形參列表的格式爲:(形參類型 形參1,形參類型 形參2,...),能夠有多個形參。不能使用C語言的形參格式。

1.10.2      方法參數的種類

C#語言的方法能夠使用以下四種參數(請注意和參數類型的區別):

l  值參數,不含任何修飾符。

l  引用參數,以ref修飾符聲明。

l  輸出參數,以out修飾符聲明。

l  數組參數,以params修飾符聲明。

1. 值參數

當用值參數向方法傳遞參數時,程序給實參的值作一份拷貝,而且將此拷貝傳遞給該方法,被調用的方法不會修改實參的值,因此使用值參數時,能夠保證明參的值是安全的。若是參數類型是引用類型,例如是類的引用變量,則拷貝中存儲的也是對象的引用,因此拷貝和實參引用同一個對象,經過這個拷貝,能夠修改實參所引用的對象中的數據成員。

2. 引用參數

有時在方法中,須要修改或獲得方法外部的變量值,C語言用向方法傳遞實參指針來達到目的,C#語言用引用參數。當用引用參數向方法傳遞實參時,程序將把實參的引用,即實參在內存中的地址傳遞給方法,方法經過實參的引用,修改或獲得方法外部的變量值。引用參數以ref修飾符聲明。注意在使用前,實參變量要求必須被設置初始值。

3. 輸出參數

爲了把方法的運算結果保存到外部變量,所以須要知道外部變量的引用(地址)。輸出參數用於向方法傳遞外部變量引用(地址),因此輸出參數也是引用參數,與引用參數的差異在於調用方法前無需對變量進行初始化。在方法返回後,傳遞的變量被認爲通過了初始化。值參數、引用參數和輸出參數的使用見下例:

using System;

class g{public int a=0;}//類定義

class Class1

{   public static void F1(ref char i)//引用參數

    {   i='b';}

    public static void F2(char i)//值參數,參數類型爲值類型

    {   i='d';}

    public static void F3(out char i)//輸出參數

    {   i='e';}

public static void F4(string s)//值參數,參數類型爲字符串

    {   s="xyz";}

    public static void F5(g gg)//值參數,參數類型爲引用類型

    {   gg.a=20;}

public static void F6(ref string s)//引用參數,參數類型爲字符串

    {   s="xyz";}

    static void Main(string[] args)

    {   char a='c';

        string s1="abc";

        F2(a);//值參數,不能修改外部的a

        Console.WriteLine(a);//因a未被修改,顯示c

        F1(ref a);//引用參數,函數修改外部的a的值

        Console.WriteLine(a);//a被修改成b,顯示b

        Char j;

        F3(out j);//輸出參數,結果輸出到外部變量j

        Console.WriteLine(j);//顯示e

        F4(s1);//值參數,參數類型是字符串,s1爲字符串引用變量

        Console.WriteLine(s1);//顯示:abc,字符串s1不被修改

        g g1=new g();

        F5(g1);//值參數,但實參是一個類引用類型變量

        Console.WriteLine(g1.a.ToString());//顯示:20,修改對象數據

        F6(ref s1);//引用參數,參數類型是字符串,s1爲字符串引用變量

        Console.WriteLine(s1);//顯示:xyz,字符串s1被修改

    }

}

4. 數組參數

數組參數使用params說明,若是形參表中包含了數組參數,那麼它必須是參數表中最後一個參數,數組參數只容許是一維數組。好比string[]和string[][]類型均可以做爲數組型參數。最後,數組型參數不能再有ref和out修飾符。見下例:

using System;

class Class1

{   static void F(params int[] args)//數組參數,有params說明

    {   Console.Write("Array contains {0} elements:",args.Length);

        foreach (int i in args)

Console.Write(" {0}",i);

        Console.WriteLine();

    }

    static void Main(string[] args)

    {   int[] a = {1,2,3};

        F(a);//實參爲數組類引用變量a

        F(10, 20, 30, 40);//等價於F(new int[] {60,70,80,90});

        F(new int[] {60,70,80,90});//實參爲數組類引用

        F();//等價於F(new int[] {});

        F(new int[] {});//實參爲數組類引用,數組無元素

    }

}

程序輸出

Array contains 3 elements: 1 2 3

Array contains 4 elements: 10 20 30 40

Array contains 4 elements: 60,70,80,90

Array contains 0 elements:

Array contains 0 elements:

    方法的參數爲數組時也能夠不使用params,此種方法能夠使用一維或多維數組,見下例:

using System;

class Class1

{   static void F(int[,] args)//值參數,參數類型爲數組類引用變量,無params說明

    {   Console.Write("Array contains {0} elements:",args.Length);

        foreach (int i in args)

Console.Write(" {0}",i);

        Console.WriteLine();

    }

    static void Main(string[] args)

    {   int[,] a = {{1,2,3},{4,5,6}};

        F(a);//實參爲數組類引用變量a

        //F(10, 20, 30, 40);//此格式不能使用

        F(new int[,] {{60,70},{80,90}});//實參爲數組類引用

        //F();//此格式不能使用

        //F(new int[,] {});//此格式不能使用

    }

}

程序輸出

Array contains 3 elements: 1 2 3 4 5 6

Array contains 4 elements: 60,70,80,90

1.10.3      靜態方法和實例方法

用修飾符static聲明的方法爲靜態方法,不用修飾符static聲明的方法爲實例方法。無論類生成或未生成對象,類的靜態方法均可以被使用,使用格式爲:類名.靜態方法名。靜態方法只能使用該靜態方法所在類的靜態數據成員和靜態方法。這是由於使用靜態方法時,該靜態方法所在類可能尚未對象,即便有對象,因爲用類名.靜態方法名方式調用靜態方法,靜態方法沒有this指針來存放對象的地址,沒法斷定應訪問哪一個對象的數據成員。在類建立對象後,實例方法才能被使用,使用格式爲:對象名.實例方法名。實例方法能夠使用該方法所在類的全部靜態成員和實例成員。例子以下:

using System;

public class UseMethod

{   private static int x=0;//靜態字段

private int y=1;//實例字段

public static void StaticMethod()//靜態方法

{   x=10;//正確,靜態方法訪問靜態數據成員

//y=20;//錯誤,靜態方法不能訪問實例數據成員

}

public void NoStaticMethod()//實例方法

{   x=10;//正確,實例方法訪問靜態數據成員

y=20;//正確,實例方法訪問實例數據成員

}

}

public class Class1

{   public static void Main()

{   UseMethod m=new UseMethod();

        UseMethod.StaticMethod();//使用靜態方法格式爲:類名.靜態方法名

        m.NoStaticMethod();//使用實例方法格式爲:對象名.實例方法名

}

}

1.10.4      方法的重載

在C#語言中,若是在同一個類中定義的函數名相同,而參數類型或參數個數不一樣,認爲是不相同的函數,僅返回值不一樣,不能看做不一樣函數,這叫作函數的重載。前邊Person類中定義了多個構造函數就是重載的例子。在C語言中,若計算一個數據的絕對值,則須要對不一樣數據類型求絕對值方法使用不一樣的方法名,如用abc()求整型數絕對值,labs()求長整型數絕對值,fabs()求浮點數絕對值。而在C#語言中,能夠使用函數重載特性,對這三個函數定義一樣的函數名,但使用不一樣的參數類型。下面是實現方法:

using System;

public class UseAbs

{   public int  abs(int x)//整型數求絕對值

    {   return(x<0 ? -x:x);}

    public long abs(long x)//長整型數求絕對值

    {return(x<0 ? -x:x);}

    public double  abs(double  x)//浮點數求絕對值

    {return(x<0 ? -x:x);}

}

class Class1

{   static void Main(string[] args)

    {   UseAbs m=new UseAbs();

        int x=-10;

        long y=-123;

        double z=-23.98d;

        x=m.abs(x);

        y=m.abs(y);

        z=m.abs(z);

        Console.WriteLine("x={0},y={1},z={2}",x,y,z);

}

}

類的對象調用這些同名方法,在編譯時,根據調用方法的實參類型決定調用那個同名方法,計算不一樣類型數據的絕對值。這給編程提供了極大方便。

1.10.5      操做符重載

操做符重載是將C#語言中的已有操做符賦予新的功能,但與該操做符的原本含義不衝突,使用時只需根據操做符出現的位置來判別其具體執行哪種運算。操做符重載,實際是定義了一個操做符函數,操做符函數聲明的格式以下:

static public 函數返回類型 operator 從新定義的操做符(形參表)

C#語言中有一些操做符是能夠重載的,例如:+ - ! ~ ++ -- true false * / % & | ^ << >> == != > < >= <=等等。但也有一些操做符是不容許進行重載的,例如:=, &&, ||, ?:, new, typeof, sizeof, is等。

下邊的例子,定義一個複數類,而且但願複數的加減乘除用符號+,-.*,/來表示。

using System;

class Complex//複數類定義

{   private double Real;//複數實部

    private double Imag;//複數虛部

    public Complex(double x,double y)//構造函數

    {   Real=x;

        Imag=y;

    }

    static public Complex operator - (Complex a)//重載一元操做符負號,注意1個參數

    {   return (new Complex(-a.Real,-a.Imag));}

    static public Complex operator +(Complex a,Complex b)//重載二元操做符加號

    {   return (new Complex(a.Real+b.Real,a.Imag+b.Imag));}

    public void Display()

    {   Console.WriteLine("{0}+({1})j",Real,Imag);}

}

class Class1

{   static void Main(string[] args)

    {   Complex x=new Complex(1.0,2.0);

        Complex y=new Complex(3.0,4.0);

        Complex z=new Complex(5.0,7.0);

        x.Display();//顯示:1+(2)j

        y.Display();//顯示:3+(4)j

        z.Display();//顯示:5+(7)j

        z=-x;//等價於z=opeator-(x)

        z.Display();//顯示:-1+(-2)j

        z=x+y;//即z=opeator+(x,y)

        z.Display();//顯示:4+(6)j

    }

}

1.10.6      this關鍵字

每一個類均可以有多個對象,例如定義Person類的兩個對象:

Person P1=new Person("李四",30);

Person P2=new Person("張三",40);

所以P1.Display()應顯示李四信息,P2.Display()應顯示張三信息,但不管建立多少個對象,只有一個方法Display(),該方法是如何知道顯示那個對象的信息的呢?C#語言用引用變量this記錄調用方法Display()的對象,當某個對象調用方法Display()時,this便引用該對象(記錄該對象的地址)。所以,不一樣的對象調用同一方法時,方法便根據this所引用的不一樣對象來肯定應該引用哪個對象的數據成員。this是類中隱含的引用變量,它是被自動被賦值的,能夠使用但不能被修改。例如:P1.Display(),this引用對象P1,顯示李四信息。P2.Display(),this引用對象P2,顯示張三信息。

1.11  類的多態性

在面向對象的系統中,多態性是一個很是重要的概念。C#支持兩種類型的多態性,第一種是編譯時的多態性,一個類的對象調用若干同名方法,系統在編譯時,根據調用方法的實參類型及實參的個數決定調用那個同名方法,實現何種操做。編譯時的多態性是經過方法重載來實現的。C#語言的方法重載以及操做符重載和C++語言的基本一致。

第二種是運行時的多態性,是在系統運行時,不一樣對象調用一個名字相同,參數的類型及個數徹底同樣的方法,會完成不一樣的操做。C#運行時的多態性經過虛方法實現。在類的方法聲明前加上了virtual修飾符,被稱之爲虛方法,反之爲非虛方法。C#語言的虛方法和C++語言的基本一致。下面的例子說明了虛方法與非虛方法的區別:

using System;

class A

{   public void F()//非虛方法

{   Console.Write("  A.F");}

public virtual void G()//虛方法

{ Console.Write("  A.G");}

}

class B:A//A類爲B類的基類

{   new public void F()//覆蓋基類的同名非虛方法F(),注意使用new

{   Console.Write("  B.F");}

public override void G()//覆蓋基類的同名虛方法G(),注意使用override

{   Console.Write("  B.G");}

}

class Test

{   static void F2(A aA)//注意,參數爲A類引用變量

{   aA.G();}

static void Main()

{   B b=new B();

A a1=new A();

A a2=b;//容許基類引用變量引用派生類對象,a2引用派生類B對象b

a1.F();//調用基類A的非虛方法F(),顯示A.F

a2.F();//F()爲非虛方法,調用基類A的F(),顯示A.F

b.F();//F()爲非虛方法,調用派生類B的F(),顯示B.F

a1.G();//G()爲虛方法,因a1引用基類A對象,調用基類A的G(),顯示A.G

a2.G();//G()爲虛方法,因a2引用派生類B對象,調用派生類B的G(),顯示B.G

F2(b);//實參爲派生類B對象,因爲A aA=b,調用派生類B的函數G(),顯示B.G

F2(a1);//實參爲基類A對象,調用A類的函數G(),顯示A.G

}

}

那麼輸出應該是:

A.F  A.F  B.F  A.G  B.G  B.G  A.G

注意例子中,不一樣對象調用同名非虛方法F()和同名虛方法G()的區別。a2雖然是基類引用變量,但它引用派生類對象b。因爲G()是虛方法,所以a2.G()調用派生類B的G(),顯示G.F。但因爲F()是非虛方法,a2.F()仍然調用基類A的F(),顯示A.F。或者說,若是將基類引用變量引用不一樣對象,或者是基類對象,或者是派生類對象,用這個基類引用變量分別調用同名虛方法,根據對象不一樣,會完成不一樣的操做。而非虛方法則不具有此功能。

方法F2(A aA)中,參數是A類類型,F2(b)中形參和實參的關係是:A aA=b,即基類引用變量aA引用派生類對象b,aA.G()調用派生類B的函數G(),顯示B.G。同理,F2(a1)實參爲基類A對象,調用A類的函數G(),顯示A.G。

在類的基本概念一節中,定義一個描述我的狀況的類Person,其中公有方法Display()用來顯示我的信息。在派生僱員類Employee中,覆蓋了基類的公有方法Display(),以顯示僱員新增長的信息。咱們但願隱藏這些細節,但願不管基類仍是派生類,都調用同一個顯示方法,根據對象不一樣,自動顯示不一樣的信息。能夠用虛方法來實現,這是一個典型的多態性例子。例子

using System;

public class Person

{   private String name="張三";//類的數據成員聲明

    private int age=12;

    protected virtual void Display()//類的虛方法

{   Console.WriteLine("姓名:{0},年齡:{1}",name,age);

    }

    public Person(string Name,int Age)//構造函數,函數名和類同名,無返回值

    {   name=Name;

        age=Age;

    }

static public void DisplayData(Person aPerson)//靜態方法

{   aPerson.Display();//不是靜態方法調用實例方法,如寫爲Display()錯誤

}

}

public class Employee:Person//Person類是基類

{   private string department;

private decimal salary;

public Employee(string Name,int Age,string D,decimal S):base(Name,Age)

{   department=D;

salary=S;

}

protected override void Display()//重載虛方法,注意用override

{   base.Display();//訪問基類同名方法

    Console.WriteLine("部門:{0}  薪金:{1} ", department,salary);

}

}

class Class1

{   static void Main(string[] args)

    {   Person OnePerson=new Person("李四",30);

        Person.DisplayData(OnePerson);//顯示基類數據

        Employee OneEmployee=new Employee("王五",40,"財務部",2000);

        Person.DisplayData(OneEmployee); //顯示派生類數據

    }

}

運行後,顯示的效果是:

姓名: 李四,年齡:30

姓名: 王五,年齡:40

部門:財務部  薪金:2000

1.12  抽象類和抽象方法

抽象類表示一種抽象的概念,只是但願以它爲基類的派生類有共同的函數成員和數據成員。抽象類使用abstract修飾符,對抽象類的使用有如下幾點規定:

l  抽象類只能做爲其它類的基類,它不能直接被實例化。

l  抽象類容許包含抽象成員,雖然這不是必須的。抽象成員用abstract修飾符修飾。

l  抽象類不能同時又是密封的。

l  抽象類的基類也能夠是抽象類。若是一個非抽象類的基類是抽象類,則該類必須經過覆蓋來實現全部繼承而來的抽象方法,包括其抽象基類中的抽象方法,若是該抽象基類從其它抽象類派生,還應包括其它抽象類中的全部抽象方法。

請看下面的示例:

abstract class Figure//抽象類定義

{   protected double x=0,y=0;

    public Figure(double a,double b)

    {   x=a;

        y=b;

    }

public abstract void Area();//抽象方法,無實現代碼

}

class Square:Figure///類Square定義

{   public Square(double a,double b):base(a,b)

    {}

public override void Area()//不能使用new,必須用override

{   Console.WriteLine("矩形面積是:{0}",x*y);}

}

class Circle:Figure///類Square定義

{   public Circle(double a):base(a,a)

    {}

public override void Area()

{   Console.WriteLine("園面積是:{0}",3.14*x*y);}

}

class Class1

{   static void Main(string[] args)

    {   Square s=new Square(20,30);

        Circle c=new Circle(10);

s.Area();

        c.Area();

    }

}

程序輸出結果爲:

矩形面積是:600

園面積是:314

抽象類Figure提供了一個抽象方法Area(),並無實現它,類Square和Circle從抽象類Figure中繼承方法Area(),分別具體實現計算矩形和園的面積。

在類的基本概念一節中,定義一個描述我的狀況的類Person,它只是描述了一我的最通常的屬性和行爲,所以不但願生成它的對象,能夠定義它爲抽象類。

注意:C++程序員在這裏最容易犯錯誤。C++中沒有對抽象類進行直接聲明的方法,而認爲只要在類中定義了純虛函數,這個類就是一個抽象類。純虛函數的概念比較晦澀,直觀上不容易爲人們接受和掌握,所以C#拋棄了這一律念。

1.13  密封類和密封方法

有時候,咱們並不但願本身編寫的類被繼承。或者有的類已經沒有再被繼承的必要。C#提出了一個密封類(sealed class)的概念,幫助開發人員來解決這一問題。

密封類在聲明中使用sealed修飾符,這樣就能夠防止該類被其它類繼承。若是試圖將一個密封類做爲其它類的基類,C#編譯器將提示出錯。理所固然,密封類不能同時又是抽象類,由於抽象老是但願被繼承的。

C#還提出了密封方法(sealed method)的概念。方法使用sealed修飾符,稱該方法是一個密封方法。在派生類中,不能覆蓋基類中的密封方法。

1.14  接口

與類同樣,在接口中能夠定義一個和多個方法、屬性、索引指示器和事件。但與類不一樣的是,接口中僅僅是它們的聲明,並不提供實現。所以接口是函數成員聲明的集合。若是類或結構從一個接口派生,則這個類或結構負責實現該接口中所聲明的全部成員。一個接口能夠從多個接口繼承,而一個類或結構能夠實現多個接口。因爲C#語言不支持多繼承,所以,若是某個類須要繼承多個類的行爲時,只能使用多個接口加以說明。

1.14.1      接口聲明

接口聲明是一種類型聲明,它定義了一種新的接口類型。接口聲明格式以下:

屬性  接口修飾符  interface  接口名:基接口{接口體}

其中,關鍵字interface、接口名和接口體時必須的,其它項是可選的。接口修飾符能夠是new、public、protected、internal和private。例子:

public interface IExample

{//全部接口成員都不能包括實現

string this[int index] {get;set;}//索引指示器聲明

event EventHandler E;//事件聲明

void F(int value);//方法聲明

string P { get; set;}//屬性聲明

}

聲明接口時,需注意如下內容:

l  接口成員只能是方法、屬性、索引指示器和事件,不能是常量、域、操做符、構造函數或析構函數,不能包含任何靜態成員。

l  接口成員聲明不能包含任何修飾符,接口成員默認訪問方式是public。

1.14.2      接口的繼承

相似於類的繼承性,接口也有繼承性。派生接口繼承了基接口中的函數成員說明。接口容許多繼承,一個派生接口能夠沒有基接口,也能夠有多個基接口。在接口聲明的冒號後列出被繼承的接口名字,多個接口名之間用分號分割。例子以下:

using System;

interface IControl

{   void Paint();

}

interface ITextBox:IControl//繼承了接口Icontrol的方法Paint()

{   void SetText(string text);

}

interface IListBox:IControl//繼承了接口Icontrol的方法Paint()

{   void SetItems(string[] items);

}

interface IComboBox:ITextBox,IListBox

{//能夠聲明新方法

}

上面的例子中,接口ITextBox和IListBox都從接口IControl中繼承,也就繼承了接口IControl的Paint方法。接口IComboBox從接口ITextBox和IListBox中繼承,所以它應該繼承了接口ITextBox的SetText方法和IListBox的SetItems方法,還有IControl的Paint方法。

1.14.3      類對接口的實現

前面已經說過,接口定義不包括函數成員的實現部分。繼承該接口的類或結構應實現這些函數成員。這裏主要講述經過類來實現接口。類實現接口的本質是,用接口規定類應實現那些函數成員。用類來實現接口時,接口的名稱必須包含在類聲明中的基類列表中。

在類的基本概念一節中,定義一個描述我的狀況的類Person,從類Person能夠派生出其它類,例如:工人類、公務員類、醫生類等。這些類有一些共有的方法和屬性,例如工資屬性。通常但願全部派生類訪問工資屬性時用一樣變量名。該屬性定義在類Person中不合適,由於有些人無工資,如小孩。如定義一個類做爲基類,包含工資屬性,但C#不支持多繼承。可行的辦法是使用接口,在接口中聲明工資屬性。工人類、公務員類、醫生類等都必須實現該接口,也就保證了它們訪問工資屬性時用一樣變量名。例子以下:

using System;

public interface I_Salary//接口

{   decimal Salary//屬性聲明

    {   get;

        set;

    }

}

public class Person

{…//見1.9.2屬性節Person類定義,這裏不重複了。

}

public class Employee:Person,I_Salary//Person類是基類,I_Salary是接口

{//不一樣程序員完成工人類、醫生類等,定義工資變量名稱可能不一樣

    private decimal salary;

public new void Display()

{   base.Display();

    Console.WriteLine("薪金:{0} ",salary);

}

//工人類、醫生類等都要實現屬性Salary,保證使用的工資屬性同名

public decimal Salary

       {     get

              {     return  salary;}

              set

              {     salary=value;}

       }

}

public class Test

{   public static void Main()

{ Employee S=new Employee();

S.Name="田七";//修改屬性Name

S.Age=20;//修改屬性Age

S.Salary=2000;//修改屬性Salary

S.Display();

}

}

若是類實現了某個接口,類也隱式地繼承了該接口的全部基接口,無論這些基接口有沒有在類聲明的基類表中列出。所以,若是類從一個接口派生,則這個類負責實現該接口及該接口的全部基接口中所聲明的全部成員。

1.15  表明

在這裏要介紹的是C#的一個引用類型----表明(delegate),也翻譯爲委託。它實際上至關於C語言的函數指針。與指針不一樣的是C#中的表明是類型安全的。表明類聲明格式以下:

屬性集 修飾符 delegate 函數返回類型 定義的表明標識符(函數形參列表);

修飾符包括new、public、protected、internal和private。例如咱們能夠聲明一個返回類型爲int,無參數的函數的表明MyDelegate:

public delegate int MyDelegate();//只能表明返回類型爲int,無參數的函數

聲明瞭表明類MyDelegate,能夠建立表明類MyDelegate的對象,用這個對象去表明一個靜態方法或非靜態的方法,所表明的方法必須爲int類型,無參數。看下面的例子:

using System;

delegate int MyDelegate();//聲明一個表明,注意聲明的位置

public class MyClass

{   public int InstanceMethod()//非靜態的方法,注意方法爲int類型,無參數

{   Console.WriteLine("調用了非靜態的方法。");

return 0;

}

static public int StaticMethod()//靜態方法,注意方法爲int類型,無參數

{   Console.WriteLine("調用了靜態的方法。");

return 0;

}

}

public class Test

{   static public void Main ()

{   MyClass p = new MyClass();

//用new創建表明類MyDelegate對象,d中存儲非靜態的方法InstanceMethod的地址

MyDelegate d=new MyDelegate(p.InstanceMethod);//參數是被表明的方法

d();//調用非靜態方法

//用new創建表明類MyDelegate對象,d中存儲靜態的方法StaticMethod的地址

d=new MyDelegate(MyClass.StaticMethod);//參數是被表明的方法

d();//調用靜態方法

}

}

程序的輸出結果是:

調用了非靜態的方法。

調用了靜態的方法。

1.16  事件

事件是C#語言內置的語法,能夠定義和處理事件,爲使用組件編程提供了良好的基礎。

1.16.1      事件驅動

Windows操做系統把用戶的動做都看做消息,C#中稱做事件,例如用鼠標左鍵單擊按鈕,發出鼠標單擊按鈕事件。Windows操做系統負責統一管理全部的事件,把事件發送到各個運行程序。各個程序用事件函數響應事件,這種方法也叫事件驅動。

C#語言使用組件編制Windows應用程序。組件本質上是類。在組件類中,預先定義了該組件可以響應的事件,以及對應的事件函數,該事件發生,將自動調用本身的事件函數。例如,按鈕類中定義了單擊事件Click和單擊事件函數。一個組件中定義了多個事件,應用程序中沒必要也不必響應全部的事件,而只需響應其中不多事件,程序員編制相應的事件處理函數,用來完成須要響應的事件所應完成的功能。如今的問題是,第一,如何把程序員編制的事件處理函數和組件類中預先定義的事件函數聯繫起來。第二,如何使不需響應的事件無動做。這是本節要節的解決問題。

1.16.2      事件的聲明

在C#中,事件首先表明事件自己,例如按鈕類的單擊事件,同時,事件仍是表明類引用變量,能夠表明程序員編制的事件處理函數,把事件和事件處理函數聯繫在一塊兒。下面的例子定義了一個Button組件,這個例子不完整,只是說明問題。實際在C#語言類庫中已預約義了Button組件,這裏的代碼只是想說明Button組件中是如何定義事件的。例子以下:

public delegate void EventHandler(object sender,EventArgs e);//表明聲明

//EventHandler能夠表明沒有返回值,參數爲(object sender,EventArgs e)的函數

public class Button:Control//定義一個按鈕類Button組件

{…//按鈕類Button其它成員定義

public event EventHandler Click;//聲明一個事件Click,是表明類引用變量

protected void OnClick(EventArgs e)//Click事件發生,自動觸發OnClick方法

{   if(Click!=null)//若是Click已表明了事件處理函數,執行這個函數

Click(this,e);

}

public void Reset()

{   Click=null;}

}

在這個例子中,Click事件發生,應有代碼保證(未列出)自動觸發OnClick方法。Click是類Button的一個事件,同時也是表明EventHandler類的引用變量,如令Click表明事件處理函數,該函數完成Click事件應完成的功能,Click事件發生時,執行事件處理函數。

1.16.3      事件的預訂和撤消

在隨後的例子中,咱們聲明瞭一個使用Button類的登陸對話框類,對話框類含有兩個按鈕:OK和Cancel按鈕。

public class LoginDialog: Form//登陸對話框類聲明

{   Button OkButton;

Button CancelButton;

public LoginDialog()//構造函數

{   OkButton=new Button();//創建按鈕對象OkButton

//Click表明OkButtonClick方法,注意+=的使用

OkButton.Click+=new EventHandler(OkButtonClick);

CancelButton=new Button();//創建按鈕對象OkButton

CancelButton.Click += new EventHandler(CancelButtonClick);

}

void OkButtonClick(object sender, EventArgs e)

{…//處理OkButton.Click事件的方法

}

void CancelButtonClick(object sender, EventArgs e)

{…//處理CancelButton.Click事件的方法

}

}

在例子中創建了Button類的兩個實例,單擊按鈕事件Click經過以下語句和事件處理方法聯繫在一塊兒:OkButton.Click+=new EventHandler(OkButtonClick),該語句的意義是使OkButton.Click表明事件處理方法OkButtonClick,這樣只要Click事件被觸發,事件處理方法OkButtonClick就會被自動調用。撤消事件和事件處理方法OkButtonClick的聯繫採用以下語句實現:OkButton.Click-=new EventHandler(OkButtonClick),這時,OkButton.Click就再也不表明事件處理方法,Click事件被觸發,方法OkButtonClick就不會被調用了。務必理解這兩條語句的用法。使用Visual Studio.Net集成環境能夠自動創建這種聯繫,在自動生成的代碼中包括這兩條語句。

1.17  索引指示器

在C#語言中,數組也是類,好比咱們聲明一個整型數數組:int[] arr=new int[5],實際上生成了一個數組類對象,arr是這個對象的引用(地址),訪問這個數組元素的方法是:arr[下標],在數組類中,使用索引訪問元素是如何實現的呢?是否能夠定義本身的類,用索引訪問類中的數據成員?索引指示器(indexer)爲咱們提供了經過索引方式方便地訪問類的數據成員的方法。

首先看下面的例子,用於打印出小組人員的名單:

using System

class Team

{   string[] s_name = new string[2];//定義字符串數組,記錄小組人員姓名

public string this[int nIndex]//索引指示器聲明,this爲類Team類的對象

{   get//用對象名[索引]獲得記錄小組人員姓名時,調用get函數

{   return s_name[nIndex];

}

set//用對象名[索引]修改記錄小組人員姓名時,調用set函數

{   s_name[nIndex] =value;//value爲被修改值

}

}

}

class Test

{   public static void Main()

{   Team t1 = new Team();

t1[0]="張三";

t1[1]="李斯";

Console.WriteLine("{0},{1}",t1[0], t1[1]);

}

}

顯示結果以下:張三,李斯

1.18  名字空間

一個應用程序可能包含許多不一樣的部分,除了本身編制的程序以外,還要使用操做系統或開發環境提供的函數庫、類庫或組件庫,軟件開發商處購買的函數庫、類庫或組件庫,開發團隊中其它人編制的程序,等等。爲了組織這些程序代碼,使應用程序能夠方便地使用這些程序代碼,C#語言提出了名字空間的概念。名字空間是函數、類或組件的容器,把它們按類別放入不一樣的名字空間中,名字空間提供了一個邏輯上的層次結構體系,使應用程序能方便的找到所需代碼。這和C語言中的include語句的功能有些類似,但實現方法徹底不一樣。

1.18.1      名字空間的聲明

用關鍵字namespace聲明一個名字空間,名字空間的聲明要麼是源文件using語句後的第一條語句,要麼做爲成員出如今其它名字空間的聲明之中,也就是說,在一個名字空間內部還能夠定義名字空間成員。全局名字空間應是源文件using語句後的第一條語句。在同一名字空間中,不容許出現同名名字空間成員或同名的類。在聲明時不容許使用任何訪問修飾符,名字空間隱式地使用public修飾符。例子以下:

using System;

namespace N1//N1爲全局名字空間的名稱,應是using語句後的第一條語句

{   namespace N2//名字空間N1的成員N2

{   class A//在N2名字空間定義的類不該重名

{   void f1(){};}

class B

{   void f2(){};}

}

}

也能夠採用非嵌套的語法來實現以上名字空間:

namespace N1.N2//類A、B在名字空間N1.N2中

{   class A

{   void f1(){};}

class B

{   void f2(){};}

}

也能夠採用以下格式:

namespace N1.N2//類A在名字空間N1.N2中

{   class A

{   void f1(){};}

}

namespace N1.N2//類B在名字空間N1.N2中

{   class B

{   void f2(){};}

}

1.18.2      名字空間使用

如在程序中,需引用其它名字空間的類或函數等,能夠使用語句using,例如需使用上節定義的方法f1()和f2(),能夠採用以下代碼:

using N1.N2;

class WelcomeApp

{   A a=new A();

a.f1();

}

using N1.N2其實是告訴應用程序到哪裏能夠找到類A。請讀者從新看一下1.2.1節中的例子。

1.19  非安全代碼

在C和C++的程序員看來,指針是最強有力的工具之一,同時又帶來許多問題。由於指針指向的數據類型可能並不相同,好比你能夠把int類型的指針指向一個float類型的變量,而這時程序並不會出錯。若是你刪除了一個不該該被刪除的指針,好比Windows中指向主程序的指針,程序就有可能崩潰。所以濫用指針給程序帶來不安全因素。正由於如此,在C#語言中取消了指針這個概念。雖然不使用指針能夠完成絕大部分任務,但有時在程序中還不可避免的使用指針,例如調用Windows操做系統的API函數,其參數多是指針,因此在C#中還容許使用指針,但必須聲明這段程序是非安全(unsafe)的。能夠指定一個方法是非安全的,例如:unsafe void F1(int * p){…}。能夠指定一條語句是非安全的,例如:unsafe int* p2=p1;還能夠指定一段代碼是非安全的,例如:unsafe{ int* p2=p1;int* p3=p4;}。在編譯時要採用以下格式:csc 要編譯的C#源程序 /unsafe。

習題

  1. 從鍵盤輸入姓名,在顯示器中顯示對輸入姓名的問候。(提示:string爲字符串類型,用語句string s=Console.ReadLine()輸入姓名)
  2. 構造函數和析購函數的主要做用是什麼?它們各有什麼特性?
  3. 定義點類,數據成員爲私有成員,增長有參數和無參數構造函數,在主函數中生成點類對象,並用字符顯示點類對象的座標。
  4. 定義矩形類,數據成員爲私有成員,增長有參數和無參數構造函數,在主函數中生成矩形類對象,並用字符顯示矩形類對象的長、寬和矩形左上角的座標。
  5. 設計一個計數器類,統計鍵入回車的次數,數據成員爲私有成員,在主程序中使用此類統計鍵入回車的次數。
  6. 說明值類型和引用類型的區別,並和C語言相應類型比較。
  7. 定義點結構,在主函數中生成點結構變量,從鍵盤輸入點的位置,並從新顯示座標。
  8. 定義整型一維數組,從鍵盤輸入數組元素數值後,用循環語句顯示全部元素的值。
  9. 輸入字符串,將字符串第一個字母和每一個空格後的字母變爲大寫,其他字母爲小寫後輸出。
  10. 輸入5個數,在每兩個數之間增長3個空格後輸出。
  11. 編一個猜數程序,程序設定一個1位十進制數,容許用戶猜3次,錯了告訴比設定數大仍是小,用switch語句實現。
  12. C#語言for語句能夠這樣使用:for(int i;i<10;i++),請問,i的有效使用範圍。
  13. 用字符*在CRT上顯示一個矩形。
  14. 輸入一個字符串,用foreach語句計算輸入的字符串長度,並顯示長度。
  15. 輸入兩個數相加,並顯示和。用異常語句處理輸入錯誤。
  16. 將1.6.3節中try–catch-finally語句例子改成try-finally和try–catch語句。
  17. 定義點類,從點類派生矩形類,數據成員爲私有成員,增長有參數和無參數構造函數,在主函數中生成矩形類對象,並用字符顯示矩形類對象的長、寬和矩形左上角的座標。
  18. 重作12題,將數據成員用屬性表示。
  19. 定義一個類,將類外部的char數組元素都變爲大寫。主程序輸入一個字符串,將其變爲char數組,變爲大寫後輸出每個char數組元素。分別用類對象和靜態函數實現。
  20. 定義分數類,實現用符號+,-,*,/完成分數的加減乘除。在主函數中輸入兩個數,完成運算後輸出運算結果。
  21. 創建一個sroot()函數,返回其參數的二次根。重載它,讓它可以分別返回整數、長整數和雙精度參數的二次根。
  22. 從新設計complex類,完成複數的+、-、*、/四則運算。
  23. 定義點類,從點類派生矩形類和園類,主程序實現用同一個方法顯示矩形和園的面積。
  24. 重作19題,將點類定義爲抽象類。
  25. 重作19題,改成接口實現,即將點類改成接口。

 

 

第二章       Windows編程的基礎知識

2.1      窗口

Windows應用程序通常都有一個窗口,窗口是運行程序與外界交換信息的界面。一個典型的窗口包括標題欄,最小化按鈕,最大/還原按鈕,關閉按鈕,系統菜單圖標,菜單,工具條,狀態欄,滾動條,客戶區等。程序員的工做之一是設計符合本身要求的窗口,C#用控件的方法設計界面。編程另外一個工做是在用戶區顯示數據和圖形。

2.2      Windows的消息系統

2.2.1  消息驅動(事件驅動)

Windows應用程序和dos程序(控制檯程序)的最大區別是事件驅動,也叫消息驅動。dos程序運行時如要讀鍵盤,則要獨佔鍵盤等待用戶輸入,如用戶不輸入,則CPU一直執行鍵盤輸入程序,等待用戶輸入,即dos程序獨佔外設和CPU。

Windows操做系統是一個多任務的操做系統,容許同時運行多個程序,它不容許任何一個程序獨佔外設,如鍵盤,鼠標等,全部運行程序共享外設和CPU,各個運行程序都要隨時從外設接受命令,執行命令。

所以必須由Windows操做系通通一管理各類外設。Windows把用戶對外設的動做都看做事件(消息),如單擊鼠標左鍵,發送單擊鼠標左鍵事件,用戶按下鍵盤,發送鍵盤被按下的事件等。Windows操做系通通一負責管理全部的事件,把事件發送到各個運行程序,而各個運行程序用一個函數響應事件,這個函數叫事件響應函數。這種方法叫事件驅動。每一個事件都有它本身的事件響應函數,當接到Windows事件後,自動執行此事件的事件響應函數。程序員編程的主要工做就是編制這些事件的處理函數,完成相應的工做。

2.2.2  事件隊列

Windows把用戶的動做都看做事件,Windows操做系統負責管理全部的事件,事件發生後,這些事件被放到系統事件隊列中,Windows操做系統從系統事件隊列中逐一取出事件,分析各個事件,分送事件到相應運行程序的事件隊列中。而每一個運行程序,則利用消息循環方法(既循環取得本身事件隊列中的事件)獲得事件,並把他們送到當前活動窗口,由窗口中的事件函數響應各個事件(消息)。所以,每一個運行程序都有本身的事件隊列。

2.2.3  注視窗口

Windows操做系統容許多個程序同時運行,每一個程序可能擁有多個窗口,但其中只有一個窗口是活動的,咱們能從窗口的標題欄的顏色來識別一個活動窗口,這個窗口接收Windows系統發來的大部分的事件。這個應用程序的窗口被稱爲注視(活動)窗口。

2.3      Windows編程接口和類庫

操做系統爲了方便應用程序設計,通常都要提供一個程序庫,一些設計應用程序的共用代碼都包含在這個程序庫中。程序員能夠調用這些代碼,以簡化編程。這節介紹一些經常使用程序庫。

2.3.1  Windows編程接口(API)

API(Application Programming Interface)是Windows9八、2000和XP操做系統中提供的一組函數,這些函數採用C語言調用格式,是爲程序員編制Windows應用程序提供的編程接口。程序員用C語言直接調用API也能夠編制Windows應用程序,但大量的程序代碼必須由程序員本身編寫,而API函數很是龐大,給編程者帶來很大的困難。

2.3.2  MFC類庫

因爲API函數十分龐大複雜,看不到函數之間的關係,使程序員不易使用。用C語言使用API函數編寫Windows應用程序是十分困難的。微軟的VC++6.0用類對API函數進行了封裝,爲編程提供了MFC類庫。使用MFC類庫簡化了Windows應用程序的編制。可是,MFC類庫的使用仍是比較複雜的,所以,VC++一直是一些專業人員的編程工具。

2.3.3  組件庫

爲了簡化Windows應用程序的設計,提出了組件(控件)的概念,組件也是類,按鈕、菜單、工具條等均可以封裝爲組件,組件採用屬性、事件、方法來描述,其中屬性描述組件的特性,如按鈕的標題,標籤字體的顏色和大小。方法是組件類提供的函數,經過調用這些方法,能夠控制組件的行爲。組件經過事件和外界聯繫,一個組件能夠響應若干個事件,能夠爲事件增長事件處理函數,之後每當發生該事件,將自動調用該事件處理函數處理此事件。不少組件在設計階段是可見的,支持可視化編程,這些組件又被叫作控件。用控件編制Windows應用程序很象搭積木,將控件放到窗體中,設置好屬性,漂亮的界面就設計好了。組件編程的工具備不少,例如:VB6.0、VB.Net、C#、C++Builder、Java、Delphi等快速開發工具(RAD)。這些工具都有本身的組件庫。

2.3.4  .NET框架類庫

.NET系統爲編制Windows應用程序、Web應用程序、Web服務,在.Net框架(.Net FrameWork)中提供了基礎類庫(Base Class Library)。它是一個統一的、面向對象的、層次化的、可擴展的類庫,統一了微軟當前各類不一樣的框架和開發模式,不管開發Windows應用程序,仍是開發Web應用程序,採用相同的組件名稱,組件具備相同的屬性、方法和事件,開發模式也相似,方便程序員學習。.Net框架類庫支持控件可視化編程,.Net中的VC++.Net、VB.Net、C#語言都使用這個類庫,消除了各類語言開發模式的差異。該類庫包括如下功能:基礎類庫(基本功能,象字符串、數組等)、網絡、安全、遠程化、診斷和調試、I/O、數據庫、XML、Web服務、Web編程、Windows編程接口等等。

Windows9八、2000和XP操做系統並不包含.NET框架類庫,爲了運行C#程序,必須安裝.Net FrameWork。

2.4      Windows應用程序的基本結構

Windows應用程序和控制檯應用程序的基本結構基本同樣,程序的執行老是從Main()方法開始,主函數Main()必須在一個類中。但Windows應用程序使用圖形界面,通常有一個窗口(Form),採用事件驅動方式工做。本節介紹Windows應用程序的基本結構。

2.4.1  最簡單的Windows應用程序

最簡單的Windows應用程序以下:

using System;//引入名字空間

using System.Windows.Forms;

public class Form1:Form//類定義

{   static void Main()//主函數

{   Application.Run(new Form1());

}

}

自定義類Form1以Form類爲基類。Form類是.Net系統中定義的窗體類,Form類對象具備Windows應用程序窗口的最基本功能,有標題欄、系統菜單、最大化按鈕、最小化按鈕和關閉按鈕、用戶區。Form類對象仍是一個容器,在Form窗體中能夠放置其它控件,例如菜單控件,工具條控件等等。System.Application類中的靜態方法Run負責完成一個應用程序的初始化,運行,終止等功能,其參數是本程序使用的窗體Form1類對象,Run方法還負責從操做系統接受事件,並把事件送到窗體中響應。窗體關閉,方法Run退出,Windows應用程序結束。假設已經將文件保存在d:\Charp目錄下,文件名爲:e1.cs。啓動命令行提示符,在屏幕上輸入一行命令:d:回車,cd  Charp回車,鍵入命令:

C:\WINNT\Microsoft.NET\Framework\v1.0.3705\csc /t:winexe /r:system.dll,System.Windows.Forms.dll e1.cs

命令中的/t:winexe表示要創建一個Windows應用程序,/r表示要引入的命名空間。也能夠用記事本創建一個批處理文件g.bat,將以上命令內容拷貝到文件中,運行g.bat,和在命令行提示符鍵入命令效果相同。以上方法在FrameWork SDK 2000中實現。若是一切正常e1.cs文件將被編譯,編譯後生成可執行文件e1.exe。運行可執行文件e1.exe,CRT上出現一個窗口如右圖。

能夠在Form1類中定義新的變量,因爲主窗體關閉,程序也就結束了,所以定義在主窗體Form1中的變量的生命週期和程序的生命週期是相同的,從這個意義上說,這些變量是全局變量。能夠爲Form1類定義構造函數,在構造函數中作一些初始化的工做,例如修改Form1標題欄中的標題。還能夠在Form1中定義控件類的對象,這些控件將在Form1的用戶區顯示出來,換句話講,在Form1中生成控件對象,也就是把控件放到窗體中。如在窗體中增長了一個按鈕(Button)控件,單擊按鈕,將產生單擊按鈕事件,完成必定功能,下例說明了如何在窗體中增長控件,如何修改控件屬性,如何增長控鍵的事件處理函數。

using System;

using System.Windows.Forms;

public class Form1:Form

{   Button button1;//生成Button類引用變量,和應用程序有相同生命週期

public Form1()//構造函數

       {//下句修改主窗體標題,不指明屬性(方法)所屬對象,默認爲Form1類的屬性(方法)

Text="個人第一個程序";//也可寫爲:this.Text="個人第一個程序";

button1=new Button();//生成Button類對象

button1.Location=new Point(25,25);//修改button1屬性location即按鈕位置

button1.Text="肯定";//修改button1屬性Text,即按鈕的標題

//下句指定button1_Click函數是按鈕單擊事件的單擊事件處理函數

button1.Click+=new System.EventHandler(button1_Click);

this.Controls.Add(button1);//按鈕增長到窗體中,將在主窗體用戶區顯示出來

    }

static void Main()

{   Application.Run(new Form1());

}

private void button1_Click(object sender, System.EventArgs e)

{//事件處理函數

this.button1.Text="單擊了我";//單擊按鈕事件執行的語句

}

}

請注意在窗體中增長控件類的對象的步驟,首先生成一個引用變量button1,和主窗體Form1有相同的生命週期,第二步在構造函數中用new生成Button類對象,第三步在構造函數中修改button1的屬性,增長button1的事件函數。這些步驟對於定義任何一個控件都是相同的。編譯運行結果如右圖:

 

2.4.2  用Visual Studio.Net創建Windows應用程序框架

以上所作的工做,都是一些固定的工做,能夠使用Visual Studio.Net自動創建,下面介紹使用Visual Studio.Net建立Windows應用程序的具體步驟。

(1) 運行Visual Studio.Net程序,出現如圖1.2.2A界面。

(2) 單擊新建項目按鈕,出現如圖1.2.2B對話框。在項目類型(P)編輯框中選擇Visual C#項目,在模板(T)編輯框中選Windows應用程序,在名稱(N)編輯框中鍵入e2,在位置(L)編輯框中鍵入D:\csarp。也能夠單擊瀏覽按鈕,在打開文件對話框中選擇文件夾。單擊肯定按鈕,建立項目。出現如圖2.4.2A界面。生成一個空白窗體(Form1)。

 

                                圖2.4.2A

(3) 在e2文件夾中下有兩個文件夾和8個文件,通常只修改Form1.cs文件。右擊Form1窗體,在快捷菜單中選擇菜單項查看代碼(C),可打開Form1.cs文件。Visual Studio.Net生成的Foem1.cs文件以下,這是使用Visual Studio.Net建立Windows應用程序的最基本的形式。底色爲黑色的字是做者增長的註解。

using System;//引入名字空間

using System.Drawing;

using System.Collections;

using System.ComponentModel;

using System.Windows.Forms;

using System.Data;

namespace e2//定義名字空間,///爲解釋

{    //此處可定義其它類

     /// <summary>

     /// Form1 的摘要說明。

     /// </summary>

     public class Form1 : System.Windows.Forms.Form//Forme1類定義

     {    //此處可定義本身的變量,這些變量和運行程序同生命週期

         /// <summary>

         /// 必需的設計器變量。

         /// </summary>

         private System.ComponentModel.Container components = null;

         public Form1()//構造函數

         {

              //

              // Windows 窗體設計器支持所必需的

              //

              InitializeComponent();//此函數系統自動生成,不要修改,該函數作一些初始化工做

              //

              // TODO: 在 InitializeComponent 調用後添加任何構造函數代碼

              //在構造函數增長本身的初始化代碼,必須放在InitializeComponent()以後

         }

         /// <summary>

         /// 清理全部正在使用的資源。

         /// </summary>

         protected override void Dispose( bool disposing )

         {

              if( disposing )

              {

                   if (components != null)

                   {

                       components.Dispose();

                   }

              }

              base.Dispose( disposing );

         }

         #region Windows Form Designer generated code

         /// <summary>

         /// 設計器支持所需的方法 - 不要使用代碼編輯器修改

         /// 此方法的內容。

         /// </summary>

         private void InitializeComponent()

         {    //此函數系統自動生成,不要修改函數內容,函數作一些初始化工做

              //

              // Form1

              //

              this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);

              this.ClientSize = new System.Drawing.Size(292, 273);

              this.Name = "Form1";//this 是Form1窗體對象

              this.Text = "Form1";

         }

         #endregion

         /// <summary>

         /// 應用程序的主入口點。

         /// </summary>

         [STAThread]

         static void Main()//程序入口函數 ,通常不修改

         {

              Application.Run(new Form1());//主程序創建窗體運行

         }//程序入口函數以後可定義本身的方法、屬性等

     }

}

(4) 下邊在窗體中增長一個按鈕,併爲按鈕增長單擊事件函數。單擊圖2.4.2A中標題爲Forms.cs[設計]的窗口標籤,返回標題爲Forms.cs[設計]的窗口。向項目中添加控件須要使用工具箱窗口,若看不到,能夠用菜單命令視圖/工具箱打開這個窗口(見圖2.4.2B左圖)。選中工具箱窗口中Windows窗體類型下的Button條目,而後在標題爲Forms.cs[設計]的窗口的Form1窗體中按下鼠標左鍵,拖動鼠標畫出放置Button控件的位置,擡起鼠標左鍵,就將Button控件放到Form1窗體中。選中按鈕控件,屬性窗口(見圖2.4.2B中圖)顯示按鈕屬性,其中左側爲屬性名稱,右側爲屬性值,用屬性窗口修改Button的Text屬性值爲:肯定。單擊屬性窗體上的第4個圖標,打開事件窗口(見圖2.4.2B右圖),顯示Button控件所能響應的全部事件,其中左側爲事件名稱,右側爲事件處理函數名稱,若是爲空白,表示尚未事件處理函數,選中Click事件,雙擊右側空白處,增長單擊事件處理函數。

                                      圖2.4.2B

完成以上設計後,集成環境生成的Foem1.cs文件以下,底色爲黑色的代碼是新增代碼。

using System;

using System.Drawing;

using System.Collections;

using System.ComponentModel;

using System.Windows.Forms;

using System.Data;

namespace e2

{

     /// <summary>

     /// Form1 的摘要說明。

     /// </summary>

     public class Form1 : System.Windows.Forms.Form

     {

         private System.Windows.Forms.Button button1;//定義Button類引用變量

         /// <summary>

         /// 必需的設計器變量。

         /// </summary>

         private System.ComponentModel.Container components = null;

         public Form1()

         {

              //

              // Windows 窗體設計器支持所必需的

              //

              InitializeComponent();

              //

              // TODO: 在 InitializeComponent 調用後添加任何構造函數代碼

              //

         }

         /// <summary>

         /// 清理全部正在使用的資源。

         /// </summary>

         protected override void Dispose( bool disposing )

         {

              if( disposing )

              {

                   if (components != null)

                   {

                       components.Dispose();

                   }

              }

              base.Dispose( disposing );

         }

         #region Windows Form Designer generated code

         /// <summary>

         /// 設計器支持所需的方法 - 不要使用代碼編輯器修改

         /// 此方法的內容。

         /// </summary>

         private void InitializeComponent()

         {

              this.button1 = new System.Windows.Forms.Button();//生成對象

              this.SuspendLayout();

              //

              // button1

              //

              this.button1.Location = new System.Drawing.Point(96, 56);//修改屬性

              this.button1.Name = "button1";

              this.button1.Size = new System.Drawing.Size(72, 32);

              this.button1.TabIndex = 0;

              this.button1.Text = "肯定";

              this.button1.Click += new System.EventHandler(this.button1_Click);//增長事件

              //

              // Form1

              //

              this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);

              this.ClientSize = new System.Drawing.Size(292, 273);

              this.Controls.AddRange(new System.Windows.Forms.Control[] {this.button1});

              this.Name = "Form1";

              this.Text = "Form1";

         }

         #endregion

         /// <summary>

         /// 應用程序的主入口點。

         /// </summary>

         [STAThread]

         static void Main()

         {

              Application.Run(new Form1());

         }

         private void button1_Click(object sender, System.EventArgs e)

         {//事件處理函數

         }

     }

}

請注意按鈕放到窗體後,集成環境自動增長的語句。分析這些增長的語句,可知在窗體中增長Button類對象的步驟:首先定義Button類變量button1,這是Form1類的一個字段,因爲主窗體關閉,程序也就結束了,所以定義在主窗體Form1中的變量的生命週期和程序的生命週期是相同的,從這個意義上說,這樣的變量是全局變量。所以變量button1和主窗體Form1有相同的生命週期。第二步在構造函數中用new生成Button類對象,第三步在構造函數中修改button1的屬性,第四步增長button1的事件函數,函數button1_Click()是事件處理函數,語句this.button1.Click += new System.EventHandler(this.button1_Click)把按鈕Button1的事件Click和事件處理函數button1_Click()聯繫到一塊兒。程序員應在事件處理函數button1_Click()中增長具體的事件處理語句。這些步驟對於增長任何控件都是相同的。能夠比較一下2.4.1節中的步驟,它們基本是相同的。應熟悉以上操做步驟,學會在窗體中增長控件,修改控件屬性,增長事件函數。

2.4.3  方案(Solution)和項目(Project)

一個應用(Application)可能包括一個或多個可執行程序,例如,學生信息管理系統,可能包括客戶端程序和服務器端程序,全部這些可執行程序的集合叫作一個應用解決方案。爲了生成一個可執行程序,可能須要有一個或多個文件,例如,通常須要一個窗體文件,有時還須要一個資源文件,若干圖形或圖像文件。全部這些文件的集合叫一個項目,所以項目是爲了建立一個可執行程序所必需的全部的文件的集合。而一個方案中可能包括多個項目。爲了方便管理項目和項目所在的方案,Visual Studio.Net爲開發人員提供瞭解決方案資源管理器窗口(圖2.4.3)。它能夠爲咱們顯示一個方案的樹形結構,以及它所包含的項目及項目中的文件。

一個項目通常要放在一個文件夾中,例如上邊的例子,項目e2的全部文件都在文件夾e2中,共有兩個文件夾和8個文件,它們的用途以下:

l  bin文件夾:包含debug子文件夾,存儲生成帶調試信息的可執行C#程序。

l  obj文件夾:包含編譯過程當中生成的中間代碼。

l  AssemblyInfo.cs:建立項目自動添加。包含各類屬性設置,例如,項目最終建立的可執行文件或DLL文件中的信息,如標題、描述、公司名等。通常用工具修改該程序,不要直接修改。

l  Form1.cs:窗體文件,程序員通常只修改該文件。

l  Form1.resx:資源文件。程序員用集成環境提供的工具修改,不要直接修改。

l  e2.suo:解決方案用戶選項文件,記錄用戶關於解決方案的選項。

l  e2.csproj:項目文件,記錄用戶關於項目的選項。

l  e2.sln:解決方案文件。

爲了之後從新用Visual Studio.Net打開該解決方案,必須保存除了兩個文件夾之外的全部文件,實際上,因爲文件夾e2不太大,能夠保存整個e2文件夾。若是從新開始一個解決方案,首先用菜單項文件/關閉解決方案,關閉當前項目,再新建一個項目。爲了用Visual Studio.Net修改之前的程序,必須打開保存的項目文件(擴展名爲csproj),或者使用菜單項文件/打開項目,打開保存的項目,同時打開項目所在的解決方案。

 

 

        圖2.4.3

習題

(1)Windows應用程序和dos程序有那些不一樣。

(2)以鍵盤操做爲例說明什麼是事件驅動。

(3)那些Windows操做系統提供了.NET框架類庫,那些提供了API。

(4)運行C#程序,應首先安裝那些軟件。

(5)定義一個和應用程序同生命週期的變量,該變量應定義在何處,說明該變量的使用範圍。

(6)在窗體中增長一個控件,應如何操做,集成環境增長了那些代碼。

(7)爲控件增長事件函數,應如何操做,集成環境增長了那些代碼。

(8)如何爲窗體文件增長一個方法,說明該方法的使用範圍。

 

 

第三章       經常使用控件和類的使用

Visual Studio.Net(簡稱VS.NET)使用控件(組件)設計Windows應用程序。將VS.NET工具箱窗口中的控件放到窗體中,使用屬性窗口改變控件的屬性,或在程序中用語句修改屬性,爲控件增長事件函數,完成指定的功能。

3.1      控件通用屬性

大部分控件,例如Label、Button、TextBox等,都是Control類的派生類。Control類中定義了這些派生類控件通用的一組屬性和方法,這些屬性是:

l  Name:控件的名稱,區別控件類不一樣對象的惟一標誌,例如創建一個Button控件類對象,可用以下語句,Button button1=new Button(),那麼Name屬性的值爲button1。

l  Location:表示控件對象在窗體中的位置。本屬性是一個結構,結構中有兩個變量,x和y,分別表明控件對象左上角頂點的x和y座標,該座標系以窗體左上角爲原點,x軸向左爲正方向,y軸向下爲正方向,以像素爲單位。修改Location,能夠移動控件的位置,例如:button1.Location=new Point(100,200)語句移動按鈕button1到新位置。

l  Left和Top:屬性值等效於控件的 Location 屬性的 X 和Y。修改Left和Top,能夠移動控件的位置,例如:button1.Left=100語句水平移動按鈕button1。

l  Size:本屬性是一個結構,結構中有兩個變量,Width和Height分別表明控件對象的寬和高,例如可用語句button1.Size.Width=100修改Button控件對象button1的寬。

l  BackColor:控件背景顏色。

l  Enabled:布爾變量,爲true表示控件能夠使用,爲false表示不可用,控件變爲灰色。

l  Visible:布爾變量,爲true控件正常顯示,爲false控件不可見。

l  Modifier:定義控件的訪問權限,能夠是private、public、protected等。默認值爲private。

l  Cursor:鼠標移到控件上方時,鼠標顯示的形狀。默認值爲Default,表示使用默認鼠標形狀,即爲箭頭形狀。

3.2      Form類

Form類是.Net系統中定義的窗體類(WinForm),它屬於System.Windows.Forms名字空間。Form類對象具備Windows應用程序窗口的最基本功能。它能夠是對話框、單文檔或多文檔應用程序窗口的基類。Form類對象仍是一個容器,在Form窗體中能夠放置其它控件,例如菜單控件,工具條控件等等,還能夠放置子窗體。

  1. 1.             Form經常使用屬性

l  AutoScroll:布爾變量,表示窗口是否在須要時自動添加滾動條。

l  FormBorderStyle:窗體邊界的風格,若有無邊界、單線、3D、是否可調整等。

l  Text:字符串類對象,窗體標題欄中顯示的標題。

l  AcceptButton:記錄用戶鍵入回車時,至關於單擊窗體中的那個按鈕對象。

l  CanceButton:記錄用戶鍵入ESC鍵時,至關於單擊窗體中的那個按鈕對象。以上兩個屬性多用於對話框,例如打開文件對話框,用戶鍵入回車,至關於單擊肯定按鈕。

l  MaxiMizeBox:窗體標題欄右側最大化按鈕是否可用,設置爲false,按鈕不可用。

l  MiniMizeBox:窗體標題欄右側最小化按鈕是否可用,設置爲false,按鈕不可用。若是屬性MaxiMizeBox和MiniMizeBox都設置爲false,將只有關閉按鈕。在不但願用戶改變窗體大小時,例如對話框,將二者都設置爲false。

  1. 2.    Form類經常使用方法

l  Close():窗體關閉,釋放全部資源。如窗體爲主窗體,執行此方法,程序結束。

l  Hide():隱藏窗體,但不破壞窗體,也不釋放資源,可用方法Show()從新打開。

l  Show():顯示窗體。

  1. 3.    Form類經常使用事件

l  Load:在窗體顯示以前發生,能夠在其事件處理函數中作一些初始化的工做。

3.3      標籤(Label)控件

標籤控件用來顯示一行文本信息,但文本信息不能編輯,經常使用來輸出標題、顯示處理結果和標記窗體上的對象。標籤通常不用於觸發事件。

  1. 1.         Label控件經常使用屬性

l  Text:顯示的字符串

l  AutoSize:控件大小是否隨字符串大小自動調整,默認值爲false,不調整。

l  ForeColor:Label顯示的字符串顏色。

l  Font:字符串所使用的字體,包括所使用的字體名,字體的大小,字體的風格等等,具體修改方法見下邊的例子。

  1. 2.         例子e3_3:個人第一個程序

下面的例子在窗口中顯示一行文本,該例雖然簡單,但包括了用Visual Studio.Net創建C# Windows應用程序的基本步驟。具體實現步驟以下:

(1)創建一個新項目,生成一個空白窗體(Form1),見圖2.4.2A。能夠用屬性窗口(圖2.4.2B中圖)修改窗體的屬性,例如修改Form1的屬性Text,能夠修改窗體的標題。用鼠標拖動窗體的邊界小正方形,能夠修改窗體打開時的初始大小。

(2)雙擊工具箱窗口(圖2.4.2B左圖)中Windows窗體類型下的Label條目,在窗體Form1放置一個Label控件。該控件用來顯示一行文本。能夠用鼠標拖放Label到窗體的任意位置,並可拖動Label邊界改變控件的大小。

(3)選中Label控件,在屬性窗口中找到屬性text,把它的值由「Label1」修改成「個人第一個程序」。接着在屬性窗口中選中Font屬性,單擊Font屬性右側的標題爲…的按鈕,打開對話框,在對話框中能夠修改Label控件顯示字符串的字體名稱和字號等,也能夠單擊Font屬性左邊的+號,在出現的子屬性中編輯。編輯完成後,單擊Font屬性左邊的-號,隱藏Font的子屬性。修改ForeColor屬性能夠修改Label控件顯示字符串的顏色。這是在設計階段修改屬性。

(4) 編譯,運行,能夠看到窗口中按指定字體大小和顏色顯示:個人第一個程序。運行效果如右圖。

(5)保存項目。生成一個可執行程序須要多個文件,這些文件組成一個項目。通常把一個項目存到一個子目錄中。單擊文件/存全部文件菜單項,保存全部文件。

(6)  關掉VS.NET,再啓動。用文件/打開項目菜單項打開剛纔關閉的項目文件(擴展名爲sln)。應能看到剛纔關閉的設計界面。必須打開項目,才能完成編譯工做。

3.4      按鈕(Button)控件

用戶單擊按鈕,觸發單擊事件,在單擊事件處理函數中完成相應的工做。

  1. 1.         Button 控件的經常使用屬性和事件

l  屬性Text:按鈕表面的標題

l  事件Click:用戶單擊觸發的事件,通常稱做單擊事件。

  1. 2.         例子e3_4

本例說明如何用程序修改屬性,如何使用方法,增長事件函數。該例在窗口中顯示一行文字,增長2個按紐,單擊標題爲紅色的按紐把顯示的文本顏色改成紅色,單擊標題爲黑色的按紐把顯示的文本顏色改成黑色。實現步驟以下:

(1)繼續上例,放三個Button控件到窗體,修改屬性Text,使標題分別爲紅色,黑色,退出。設計好的界面如右圖。

(2)選中標題爲紅色的按紐,打開事件窗口(見圖2.4.2B右圖),顯示該控件所能響應的全部事件,其中左側爲事件名稱,右側爲事件處理函數名稱,若是爲空白,表示尚未事件處理函數,選中Click事件,雙擊右側空白處,增長單擊(Click)標題爲紅色的按鈕的事件處理函數以下:

private void button1_Click(object sender, System.EventArgs e)

{   label1.ForeColor=Color.Red;//運行階段修改屬性

}//注意label1是控件的名字(label的Name屬性),用它來區分不一樣的控件。

(3)單擊(Click)標題爲黑色的按紐的事件處理函數以下:

private void button2_Click(object sender, System.EventArgs e)

{   label1.ForeColor=Color.Black;}

(4)單擊(Click)標題爲退出的按紐的事件處理函數以下:

private void button3_Click(object sender, System.EventArgs e)

{   Close();}

Close()爲窗體(Form)的方法,做用是關閉注窗體。因爲關閉了主窗體,程序也就結束了。注意,引用窗體的方法和屬性時可不用指定對象名,換句話講,如不指定屬性或方法的對象名,默認爲窗體的屬性或方法。而使用其它組件的屬性及方法要指明所屬組件對象,例如label1.ForeColor=Color.Red;

(5)編譯,運行,單擊標題爲紅色的按紐,窗體顯示字符串顏色變爲紅色,單擊標題爲黑色的按紐,窗體顯示字符串顏色變爲黑色,單擊標題爲退出的按紐,結束程序。

3.5      事件處理函數的參數

事件處理函數通常有兩個參數,第一個參數(object sender)爲產生該事件的對象的屬性Name的值,例如上例單擊標題爲紅色的按鈕,第一個參數sender的值爲button1。如上例標題爲紅色的按鈕和標題爲黑色的按鈕使用同一個單擊事件處理函數,其事件處理以下:

private void button1_Click(object sender,System.EventArgs e)

{   if(sender==button1)

label1.ForeColor=Color.Red;

else

label1.ForeColor=Color.Black;

}

事件處理函數第二個參數(System.EventArgs e)表明事件的一些附加信息,事件不一樣,所表明的信息也不相同,例如在後邊的例子中能夠看到,按下鼠標的事件處理函數中,e.X和e.Y分別爲發生事件時鼠標位置的x座標和y座標,e.Button表示用戶單擊了鼠標那個鍵,如爲MouseButtons.Left,表示單擊了鼠標左鍵。

爲了使這兩個按鈕使用相同的單擊事件處理函數,首先爲標題爲紅色的按鈕增長單擊事件處理函數,便是上邊的代碼,事件函數名稱爲:button1_Click。選中標題爲黑色的按鈕,打開事件窗體(見圖2.4.2B右圖),選中Click事件,從其右側下拉列表中選擇事件處理函數爲button1_Click,這樣兩個按鈕就使用相同的單擊事件處理函數了。

3.6  文本框(TextBox)控件

TextBox控件是用戶輸入文本的區域,也叫文本框。

  1. 1.         TextBox控件屬性和事件

l  屬性Text:用戶在文本框中鍵入的字符串

l  屬性MaxLength:單行文本框最大輸入字符數。

l  屬性ReadOnly:布爾變量,爲true,文本框不能編輯。

l  屬性PasswordChar:字符串類型,容許輸入一個字符,如輸入一個字符,用戶在文本框中輸入的全部字符都顯示這個字符。通常用來輸入密碼。

l  屬性MultiLine:布爾變量,爲true,多行文本框,爲false,單行文本框。

l  屬性ScrollBars:MultiLine=true時有效,有4種選擇:=0,無滾動條,=1,有水平滾動條,=2,有垂直滾動條,=3,有水平和垂直滾動條。

l  屬性SelLength:可選中文本框中的部分或所有字符,本屬性爲所選擇的文本的字符數。

l  屬性SelStart:所選中文本的開始位置。

l  屬性SelText:所選中的文本

l  屬性AcceptsReturn:MultiLine=true時有效,布爾變量,爲true,鍵入回車,換行,爲false,鍵入回車鍵,至關於單擊窗體中的默認按鈕。

l  事件TextChanged:文本框中的字符發生變化時,發出的事件。

  1. 2.         例子e3_6

本例要求用戶在編輯框中輸入兩個乘數,單擊按鈕把相乘的結果在編輯框中顯示出來。

(1)創建一個新的項目。放四個Label控件到窗體,Text屬性分別爲:被乘數,乘數,積,*,=。

(2)放三個textBox控件到窗體,屬性Name從左到右分別爲:textBox一、textBox二、textBox3,屬性Text都爲空。

(3)放三個Button控件到窗體,Text屬性分別修改成求積,清空,退出。設計的界面如上圖。

(4)標題爲求積的按鈕的單擊事件處理函數以下:

private void button1_Click(object sender, System.EventArgs e)

{   float ss,ee;

    ss=Convert.ToSingle(textBox1.Text);

    ee=Convert.ToSingle(textBox2.Text);

    textBox3.Text=Convert.ToString(ss*ee);

}

(5)標題爲清空的按鈕的單擊事件處理函數以下:

private void button2_Click(object sender,System.EventArgs e)

{   textBox1.Text="";

    textBox2.Text="";

    textBox3.Text="";

}

(6)標題爲退出的按鈕的單擊事件處理函數以下:

private void button3_Click(object sender, System.EventArgs e)

{   Close();}

(7)  編譯,運行,在文本框textBox1,textBox2分別輸入2和3,單擊標題爲求積的按紐,textBox3中顯示6,單擊標題爲清空的按鈕,三個文本框被清空,單擊標題爲退出的按紐,結束程序。

3.7      Convert類

Convert類中提供了一些靜態方法,用來把一種類型數據轉換爲另外一種類型數據。例如,Convert.ToSingle(textBox1.Text)把字符串textBox1.Text轉換爲單浮點數。Convert.ToString(3.14)把單浮點數3.14轉換爲字符串。其它轉換函數還有:ToInt、ToInt16等等。

3.8      單選按鈕(RadioButton)和GroupBox控件

RadioButton是單選按鈕控件,多個RadioButton控件能夠爲一組,這一組內的RadioButton控件只能有一個被選中。GroupBox控件是一個容器類控件,在其內部可放其它控件,表示其內部的全部控件爲一組,其屬性Text可用來表示此組控件的標題。例如把RadioButton控件放到GroupBox控件中,表示這些RadioButton控件是一組。有一些特性是互斥的,例如性別,選擇這類特性可用RadioButton和GroupBox控件。

  1. 1.        GroupBox控件經常使用屬性

GroupBox控件經常使用屬性只有一個,屬性Text,指定GroupBox控件頂部的標題。

  1. 2.        RadioButton控件屬性和事件

l  屬性Text:單選按鈕控件旁邊的標題。

l  屬性Checked:布爾變量,爲true表示按鈕被選中,爲false表示不被選中。

l  事件CheckedChanged:單選按鈕選中或不被選中狀態改變時產生的事件。

l  事件Click:單擊單選按鈕控件時產生的事件。

  1. 3.        例子e3_8

該例用RadioButton控件修改Label控件字符串的字體爲:宋體、黑體、楷體。具體實現步驟以下:

(1) 創建一個新的項目。

(2) 放Label控件到窗體,屬性Text=「不一樣的字體」。字體爲宋體。

(3) 放GroupBox控件到窗體,其屬性Text=「選擇字體」。

(4) 放三個RadioButton控件到GroupBox中,其屬性Text分別爲:宋體、黑體、楷體。宋體RadioButton控件的屬性Checked=true。設計好的界面如右圖。

(5) 爲三個RadioButton控件的CheckedChanged事件增長事件處理函數以下:

private void radioButton1_CheckedChanged(object sender, System.EventArgs e)

{   if(radioButton1.Checked)

label1.Font=new Font("宋體",label1.Font.Size);

}//label1顯示的字體變爲宋體,字體大小不變

private void radioButton2_CheckedChanged(object sender, System.EventArgs e)

{   if(radioButton2.Checked)

label1.Font=new Font("黑體",label1.Font.Size);

}

private void radioButton3_CheckedChanged(object sender, System.EventArgs e)

{   if(radioButton3.Checked)

label1.Font=new Font("楷體_GB2312",label1.Font.Size);

}

(6)    編譯,運行,單擊RadioGroup1中的三個RadioButton按鈕,能夠改變字體。注意三個按鈕只能選一個,既只能選一種字體。考慮一下,是否可用Click事件。

3.9      Font類

Font類有兩個構造函數:第一個是new Font(字體名稱,字號),例如,label1.Font=new Font("黑體",9),用法還可參考例e3_8。第二個是new Font(字體名稱,字號,字體風格),其中第三個參數是枚舉類型,具體定義以下:

enum FontStyle{

Regular     =0,//正常字體

Bold        =1,//黑體

Italic      =2,//斜體

BoldItalic  =3,//黑斜體

Underline   =4,//下劃線,5=黑體下劃線,6=斜體下劃線,7=黑斜體下劃線

Strikeout   =8}//刪除線,9=黑體刪除線,10=斜體刪除線,依此類推。

例如修改標籤控件字體爲斜體:

label1.Font=new Font("黑體",9,label1.Font.Style|FontStyle.Italic);

或者:label1.Font=new Font("黑體",9,label1.Font.Style|(FontStyle)2);

修改標籤控件字體不爲斜體:

label1.Font=new Font("黑體",9,label1.Font.Style&~FontStyle.Italic);

或者:label1.Font=new Font("黑體",9,label1.Font.Style&(FontStyle)(~2));

用法還可參考例e3_11。

3.10  多選框(CheckBox)控件

CheckBox是多選框控件,可將多個CheckBox控件放到GroupBox控件內造成一組,這一組內的CheckBox控件能夠多選,不選或都選。可用來選擇一些可共存的特性,例如一我的的愛好。

  1. 1.         CheckBox控件屬性和事件

l  屬性Text:多選框控件旁邊的標題。

l  屬性Checked:布爾變量,爲true表示多選框被選中,爲false不被選中。

l  事件Click:單擊多選框控件時產生的事件。

l  事件CheckedChanged:多選框選中或不被選中狀態改變時產生的事件。

  1. 2.         例子e3_10A

在窗口中增長2個CheckBox控件,分別用來選擇是否愛好音樂和是否愛好文學,用鼠標單擊CheckBox控件,改變愛好選擇,用Label控件顯示所選擇的愛好。實現步驟以下:

(1)創建新項目。放Label控件到窗體,屬性Text=「你的愛好是:」。

(2)放GroupBox控件到窗體,屬性Text=「愛好」。放兩個CheckBox控件到GroupBox中,屬性Text分別爲:音樂、文學。設計界面以下圖。

(3)標題爲音樂的多選框控件的CheckedChanged事件處理函數以下:

private void checkBox1_CheckedChanged(object sender, System.EventArgs e)

{   String text1="你的愛好是:";

if(checkBox1.Checked)

text1=text1+checkBox1.Text;

if(checkBox2.Checked)

text1+=checkBox2.Text;

label1.Text=text1;

}

(4)將標題爲文學的多選框控件的CheckedChanged事件處理函數,設置爲標題爲音樂的多選框控件的CheckedChanged事件處理函數,具體步驟見3.5節。

(5)編譯,運行。選中音樂將在標籤控件中顯示:你的愛好是:音樂,再選中文學顯示:你的愛好是:音樂文學,…。

  1. 3.         例子e3_10B

該例同上例,但按選中音樂和文學的順序在標籤中顯示愛好,實現步驟以下:

(1)創建一個新項目。爲Form1類增長私有變量String s="你的愛好是:"。

(2)放Label控件、GroupBox控件、兩個CheckBox到窗體,屬性設置同上例。

(4)標題爲音樂的多選框控件CheckBox1的CheckedChanged事件處理函數以下:

private void checkBox1_CheckedChanged(object sender,System.EventArgs e)

{   int n=s.IndexOf("音樂");//s中有字符串"音樂"嗎?n=-1表示沒有

if(n==-1)//n=-1,表示上次沒選此項,這次選中,應增長"音樂"

s+="音樂";

else//不然,表示上次已選此項,這次不選中,應刪除"音樂"

s=s.Remove(n,2);

label1.Text=s;

}

(5)標題爲文學的多選框控件CheckBox2的CheckedChanged事件處理函數以下:

private void checkBox2_CheckedChanged(object sender,System.EventArgs e)

{   int n=s.IndexOf("文學");//s中有字符串"文學"嗎?=-1表示沒有

if(n==-1)//=-1,表示上次沒選此項,這次選中,應增長"文學"

s+="文學";

else//不然,表示上次已選此項,這次不選中,應刪除"文學"

s=s.Remove(n,2);

label1.Text=s;

}

(6)編譯,運行。選中音樂在標籤中顯示:你的愛好是:音樂,再選中文學顯示:你的愛好是:音樂文學,不選音樂顯示:你的愛好是:文學,再選音樂顯示:你的愛好是:文學音樂。

3.11  列表選擇控件(ListBox)

列表選擇控件列出全部供用戶選擇的選項,用戶可從選項中選擇一個或多個選項。

  1. 1.         列表選擇控件的經常使用屬性、事件和方法

l  屬性Items:存儲ListBox中的列表內容,是ArrayList類對象,元素是字符串。

l  屬性SelectedIndex:所選擇的條目的索引號,第一個條目索引號爲0。如容許多選,該屬性返回任意一個選擇的條目的索引號。如一個也沒選,該值爲-1。

l  屬性SelectedIndices:返回全部被選條目的索引號集合,是一個數組類對象。

l  屬性SelectedItem:返回所選擇的條目的內容,即列表中選中的字符串。如容許多選,該屬性返回選擇的索引號最小的條目。如一個也沒選,該值爲空。

l  屬性SelectedItems:返回全部被選條目的內容,是一個字符串數組。

l  屬性SelectionMode:肯定可選的條目數,以及選擇多個條目的方法。屬性值能夠使:none(能夠不選或選一個)、one(必須並且必選一個)、MultiSimple(多選)或MultiExtended(用組合鍵多選)。

l  屬性Sorted:表示條目是否以字母順序排序,默認值爲false,不容許。

l  方法GetSelected():參數是索引號,如該索引號被選中,返回值爲true。

l  事件SelectedIndexChanged:當索引號(即選項)被改變時發生的事件。

  1. 2.         例子e3_11

根據列表框的選擇,爲字符串加下劃線、刪除線、變斜體、變粗體。具體步驟以下:

(1)  創建一個新項目。放Label控件到窗體,其屬性Text=「字體風格」。

(2)  放置ListBox控件到窗體中,屬性Name=listBox1。選中ListBox控件,在屬性窗口中,單擊Items屬性右側的三個小點,打開字符串集合編輯器對話框,在其中輸入四項:粗體、斜體、下劃線、刪除線,注意每一項要換行。如上圖。

(3)  設置列表選擇控件ListBox1屬性SelectionMode爲MultiExtended,容許多選。

(4)  爲列表選擇控件的事件SelectedIndexChenged增長事件處理函數以下:

private void listBox1_SelectedIndexChanged(object sender, System.EventArgs e)

{   int Style=0,k=1;//Style=0正常字體,1=黑體,2=斜體,3=黑斜體等,參見3.9節

    for(int i=0;i<listBox1.Items.Count;i++)//此例Count=4,爲何?

    {if(listBox1.GetSelected(i))//例如此例GetSelected(0)=true表示粗體被選中

        Style=Style|k;//增長指定風格

     else

        Style=Style&(~k);//取消指定風格

     k=k*2;

    }

    FontStyle m=new FontStyle();

    m=(FontStyle)Style;

    label1.Font=new Font(label1.Font.Name,9,m);}

(5)  編譯,運行,單選或用Ctrl鍵多選,看一下效果。運行效果如上圖。

3.12  下拉列表組合框(ComboBox)控件

控件ComboBox中有一個文本框,能夠在文本框輸入字符,其右側有一個向下的箭頭,單擊此箭頭能夠打開一個列表框,能夠從列表框選擇但願輸入的內容。現介紹該控件用法。

  1. 1.         ComboBox控件的經常使用屬性、事件和方法

l  屬性DropDownStyle:肯定下拉列表組合框類型。爲Simple表示文本框可編輯,列表部分永遠可見。爲DropDown是默認值,表示文本框可編輯,必須單擊箭頭才能看到列表部分。爲DropDownList表示文本框不可編輯,必須單擊箭頭才能看到列表部分。

l  屬性Items:存儲ComboBox中的列表內容,是ArrayList類對象,元素是字符串。

l  屬性MaxDropDownItems:下拉列表能顯示的最大條目數(1—100),若是實際條目數大於此數,將出現滾動條。

l  屬性Sorted:表示下拉列表框中條目是否以字母順序排序,默認值爲false,不容許。

l  屬性SelectedItem:所選擇條目的內容,即下拉列表中選中的字符串。如一個也沒選,該值爲空。其實,屬性Text也是所選擇的條目的內容。

l  屬性SelectedIndex:編輯框所選列表條目的索引號,列表條目索引號從0開始。若是編輯框未從列表中選擇條目,該值爲-1。

l  事件SelectedIndexChanged:被選索引號改變時發生的事件。

  1. 2.         例子e3_12 選擇Windows操做系統提供的全部字體

增長一個ComboBox控件,用來選擇字符串使用的字體名。本例提供方法使控件ComboBox的下拉列表中顯示Windows操做系統中使用的全部字體名。運行效果如右圖。實現步驟以下:

(1)  創建新項目。放Label控件到窗體,其屬性Text=「選擇不一樣字體」。

(2)  放ComboBox控件到窗體中,屬性Name=comboBox1,屬性DropDownStyle=DropDownList,不能在編輯框中輸入字體名,只能從下拉列表中選取。

(3)  爲窗體Form1的事件Load增長事件處理函數以下:

private void Form1_Load(object sender, System.EventArgs e)

{//Families是類FontFamily的一個靜態屬性,獲得操做系統中所使用的全部字體名

FontFamily[] families=FontFamily.Families;//靜態屬性沒有類的對象也可以使用

foreach (FontFamily family in families)

comboBox1.Items.Add(family.Name);//注意Add方法的使用

}

(4)  爲comboBox1的事件SelectedIndexChenged增長事件處理函數以下:

private void comboBox1_SelectedIndexChanged(object sender, System.EventArgs e)

{label1.Font=new Font(comboBox1.Text,9);}

(5)編譯,運行,在下拉列表中選擇不一樣字體名,標籤的字體變爲選擇的字體。從下拉列表中能夠看到操做系統中的全部字體名稱已經在列表中。

3.13  ToolTip控件

在一些Windows應用程序中,例如Word程序,當鼠標在工具條的按鈕上停留一段時間後,會在旁邊出現提示,ToolTip控件就是爲實現此功能的。能夠用ToolTip控件爲任何控件增長提示,本節介紹該控件的使用方法。

例子e3_13 Button控件增長提示

(1)      創建一個新項目。放Button控件到窗體,Name屬性爲Button1。

(2)      把toolTip控件放到窗體中,屬性Name=ToolTip1。

(3)      在Form1的構造函數中,增長語句以下:

toolTip1.SetToolTip(button1,"這是一個按鈕");

(4)      編譯,運行,當鼠標在Button上停留一段時間後,會在旁邊出現提示:這是一個按鈕。

3.14  超級連接(LinkLable)控件

控件LinkLable是控件Label的派生類,和控件Label不一樣的是顯示的字符有下劃線,能夠爲LinkLable控件的LinkClicked事件增長事件處理函數,當鼠標指向LinkLable控件,鼠標形狀變爲手形,單擊該控件,調用這個事件處理函數,能夠打開文件或網頁。

  1. 1.  超級連接控件的屬性、方法和事件

l  屬性LinkColor:用戶未訪問過的連接的字符顏色,默認爲藍色。

l  屬性VisitedLinkColor:用戶訪問連接後的字符顏色。

l  屬性LinkVisited:若是已經訪問過該連接,則爲true;不然爲false。

l  屬性LinkArea: 是一個結構,變量LinkArea.Start表示字符串中開始加下劃線的字符位置,LinkArea.Length表示字符串中加下劃線字符的個數。

l  事件LinkClicked:單擊控件LinkLable事件。

  1. 2.         例子e3_14:用LinkLabel控件超級連接到微軟網站。

(1)  創建一個新工程。放LinkLabel控件到窗體,屬性Text=「介紹微軟的操做系統」。

(2)  修改LinkLabel控件屬性LinkArea.Length=2,LinkArea.Start=2。也可在構造函數用語句修改:linkLabel1.LinkArea=new LinkArea(2,2);

(3)  爲LinkLabel控件的事件LinkClicked增長事件處理函數:

private void linkLabel1_LinkClicked(object sender, System.Windows.Forms.LinkLabelLinkClickedEventArgs e)

{   linkLabel1.LinkVisited=true;

System.Diagnostics.Process.Start("http://www.micosoft.com.cn");

}

(4)  運行,效果如右圖,注意只有字符微軟帶下劃線。單擊微軟,打開瀏覽器訪問微軟主頁。

(5)  若是要打開一個窗口,列出C盤根目錄下的文件及文件夾,LinkLabel控件事件LinkClicked事件處理函數修改以下:

linkLabel1.LinkVisited=true;

System.Diagnostics.Process.Start("C:/");

(6)  若是要打開指定程序,例如打開記事本程序,修改LinkClicked事件處理函數以下:

linkLabel1.LinkVisited=true;

System.Diagnostics.Process.Start("notepad");

3.15  定時(Timer)控件

定時控件(Timer)也叫定時器或計時器控件,是按必定時間間隔週期性地自動觸發事件的控件。在程序運行時,定時控件是不可見的。

  1. 3.         定時控件的屬性、方法和事件

l  屬性Interval:週期性地自動觸發事件的時間間隔,單位爲毫秒。

l  屬性Enabled:爲true,啓動定時器。調用方法Start()也可啓動定時器。

l  方法Start()和Stop():啓動和中止定時器。設置屬性Enabled=false也可中止定時器。

l  事件Tick:每間隔屬性Interval指定的時間,產生事件Tick。

  1. 4.         例子e3_15用標籤控件顯示當前日期和時間

(1)      創建一個新項目。放Timer組件到窗體,Name屬性爲timer1。

(2)      放Label控件到窗體,Name屬性爲label1。

(3)      爲窗體Form1的事件Load增長事件處理函數以下:

private void Form1_Load(object sender, System.EventArgs e)

{     this.timer1.Interval=100;

this.timer1.Enabled=true;

label1.Text=DateTime.Now.ToString();

}

(4)  爲Timer1的Tick事件增長事件處理函數以下:

private void timer1_Tick(object sender, System.EventArgs e)

{   label1.Text=DateTime.Now.ToString();

}

(5)  編譯,運行,標籤控件位置顯示日期和時間。運行效果如上圖。

3.16  DateTime類

DateTime類中提供了一些靜態方法,能夠用來獲得日期、星期和時間,下面是一些經常使用的方法。

l  獲得日期和時間,並轉換爲字符串。

String s=DateTime.Now.ToString();//或DateTime.Today.ToString()

l  獲得年、月和日期

int y=DateTime.Now.Year;//獲得年

int m=DateTime.Now.Month;//獲得月

int d=DateTime.Now.Day;//獲得日期

String s=DateTime.Now.DayOfWeek.ToString();//英文表示的星期

l  獲得小時、分和秒

int h=DateTime.Now.Hour;//獲得小時

int m=DateTime.Now.Minute;//獲得分

int s=DateTime.Now.Second;//獲得秒

l  定義一個DateTime類對象,表示1999年1月13日3時57分32.11秒

System.DateTime moment=new System.DateTime(1999,1,13,3,57,32,11);

l  加法和減法(減法請讀者本身完成)

System.DateTime dTime=new System.DateTime(1980,8,5);//1980年8月5日

//時間間隔,17天4小時2分1秒

System.TimeSpan tSpan=new System.TimeSpan(17,4,2,1);

System.DateTime result=dTime+tSpan;//結果是:1980年8月22日4:2:1 AM.

3.17  菜單

Windows應用程序通常都有一個菜單,經過選擇菜單中的不一樣菜單項,完成指定的功能。使用主菜單控件MainMenu能夠很容易創建windows應用程序的主菜單。

  1. 1.         菜單的組成及功能

放主菜單控件MainMenu到窗體中,能夠爲窗體增長一個主菜單。主菜單通常包括若干頂級菜單項,例如,文件、編輯、幫助等。單擊頂級菜單項,能夠出現彈出菜單,彈出菜單中包含若干菜單項,例如單擊文件頂級菜單項,其彈出菜單通常包括打開文件、存文件、另存爲等菜單項,用鼠標單擊菜單項,能夠執行菜單項命令。有的菜單項還包括子菜單。

全部菜單項均可以有快捷鍵,即菜單項中帶有下劃線的英文字符,當按住ALT鍵後,再按頂級菜單項的快捷鍵字符,能夠打開該頂級菜單項的彈出菜單。彈出菜單出現後,按菜單項的快捷鍵字符,能夠執行菜單項命令。增長快捷鍵的方法是在菜單項的標題中,在要設定快捷鍵英文字符的前邊增長一個字符&,例如,菜單項的標題爲:打開文件(&0),菜單項的顯示效果爲:打開文件(0)。菜單項能夠有加速鍵,通常在菜單項標題的後面顯示,例如,菜單項打開文件的加速鍵通常是Ctrl+O,不打開菜單,按住Ctrl鍵後,再按O鍵,也能夠執行打開文件命令。設定加速鍵的方法是修改菜單項的ShortCut屬性。

  1. 2.         用程序生成菜單

放主菜單控件MainMenu到窗體中,能夠爲該窗體增長一個主菜單,Visual Studio.Net自動添加以下語句:

MainMenu mainMenu1=new MainMenu();

This.Menu=mainMenu1;//指定主窗口的主菜單是mainMenu1。

能夠創建多個MainMenu類對象,用第二條語句修改使主窗口使用不一樣的主菜單。有了主菜單對象,用以下語句爲主菜單增長頂級菜單項:

MenuItem myFile=mainMenu1.MenuItem.Add(「文件(&F)」);//頂級菜單項:文件

有了頂級菜單項對象,用以下語句爲頂級菜單項的彈出菜單增長菜單項:

myFile.MenuItem.Add(「打開(&O)」);//文件頂級菜單項的彈出菜單的菜單項:打開

實際上,這些均可以用Visual Studio.Net自動生成。

  1. 3.         菜單項的屬性和事件

l  屬性Checked:布爾變量,=true,表示菜單項被選中,其後有標記:∨。

l  屬性ShortCut:指定的加速鍵,能夠從下拉列表中選擇。

l  屬性ShowShortCut:布爾變量,true(默認值),表示顯示加速鍵,false,不顯示。

l  屬性Text:菜單項標題。如爲字符-,爲分隔線。如指定字符前加&,例如:顏色(&c),增長快捷鍵,即用Alt+c訪問顏色菜單。

l  經常使用事件Click:單擊菜單項事件。

  1. 4.         例子e3_17 增長菜單

本例在窗體中創建主菜單,主菜單包括一個頂級菜單項:顏色,其彈出菜單包括兩個菜單項:紅色、黑色,單擊標題爲紅色的菜單項,把窗體中顯示的字符串變爲紅色,單擊標題爲黑色的菜單項,把窗體中顯示的字符串變爲黑色。實現步驟以下:

(1)創建一個新項目。放Label控件到窗體。

(2)雙擊工具箱中Mainmenu控件,在窗體中增長主菜單。右下角有一主菜單圖標,在左上角有一方框,其中有文字:請在此處輸入,在此方框中輸入菜單標題。

(3)在方框內輸入字符」顏色」,在其下部方框內輸入字符」紅色」爲一菜單項,在」紅色」下輸入字符」黑色」爲另外一菜單項,再輸入」退出」菜單項。如但願在選中某一菜單項後出現下一級子菜單,可在菜單項右側方框中輸入子菜單項名。若是菜單項屬性Text的值爲-,則菜單項爲分隔符。能夠用鼠標拖動菜單項移動菜單項的位置。集成環境設計界面以下圖。

 

(4) 標題爲紅色的菜單項的單擊(Click)事件處理函數以下:

private void menuItem2_Click(object sender,System.EventArgs e)

{label1.ForeColor=Color.Red;}//改變字體顏色爲紅色

(5)標題爲黑色的菜單項的單擊(Click)事件處理函數以下:

private void menuItem3_Click(object sender, System.EventArgs e)

{label1.ForeColor=Color.Black;}//改變字體顏色爲黑色

(6)標題爲退出的菜單項的單擊(Click)事件處理函數以下:

private void menuItem4_Click(object sender, System.EventArgs e)

{   Close();}//退出程序

(7)  編譯,運行,單擊紅色和黑色菜單項,能改變字符串的顏色。效果如上圖。

3.18  工具條

通常Windows應用程序都有一個工具條,能夠認爲工具條上的按鈕爲菜單的某一菜單項的快捷按鈕,單擊工具條按鈕至關於單擊相應菜單項,完成一樣的功能。

  1. 1.         工具條的組成及功能

放工具條控件ToolBar到窗體中,能夠爲該窗體增長一個工具條。在工具條中能夠增長Button按鈕和其它控件,例如象Word程序的工具條中用下拉列表控件(ComboBox)選擇字號、字體等。通常工具條按鈕上都有一個圖標,提示用戶該按鈕的使用功能。按鈕的全部圖標存放到ImageList類對象中。單擊任何一個按鈕,都產生工具條控件的ButtonClick事件,在這個事件處理事件函數中,要用語句區分用戶單擊了那一個按鈕,以完成相應的功能。

  1. 2.         控件ToolBar的屬性、事件和方法

l  屬性BorderStyle:邊界風格,=None(默認值),無邊界;=FixedSingle,單線邊界;=Fixed3D,立體風格邊界。

l  屬性Button:集合屬性,存儲ToolBar的按鈕對象。單擊其後的按鈕,能夠打開ToolBarButton集合編輯器對話框(見下圖),增長或刪除按鈕,修改按鈕屬性。

 

l  屬性ImageList:指定一個ImageList類對象,該對象中能夠存儲若干圖標,這些圖標做爲ToolBar控件按鈕的圖標。

l  屬性Wrappable:布爾變量,=true(默認值),當窗體Form水平尺寸小於工具條的水平尺寸時,一行不能顯示全部按鈕,容許下一行顯示;=false,不容許。

l  事件ButtonClick:ToolBar控件的單擊事件。在ButtonClick事件處理事件函數中,要用語句區分用戶單擊了那一個按鈕,以完成相應的功能。

l  屬性ShowToolTips:布爾變量,=true,容許顯示提示信息。

l  方法IndexOF():參數爲ToolBar控件中按鈕的屬性Name,返回其索引值。

  1. 3.         ToolBar控件中ToolBarButton按鈕的屬性

ToolBar控件中ToolBarButton按鈕能夠看做獨立的控件,它有本身獨立的屬性。下面介紹ToolBar控件中ToolBarButton按鈕的屬性。

l  屬性ImageIndex:ToolBar控件屬性ImageList指定一個ImageList類對象,該對象中的圖標做爲ToolBar控件按鈕的圖標。這個屬性指定本按鈕使用ImageList類對象中存儲的第幾個圖標。

l  屬性Style:有4個值,=PushButton,爲普通按鈕;=Separator,爲一分割符,再左邊和右邊的兩個按鈕中間增長一個間隙;=ToggleButton,開關按鈕,單擊該按鈕,按鈕被按下,不擡起,再單擊,擡起。=DropDownButton,下拉按鈕,按鈕右側有一個下拉箭頭,單擊下拉箭頭,能夠彈出下拉列表。

l  屬性Text:ToolBar控件中按鈕除了有圖標外,還能夠有屬性Text指定的文字。

l  屬性ToolTipText:當鼠標在工具條按鈕上停留一段時間後,將在工具條按鈕旁邊出現此屬性指定的提示。

  1. 4.         例子e3_18

現爲上例的菜單增長工具條,有兩個按鈕,單擊按鈕分別使字體變紅、變黑。步驟以下:

(1)    繼續菜單的例子,放ImageList控件到窗體。

(2)    放ToolBar控件到窗體。修改屬性ImageList=ImageList1。

(3)    單擊ImageList屬性Images後按鈕,打開Image集合編輯器,單擊添加按鈕,打開選擇文件對話框。按指定路徑選擇圖標的文件後,單擊肯定按鈕,增長圖標到ImageList對象中。在C:\Program Files\Microsoft Office\Office\forms\2052文件夾和C:\program files\Microsoft Visual Studio.Net\Common7\Graphics\Icon\Misc文件夾中有若干圖標。也可用畫筆程序本身設計圖標,圖標的寬和高應比工具條按鈕的寬和高略小,存爲.ico文件。也能夠用抓圖軟件抓其它程序的圖標。任選以上方法,爲ImageList對象增長兩個圖標。

(4)    單擊ToolBar控件屬性Buttons後按鈕,打開ToolBarButton集合編輯器(見上圖),單擊添加按鈕,增長一個按鈕,從其屬性ImageIndex後的下拉列表中選擇按鈕使用的圖標,設置按鈕的ToolTipText屬性爲:改變字體爲紅色,爲工具按鈕增長提示。一樣方法增長第二個按鈕,按鈕的ToolTipText屬性爲:改變字體爲黑色。

(5)    設定ToolBar控件屬性ShowToolTips爲true。

(6)    爲ToolBar控件的ButtonClick事件增長事件函數以下:

private void toolBar1_ButtonClick(object sender,

System.Windows.Forms.ToolBarButtonClickEventArgs e)

{   int n=toolBar1.Buttons.IndexOf(e.Button);//n爲工具條中被單擊按鈕的序號

    switch(n)

    {   case 0://第一個按鈕,調用相應的菜單項的事件處理函數。

            this.menuItem3_Click(sender,e);

            break;

        case 1://第二個按鈕

            this.menuItem2_Click(sender,e);

            break;

    }

 }

(7)    編譯,運行,單擊兩個工具條按鈕,能夠分別使字體變爲紅色或黑色。見上圖。

3.19  狀態欄(StatusBar)控件

Windows應用程序的狀態欄通常用來顯示一些信息,如時間,鼠標位置等。

  1. 1.       狀態欄控件的屬性

l  屬性Panels:集合屬性,存儲狀態欄中的各個分欄對象。單擊其後標題爲…的按鈕,能夠打開StatusBarPanels集合編輯器對話框,增長或刪除分欄,修改分欄屬性。

l  屬性ShowPanel:布爾變量,=true,容許顯示多欄;=false,不容許。

  1. 2.       狀態欄(StatusBar)控件分欄的屬性

狀態條能夠爲單欄,也能夠爲多欄。屬性Text,表示在狀態欄中顯示的內容。如爲單欄,在單欄中顯示字符串的語句是:statusBar1.Text=」在單欄中顯示的文本」,如爲多欄,在第2欄中顯示字符串的語句是:statusBar1.Panels[1].Text=」在第2欄中顯示的文本」。

l  屬性Alignment:對齊方式,能夠爲左對齊、右對齊和中間對齊。

l  屬性Text:表示在狀態欄中顯示的內容。

l  屬性Width:欄的寬度。

l  屬性BorderStyle:指定狀態欄控件上 每一個分欄的邊框外觀。邊界風格,=None(默認值),不顯示邊框;=Raised,三維凸起邊框;=Sunken,三維凹陷邊框顯示。

  1. 例子e3_19 爲窗體增長狀態條,在狀態條內顯示時間和鼠標位置。

(1)    創建新項目。放StatusBar控件到窗體。單擊StatusBar控件屬性Panels後按鈕,打開StatusBarPanels集合編輯器(以下圖),單擊添加按鈕,增長若2欄。其序號爲0、1。

 

(2)    修改StatusBar控件屬性ShowPanel=true。

(3)    放Timer組件到窗體,Name=Timer1,屬性Interval=1000,Enabled=true。

(4)    爲Timer1的Tick事件增長事件處理函數以下:

private void timer1_Tick(object sender, System.EventArgs e)

{   statusBar1.Panels[0].Text=DateTime.Now.ToString();

}

(5)    爲Form1的MouseMove事件增長事件處理函數以下:

private void Form1_MouseMove(object sender,System.Windows.Forms.MouseEventArgs e)

{statusBar1.Panels[1].Text="X:"+e.X.ToString()+",Y:"+e.Y.ToString();

}

(6)    編譯,運行,如右圖,在第1欄中能夠看到當前時間,在窗口中移動鼠標,在第2欄中能夠看到鼠標的位置不斷變化。

3.20  鼠標事件

從類System.Windows.Forms.Control派生的控件都有鼠標事件,控件的Click事件本質上也是鼠標事件。一些控件還有單獨的鼠標事件,例如Form。鼠標事件有:

l  MouseDown:若是鼠標位於控件區域,按下鼠標按鍵時產生該事件。

l  MouseUp:若是鼠標位於控件區域,擡起鼠標按鍵時產生該事件。

l  MouseMove:若是鼠標在控件區域移動,產生該事件。

l  MouseEnter:鼠標進入控件區域,產生該事件。

l  MouseLeave:鼠標離開控件區域,產生該事件。

鼠標事件處理函數通常有兩個參數,第一個參數(object sender)是產生該事件的對象的屬性Name的值,例如,爲Form1的MouseDown事件增長事件函數,單擊Form1,第一個參數sender表明Form1對象。(System.Windows.Forms.MouseEventArgs e)是事件處理函數第二個參數,表明事件的一些信息,事件不一樣,所表明的信息也不相同,鼠標按下事件處理函數中,e.X爲發生事件時鼠標位置的x座標,e.Y爲發生事件時鼠標位置的y座標,e.Button爲MouseButtons.Left,表示單擊了鼠標左鍵等等,Right和Middle則分別表明右鍵和中間鍵。e.Clicks爲鼠標單擊的次數,若是大於2次,則爲雙擊。

例子e3_20在窗體中的指定區域,雙擊鼠標左鍵,用Label控件顯示雙擊鼠標的位置。指定區域的左上角座標爲(20,20),寬爲200,高爲200。

(1)  創建一個新項目。放Label控件到窗體。屬性Name=label1。

(2)  Panel控件能夠將窗體分爲多個區域。放Panel控件到窗體,屬性Location.X=20,Location.Y=20,屬性Width=200,Height=200,屬性Name=p1。

(3)  爲Panel的MouseDown事件增長事件函數以下:

private void p1_MouseDown(object sender,System.Windows.Forms.MouseEventArgs e)

{   if(e.Button==MouseButtons.Left&&e.Clicks>1)//若是是雙擊左鍵

label1.Text="X:"+e.X.ToString()+",Y:"+e.Y.ToString();

}

(4)  編譯,運行,分別在指定區域和區域外雙擊鼠標左鍵,看一下效果。分別在指定區域和區域外雙擊鼠標右鍵,看一下效果。

3.21  快捷菜單(ContextMenu)

使用過Word程序的人都知道,在其程序窗口的不一樣位置單擊右鍵,會出現不一樣彈出菜單,這個彈出菜單叫快捷菜單,這節介紹如何在應用程序中增長快捷菜單。快捷菜單和主菜單的屬性、事件和方法基本一致,只是快捷菜單沒有頂級菜單項,所以這裏就很少介紹了。

例子e3.21

例子在窗口中顯示一行字符串,加入兩個按紐,單擊按紐button1把字符串變爲紅色,單擊按紐button2把字符串變爲黑色。爲兩個按鈕創建快捷菜單,快捷菜單中有2個菜單項,單擊菜單項把字符串變爲紅色或黑色。爲窗體創建快捷菜單,菜單中僅有1個退出菜單項,單擊退出菜單項,退出程序。具體實現步驟以下:

(1)  創建一個新項目。放Label控件到窗體。

(2)  放2個Button控件到窗體,標題(屬性Text)分別爲紅色,黑色。

(3)  標題爲紅色的按鈕的單擊事件處理函數以下:

private void button1_Click(object sender, System.EventArgs e)

{   label1.ForeColor=Color.Red;}

(4)  標題爲黑色的按鈕的單擊事件處理函數以下:

private void button2_Click(object sender, System.EventArgs e)

{   label1.ForeColor=Color.Black;}

(5)  放2個ContextMenu控件到窗體,屬性Name分別爲contextMenu1,contextMenu2。

(6)  選中contextMenu1控件,在菜單編輯器中增長兩個標題分別爲紅色和黑色的菜單項,它們的單擊事件處理函數分別是單擊紅色按鈕和單擊黑色按鈕的事件處理函數。

(7)  選中contextMenu2控件,在菜單編輯器中增長標題爲退出的菜單項,併爲其增長單擊事件處理函數,爲事件處理函數增長語句:Close();

(8)  將紅色按鈕和黑色按鈕的屬性ContextMenu指定爲contextMenu1。Form的屬性ContextMenu指定爲contextMenu2。

(9)  編譯,運行,右擊標題爲紅色的按鈕,快捷菜單contextMenu1打開,單擊快捷菜單中標題爲紅色的菜單項,將使窗體顯示的字符串顏色變爲紅色,右擊標題爲黑色的按鈕,快捷菜單contextMenu1打開,單擊快捷菜單中標題爲黑色的菜單項,將使窗體顯示的字符串顏色變爲黑色,右擊窗體,快捷菜單contextMenu2打開,單擊快捷菜單中標題爲退出的菜單項,將退出應用程序。運行效果如上圖。

3.22  綜合例子:計算器

具體步驟以下:

(1)  創建一個新項目。Form屬性MaxiMizeBox=false,屬性MiniMizeBox=false。屬性FormBorderStyle=FixedDialog,窗口不能修改大小。

(2)  放textBox控件到窗體,屬性Name=textBox1,屬性Text="0",屬性ReadOnly=true。

(3)  增長10個Button控件,前9個按鈕屬性Name分別爲:Button1-Button9,最後一個爲Button0,屬性Text分別爲:一、二、三、四、五、六、七、八、九、0。

(4)  增長7個Button控件,屬性Name分別爲:btn_dot、btn_equ、btn_add、btn_sub、btn_mul、btn_div、btn_C,屬性Text分別爲:.、=、+、-、*、/、C。設計界面以下圖。

(5)  控件Button0單擊事件處理函數以下:

private void button0_Click(object sender, System.EventArgs e)

{   if(sender==button0) append_num(0);

    if(sender==button1) append_num(1);

    if(sender==button2) append_num(2);

    if(sender==button3) append_num(3);

    if(sender==button4) append_num(4);

    if(sender==button5) append_num(5);

    if(sender==button6) append_num(6);

    if(sender==button7) append_num(7);

    if(sender==button8) append_num(8);

    if(sender==button9) append_num(9);

}

(6)  爲Form1類增長方法以下:

public void append_num(int i)

{   if(textBox1.Text!="0")

        textBox1.Text+=Convert.ToString(i);

    else

        textBox1.Text=Convert.ToString(i);

}

(7)  將Button1-Button9的單擊事件處理函數設定爲Button0單擊事件處理函數。

(8)  爲標題爲.按鈕增長事件處理函數以下:

private void btn_dot_Click(object sender, System.EventArgs e)

{   int n=textBox1.Text.IndexOf(".");

if(n==-1)//若是沒有小數點,增長小數點,不然不增長

textBox1.Text=textBox1.Text+".";

}

(9)  編譯,單擊數字按鈕,在textBox1能夠看到輸入的數字,也能夠輸入小數。

(10)  先實現加法,必須定義一個浮點類型變量sum,初始值爲0,記錄部分和。

(11)  輸入了第一個加數,而後輸入任一運算符(+、-、*、\或=),應首先清除編輯框中顯示的第一個加數,才能輸入第二個加數。爲實現此功能,必須定義一個布爾變量blnClear,初始值爲false,表示輸入數字或小數點前不清除編輯框中顯示,輸入運算符(+、-、*、\或=)後,blnClear=true,表示再輸入數字或小數點先清除編輯框中顯示。修改前邊程序,輸入數字或小數點前,要判斷變量blnClear,如爲true,清除編輯框中顯示的內容後,再顯示新輸入的數字或小數點,同時修改blnClear=false。爲此修改append_num方法以下:

public void append_num(int i)

{   if(blnClear)//若是準備輸入下一個加數,應先清除textBox1顯示內容

    {   textBox1.Text="0";//陰影部分爲新增語句

        blnClear=false;

    }

    if(textBox1.Text!="0")

        textBox1.Text+=Convert.ToString(i);

    else

        textBox1.Text=Convert.ToString(i);

}

(12)  修改btn_dot_Click方法以下:

private void btn_dot_Click(object sender, System.EventArgs e)

{   if(blnClear) //若是準備輸入下一個數,應先清除textBox1顯示內容

    {   textBox1.Text="0";//陰影部分爲新增語句

        blnClear=false;

    }

int n=textBox1.Text.IndexOf(".");

if(n==-1)//若是沒有小數點,增長小數點,防止屢次輸入小數點

textBox1.Text=textBox1.Text+".";

}

(13)  若是計算1+2-3的運算結果,先單擊按鈕1,編輯框中顯示1,再單擊按鈕+,執行運算sum=sum+1(注意此時sum=0),顯示sum到編輯框中(實際顯示不變),記住這次輸入的運算符,這裏爲+號。單擊按鈕2,編輯框中顯示2,再單擊按鈕-,按記錄的運算符(這裏是+)計算sum=sum+2,顯示sum到編輯框中,記住這次輸入的運算符,這裏爲-號,依此類推。爲實現此功能,必須定義一個字符串變量strOper,記錄輸入的運算符,初始值爲"+",保證輸入第一個運算符後,執行運算sum=sum+第一個加數,因爲初始sum=0,也就是sum=第一個加數。標題爲+的按鈕的單擊事件處理函數以下:

private void btn_add_Click(object sender, System.EventArgs e)

{   double dbSecond=Convert.ToDouble(textBox1.Text);

    if(!blnClear)//若是未輸入第二個操做數,不運算

        switch(strOper)//按記錄的運算符號運算

        {   case "+":

            sum+=dbSecond;

                break;

        //在此增長其它運算符-、*、\代碼

        }

    if(sender==btn_add)

        strOper="+";

    //在此增長運算符-、*、\、=代碼

    textBox1.Text=Convert.ToString(sum);

    blnClear=true;

}

(14)  =號處理語句和+號處理基本一致,修改標題爲+按鈕的事件函數以下:

private void btn_add_Click(object sender, System.EventArgs e)

{   double dbSecond=Convert.ToDouble(textBox1.Text);

    if(!blnClear)//若是未輸入第二個操做數,不運算

        switch(strOper)//按記錄的運算符號運算

        {   case "+":

            sum+=dbSecond;

                break;

        //在此增長運算符-、*、\代碼

        }

    if(sender==btn_add)

        strOper="+";

    if(sender==btn_equ)//爲=號處理增長的語句

        strOper="=";

    textBox1.Text=Convert.ToString(sum);

    blnClear=true;

}

將btn_equ按鈕的單擊事件函數設定爲+按鈕的單擊事件函數。

(15)  爲標題爲C按鈕增長事件函數以下:

private void btn_C_Click(object sender, System.EventArgs e)

{   textBox1.Text="0";

    sum=0;

    blnClear=false;

    strOper="+";

}

(16)  請讀者本身補上減法,乘法,除法運算的語句。

習題:

(1)  在窗口中顯示一行字符串,加入兩個按紐,單擊按紐1把字符串改成紅色,單擊按紐2把字符串改成黑色。使字符串爲紅色時紅色按紐不能使用,字符串爲黑色時黑色按紐不能使用。(提示:能夠修改按鈕的屬性Enabled爲false使其不能使用。)

(2)  將上題改成用按扭修改字體的大小,分別爲大字體和小字體。(參見3.9節)

(3)  加一文本框控件和一按紐,單擊按紐將文本框控件輸入內容顯示標籤控件上。(提示:單擊按鈕事件處理函數中加語句label1.Text=textBox1.Text)。

(4)  修改上題,使文本框控件和標籤控件文本同步顯示(提示:文本框控件的TextChanged事件處理函數中加語句label1.Text=textBox1.Text)。

(5)  加一文本框控件和一按紐,單擊按紐將文本框控件輸入的文本中選中的內容顯示在標籤控件上(提示:單擊按鈕事件處理函數中加語句label1.Text=textBox1.SelText。)

(6)  加一文本框控件和一按紐,單擊按紐將文本框控件輸入的文本的字符、選中的內容的字符數和選中的內容的開始位置顯示在標籤控件上。

(7)  用控件RadioButton選擇性別,把選擇的結果用Label控件顯示出來。

(8)  例子e3_8中如改成響應單擊事件Click,可能出現什麼問題?

(9)  用控件ComboBox修改標籤控件字體的大小。(用屬性Item在下拉列表中輸入大小)。

(10)放ListBox控件到窗體中,屬性Name=listBox1。列表框有三項分別爲:蘋果,梨子,香蕉。容許多選。標籤控件同步顯示ListBox控件所作的選擇。提示:爲ListBox控件的SelectedIndexChenged事件增長事件函數,

label1.Text="所選擇的是:";

for(int i=0;i<listBox1.SelectedIndices.Count;i++)

label1.Text+=listBox1.SelectedItems[i].ToString()+",";

(11)  放ListBox、TextBox和3個Button控件到窗體中,屬性Name分別爲listBox一、textBox一、Button一、Button二、Button3。Button控件屬性Text分別爲:增長、刪除、清空。單擊增長按鈕,把textBox中輸入的內容做爲一個條目增長到listBox1中,單擊刪除按鈕,刪除listBox1中所選擇的條目,單擊清空按鈕,清除listBox1全部條目。提示:增長用語句:listBox1.Items.Add(textBooooox1.Text)。刪除所選擇的條目用語句:listBox1.Items.RemoveAt(listBox1.SelectedIndex)。清除listBox1全部條目用語句:listBox1.Items.Clear()。

(12)  在窗體中顯示字符,每隔1秒字體變大些,變到必定尺寸後,每隔1秒字體變小些,如此循環。增長一個按鈕,能夠啓動和中止字符串字體大小變化,按鈕標題給出正確提示。

(13)  在窗體中顯示字符,每隔1秒字符移動必定距離,先右移,移到右邊界,再左移,移到左邊界,又一次右移,如此循環。(提示:修改Label的Left屬性值。)

(14)  修改例子e3_17,使顯示字符串爲紅色時,標題爲紅色的菜單項無效;使顯示字符串黑色時,標題爲黑色的菜單項無效。

(15)  修改例子e3_17,使顯示字符串爲紅色時,標題爲紅色的菜單項前增長選中標誌;使顯示字符串黑色時,標題爲黑色的菜單項前增長選中標誌。

(16)  爲例e3_17的菜單項增長加速鍵,鍵入Alt+c打開頂級菜單項顏色的彈出菜單,彈出菜單打開後,鍵入B執行標題爲黑色的菜單項命令,鍵入R執行標題爲紅色的菜單項命令。

(17)  爲例子e3_17的菜單項定義加速鍵(屬性Shortcut),鍵入ctrl+r使顯示字符串爲紅色,鍵入ctrl+b使顯示字符串黑色。

(18)  爲例子e3_17頂級菜單項顏色增長單擊事件處理函數,在事件處理函數中判斷顯示的字符串的顏色,決定是否爲相應的菜單項增長選中標誌。

(19)  拖動鼠標左鍵時,在狀態欄中顯示鼠標的位置。

(20)  模擬畫筆程序,在左側增長工具按鈕,在下部增長顏色按鈕。

(1)              在工具欄中加三個按鈕,單擊按鈕時,按鈕保持按下狀態,再單擊按鈕,按鈕擡起。在按下狀態,使標籤控件中字符串加下畫線、斜體或加粗,擡起則取消。

(21)  工具欄中按鈕的屬性Style設置爲ToolBarButtonStyle.DropDownButton,按鈕可有一個下拉菜單。首先建立一個ContextMenu菜單,指定工具欄中按鈕的屬性DropDownMenu的值爲建立的ContextMenu菜單對象,將在按下按鈕時顯示這個菜單。請用工具欄中按鈕的下拉菜單實現使標籤控件字符的顏色變爲紅色、黑色。(提示:工具欄中按鈕的屬性Style設置爲ToggleButton。屬性Pushed是一個布爾變量,表示工具欄按鈕當前是否處於按下狀態)

(22)用工具欄中按鈕的下拉菜單實現使標籤控件字符的顏色變爲紅色、黑色。(提示:如工具欄中按鈕的屬性Style設置爲DropDownButton按鈕可有一個下拉菜單。首先建立一個ContextMenu菜單,指定工具欄中按鈕的屬性DropDownMenu的值爲建立的ContextMenu菜單對象,將在按下按鈕時顯示這個菜單)

(23)  完成計算器的減法和乘除程序。增長求平方,對數等功能。(例如Math.Sqrt())

 

 

第四章       文本編輯器的實現

本章的目的是創建一個文本編輯器,同時繼續介紹控件的用法。有兩類文本編輯器:單文檔文本編輯器和多文檔文本編輯器,單文檔文本編輯器一次只容許打開一個文件,若是要打開另外一個文件,必須關閉當前打開的文件,微軟的寫字板程序就是一個典型的單文檔字處理程序。多文檔文本編輯器同時容許打開多個文件,每一個文件佔用一個子窗口,微軟的Word程序就是一個典型的多文檔字處理程序。本章首先介紹創建一個單文檔文本編輯器的方法,而後介紹創建多文檔文本編輯器的方法。

4.1      用RichTextBox控件實現文本編輯器

RichTextBox控件能夠用來輸入和編輯文本,該控件和TextBox控件有許多相同的屬性、事件和方法,但比TextBox控件的功能多,除了TextBox控件的功能外,還能夠設定文字的顏色、字體和段落格式,支持字符串查找功能,支持rtf格式等。這裏只介紹在TextBox控件中沒有介紹的屬性、事件和方法,相同部分就不介紹了,可參見TextBox控件。RichTextBox控件的屬性、事件和方法以下:

l  屬性Dock:不少控件都有此屬性,它設定控件在窗體中的位置,能夠是枚舉類型DockStyle的成員None、Left、Right、Top、Bottom或Fill,分別表示在窗體的任意位置、左側、右側、頂部、底部或充滿客戶區。在屬性窗口中,屬性DOCK的值用周邊5個矩形,中間一個矩形的圖形來表示。

l  屬性SelectedText:獲取或設置RichTextBox控件內的選定文本。

l  屬性SelectionLength:獲取或設置RichTextBox控件中選定文本的字符數。

l  屬性SelectionStart:獲取或設置RichTextBox控件中選定的文本起始點。

l  屬性SelectionFont:若是已選定文本,獲取或設置選定文本字體,若是未選定文本,獲取當前輸入字符采用字體或設置之後輸入字符采用字體。

l  屬性SelectionColor:若是已選定文本,獲取或設置選定文本的顏色,若是未選定文本,獲取當前輸入字符采用的顏色或設置之後輸入字符采用的顏色。

l  屬性Lines:記錄RichTextBox控件中全部文本的字符串數組,每兩個回車之間字符串是數組的一個元素。

l  屬性Modified:指示用戶是否已修改控件的內容。爲true,表示已修改。

l  事件SelectionChange:RichTextBox控件內的選定文本更改時發生的事件。

l  事件TextChanged:RichTextBox控件內的文本內容改變時發生的事件。

l  方法Clear():清除RichTextBox控件中用戶輸入的全部內容,即清空屬性Lines。

l  方法Copy()、Cut()、Paste():實現RichTextBox控件的拷貝、剪貼、粘貼功能。

l  方法SelectAll():選擇RichTextBox控件內的全部文本。

l  方法Find():實現查找功能。從第二個參數指定的位置,查找第一個參數指定的字符串,並返回找到的第一個匹配字符串的位置。返回負值,表示未找到匹配字符串。第三個參數指定查找的一些附加條件,能夠是枚舉類型RichTextBoxFinds的成員:MatchCase(區分大小寫)、Reverse(反向查找)等。容許有1個、2個或3個參數。

l  方法SaveFile():存文件,它有2個參數,第一個參數爲要存文件的全路徑和文件名,第二個參數是文件類型,能夠是:純文本,RichTextBoxStreamType.PlainText;Rtf格式流,RichTextBoxStreamType.RichText;採用Unicode編碼的文本流,RichTextBoxStreamType.UnicodePlainText。

l  方法LoadFile():讀文件,參數同方法SaveFile(),注意存取文件的類型必須一致。

l  方法Undo():撤消RichTextBox控件中的上一個編輯操做。

l  方法Redo():從新應用RichTextBox控件中上次撤消的操做。

4.2      實現文本編輯器的剪貼板功能

許多程序都支持剪貼板功能。經過剪貼板能夠完成數據的剪貼(Cut),複製(Copy),粘貼(Paste)等功能。剪貼板能夠理解爲一塊存儲數據的公共區域,用戶能夠把數據複製或剪貼到剪貼板中,本任務或其它任務要用剪貼板中的數據時,能夠用粘貼功能從剪貼板中把數據取出。存入剪貼板中的數據,能夠是字符,位圖,或者其它格式數據。實現文本編輯器的編輯和剪貼板功能的具體步驟以下:

(1)    新建項目。放RichTextBox控件到窗體。屬性Name=richTextBox1,Dock=Fill,Text=」」。

(2)    放Mainmenu控件到窗體中。增長頂級菜單項:編輯,爲其彈出菜單增長菜單項:剪切、複製、粘貼、撤銷和恢復,屬性Name分別爲:mainMenuEdit、menuItemEditCut、menuItemEditCopy、menuItemEditPaste、menuItemEditUndo、menuItemEditRedo。爲各個菜單項增長事件處理函數以下:

private void menuItemEditCut_Click(object sender, System.EventArgs e)

{   richTextBox1.Cut();}            //剪切

private void menuItemEditCopy_Click(object sender, System.EventArgs e)

{   richTextBox1.Copy();}           //拷貝

private void menuItemEditPaste_Click(object sender, System.EventArgs e)

{   richTextBox1.Paste();}          //粘貼

private void menuItemEditUndo_Click(object sender, System.EventArgs e)

{   richTextBox1.Undo();}           //撤銷

private void menuItemEditRedo_Click(object sender, System.EventArgs e)

{   richTextBox1.Redo();}           //恢復

(3)    編譯,運行,輸入一些字符後,選中一些字符,試驗一下剪切、複製、粘貼等功能,並查看一下在剪貼板中字符是否能粘貼到其它字處理軟件中,例如寫字板。查看一下撤銷和恢復功能是否可用。

4.3      實現文本編輯器的存取文件功能

文本編輯器都具備文件存取功能,頂級菜單項文件的彈出菜單中通常包括以下菜單項:新建、打開、關閉、保存和另存爲等。本節實現以上菜單項。

4.3.1 OpenFileDialog和SaveFileDialog控件

OpenFileDialog對話框用來選擇要打開的文件路徑及文件名,SaveFileDialog對話框用來選擇要存儲文件的路徑及文件名。兩個對話框的外觀以下圖,它們的屬性和方法基本相同,這裏在一塊兒介紹。

 

圖4.3.1A 打開文件對話框

 

圖4.3.1B 文件另存爲對話框

l  屬性Filter:字符串類型,選擇在對話框中顯示的文件類型。屬性Filter有多項,中間用|分開,每兩項是一組,每組的第一項將出如今對話框保存類型(T)下拉列表編輯框的下拉列表中(見圖4.3.1A),供用戶選擇,第二項表示如第一項被選中,對話框實際列出的文件。例如Filter="純文本文件(*.txt)|*.txt|全部文件(*.*)|*.*",表示打開對話框,對話框的文件類型(T)下拉列表編輯框的下拉列表有兩項:純文本文件(*.txt)和全部文件(*.*),供用戶選擇。若是從文件類型下拉列表編輯框的下拉列表中選中"純文本文件(*.txt)",表示打開對話框,只列出全部擴展名爲.txt的文件,若是選中"全部文件(*.*)",表示打開對話框,將列出全部文件。

l  屬性FilterIndex:表示打開對話框後,對話框的文件類型(T)下拉列表編輯框的下拉列表中首先被選中的項的索引號。能夠在設計階段在屬性窗口修改屬性FilterIndex和Filter,也可在程序中用下列語句修改:openFileDialog1.Filter="純文本文件(*.txt)|*.txt|全部文件(*.*)|*.*",openFileDialog1.FilterIndex=1。

l  屬性FileName:用戶選取的文件的路徑和文件名。

l  屬性InitialDirectory:打開對話框首先顯示該屬性指定的文件夾中的文件。

l  屬性DefaultExt:若是用戶未指定擴展名,自動增長屬性指定的文件擴展名。

l  方法ShowDialog():打開對話框,根據方法的返回值肯定用戶單擊了那個按鈕,如返回DialogResult.Cancle,用戶單擊了忽略按鈕,如返回DialogResult.OK,用戶單擊了打開或保存按鈕。

4.3.2存取文件功能的實現

(4)    把OpenFileDialog和SaveFileDialog控件放到窗體中。屬性Name分別是openFileDialog1和saveFileDialog1。

(5)    增長頂級菜單項:文件,爲其彈出菜單增長菜單項:新建、打開...、保存...、另存爲...、退出。修改Name屬性分別爲:mainMenuFile、menuItemFileNew、menuItemFileOpen、menuItemFileSave、menuItemFileSaveAs、menuItemFileExit。

(6)    爲Form1類增長string類型變量記錄當前編輯的文件名:string s_FileName="",若是爲空,表示還未記錄文件名,即編輯的文件尚未名字。當單擊菜單項保存,保存文件時,必須請用戶輸入文件名。

(7)    爲新建菜單項增長事件處理函數以下:

private void menuItemFileNew_Click(object sender, System.EventArgs e)

{   richTextBox1.Text="";//或richTextBox1.Clear();

s_FileName="";//新建文件沒有文件名。

}

(8)    爲打開文件菜單項增長事件處理函數以下:

private void menuItemFileOpen_Click(object sender, System.EventArgs e)

{   if(openFileDialog1.ShowDialog()==DialogResult.OK)

{   s_FileName=openFileDialog1.FileName;

richTextBox1.LoadFile(openFileDialog1.FileName,

RichTextBoxStreamType.PlainText);

}

}

(9)    爲另存爲菜單項增長事件處理函數以下:

private void menuItemFileSaveAs_Click(object sender, System.EventArgs e)

{   if(saveFileDialog1.ShowDialog()==DialogResult.OK)

    {   s_FileName=saveFileDialog1.FileName;

richTextBox1.SaveFile(saveFileDialog1.FileName,

RichTextBoxStreamType.PlainText);

}//注意存取文件類型應一致。

}

(10)爲保存文件菜單項增長事件處理處理函數以下:

private void menuItemSaveFile_Click(object sender, System.EventArgs e)

{   if(s_FileName.Length!=0)

richTextBox1.SaveFile(s_FileName,RichTextBoxStreamType.PlainText);

    else

menuItemFileSaveAs_Click(sender,e);//調用另存爲菜單項事件處理函數

}

(11)把SaveFileDialog控件放到窗體中,將自動建立控件對象,其生命週期等於窗體生命週期,將長期佔用存儲空間。實際上SaveFileDialog控件對象只在存文件菜單項事件處理函數中有用,其它時間無用。爲了節約存儲空間,能夠在存文件菜單項事件處理函數中創建SaveFileDialog控件對象,退出該事件處理函數時,自動釋放該對象。修改另存爲菜單項事件處理函數以下(首先刪除增長的控件SaveFileDialog):

private void menuItemFileSaveAs_Click(object sender, System.EventArgs e)

{   SaveFileDialog saveFileDialog1=new SaveFileDialog();

    saveFileDialog1.Filter="純文本文件(*.txt)|*.txt|全部文件(*.*)|*.*";

    saveFileDialog1.FilterIndex=1;

    if(saveFileDialog1.ShowDialog()==DialogResult.OK)

    {   s_FileName=saveFileDialog1.FileName;

  richTextBox1.SaveFile(saveFileDialog1.FileName,

RichTextBoxStreamType.PlainText);

    }//也能夠用此方法修改打開文件菜單項事件處理函數。

}

(12)爲退出菜單項增長事件處理函數以下:

private void menuItemExit_Click(object sender, System.EventArgs e)

{   Close();}

(13)編譯,運行,能夠存取文件。

4.4      修改字體屬性

爲修改字體屬性,首先打開字體對話框FontDialog,選擇指定字體。能夠按兩種方式修改字體,若是未選中字符,表示之後鍵入的字符將按選定字體輸入。若是選中字符,則僅修改選定字符的字體。修改字符顏色也根據一樣原則。

4.4.1 FontDialog控件屬性和方法

用戶能夠用FontDialog對話框選定指定字體,FontDialog控件和OpenDialog控件的屬性和方法基本相同,這裏只介紹不一樣部分。屬性Font:用戶用FontDialog對話框選定的字體。FontDialog對話框顯示效果如圖4.3.1。

4.4.2 修改字體屬性的實現方法

(14)放FontDialog控件到窗體,屬性Name=fontDialog1。增長頂級菜單項:格式,爲格式頂級菜單項的彈出菜單增長菜單項:字體,屬性Name分別爲mainMenuModel和menuItemModelFont,爲字體菜單項增長事件處理函數以下:

private void menuItemModelFont_Click(object sender, System.EventArgs e)

{   if(fontDialog1.ShowDialog()==DialogResult.OK)

richTextBox1.SelectionFont=fontDialog1.Font;

}

(15)編譯,運行,在選中字符和不選中字符兩種狀況下,用字體菜單項修改字體,看是否能實現寫字板中一樣的功能。

 

圖4.3.1字體對話框

4.5      實現About對話框

前邊介紹的SaveDialog、OpenDialog和FontDialog都是類庫中預先定義的對話框,本節介紹如何建立知足必定要求的自制對話框。對話框其實就是窗體,其基類和主窗體同樣,是System.Windows.Forms.Form。只是通常對話框只有關閉按鈕,沒有最大化和最小化按鈕,對話框的邊界是固定的,不能改變。設計本身的對話框是常常遇到的工做。

(16)選擇菜單項項目/添加Windows窗體,彈出對話框(見圖4.5),在模板(T)編輯框中選擇Windows窗體,在名稱欄(N)編輯框中輸入窗體文件名稱:formAbout.cs,單擊打開按鈕,能夠見到一個新窗體。從文件formAbout.cs能夠看到新建窗體類名也爲formAbout。

(17)修改formAbout屬性StartPosition=CenterParent,表示打開對話框時,對話框在父窗口的中間。修改屬性MaximizeBox=False,MinimizeBox=False,表示沒有最大化和最小化按鈕,既不能最大化和最小化。屬性FormBorderStyle=FixedDialog,窗口不能修改大小。屬性Text="關於記事本"。能夠在窗體中增長各類控件,例如,小圖標,Label控件等。本例僅增長Label控件表示版權信息,其屬性Text="版權全部"。一個按鈕,屬性Text="肯定",按鈕單擊事件處理函數以下:

private void button1_Click(object sender,System.EventArgs e)

{Close();}

(18)爲Form1窗體增長頂級菜單項:幫助,爲幫助頂級菜單項彈出菜單增長菜單項:關於…,屬性Name爲menuItemAbout。關於…菜單項單擊事件處理函數以下:

private void menuItemAbout_Click(object sender, System.EventArgs e)

{   formAbout AboutDialog=new formAbout();

AboutDialog.ShowDialog(this);

}//注意不能使用Show()函數

(19)編譯,運行,單擊關於…菜單項,將出現一個formAbout對話框(如右圖),而且不關閉此對話框,不能回到主窗口,通常把這樣的對話框叫作模式對話框。

 

 

圖4.5

4.6      實現文本編輯器查找替換功能

本節首先介紹模式對話框和非模式對話框的概念。並用非模式對話框實現文本編輯器程序的查找和替換功能。

4.6.1 模式對話框和非模式對話框

模式對話框和非模式對話框的區別是:打開模式對話框後,只有關閉該模式對話框,才能轉到其餘窗口,例如前邊講到的SaveDialog和OpenDialog都是典型的模式對話框。而打開非模式對話框後,沒必要退出該模式對話框,就能夠轉到其餘窗口,例如查找和替換對話框都是典型的非模式對話框。兩類對話框本質上都是窗體,是System.Windows.Forms.Form類的派生類,只是打開時使用的方法不同,打開模式對話框,使用方法ShowDialog(),而打開非模式對話框,使用方法Show()。文本編輯器程序中,查找和替換對話框通常是非模式對話框。

4.6.2 寫字板查找替換功能的實現

(20)創建查找替換對話框。對話框其實就是窗體,其基類是System.Windows.Forms.Form。選擇菜單項項目/添加Windows窗體,彈出對話框(如圖4.5),選擇Windows窗體,在名稱欄輸入窗體文件名稱:formFindReplace.cs,單擊打開按鈕,能夠見到一個新窗體。其屬性Name=formFindReplace。

(21) 修改formFindReplace窗體屬性StartPosition=CenterParent,表示打開對話框時,對話框在父窗口的中間。修改屬性MaximizeBox=False,MinimizeBox=False,表示沒有最大化和最小化按鈕,既不能最大化和最小化。FormBorderStyle=FixedDialog,窗口不能修改大小。屬性Text="查找和替換"。在窗體中增長兩個Label控件,屬性Text分別爲"查找字符串"和"替換字符串"。兩個TextBox控件,屬性Text=""。兩個按鈕,屬性Text分別爲"查找下一個"和"替換查到字符"。修改屬性TopMost=true,使該窗口打開時總在其它窗體的前邊。對話框界面如右圖。

(22)爲formFindReplace窗體增長變量:Form1 MainForm1;

(23)修改formFindReplace類構造函數以下(陰影部分是所作的修改):

public formAbout(Form1 form1)//增長參數

{

//Windows窗體設計器支持所必需的

    InitializeComponent();

//TODO:在InitializeComponent調用後添加任何構造函數代碼

    MainForm1=form1;//新增語句,這裏Form1是主窗體的屬性Name的值

}//有了Form1,能夠在formFindReplace窗體中調用主窗體的公有方法

(24)爲主窗體Form1增長方法以下,該方法將被formFindReplace窗體類調用。

public void FindRichTextBoxString(string FindString)

{}   //之後步驟將在此方法中增長查找語句

(25)formFindReplace窗體中查找下一個按鈕單擊事件處理函數以下:

private void buttonFind_Click(object sender, System.EventArgs e)

{   if(textBox1.Text.Length!=0)//若是查找字符串不爲空,調用主窗體查找方法

MainForm1.FindRichTextBoxString(textBox1.Text);//上步增長的方法

else

MessageBox.Show("查找字符串不能爲空","提示",MessageBoxButtons.OK);

}//MessageBox時對話框,使用方法見4.7.1節

(26)爲主窗體Form1增長方法以下,該方法將被formFindReplace窗體類調用。

public void ReplaceRichTextBoxString(string ReplaceString)

{}     //之後步驟將在此方法中增長替換語句

(27)爲替換查到字符按鈕單擊事件增長事件處理函數以下:

private void buttonReplace_Click(object sender, System.EventArgs e)

{ if(textBox2.Text.Length!=0)//若是查找字符串不爲空,調用主窗體替換方法

MainForm1.ReplaceRichTextBoxString(textBox1.Text,textBox2.Text);

else//方法MainForm1.ReplaceRichTextBoxString見(26)中定義

MessageBox.Show("替換字符串不能爲空","提示", MessageBoxButtons.OK);

}

(28)爲Form1窗體增長變量:int FindPostion=0,記錄查找位置。

(29)爲Form1窗體頂級菜單項編輯的彈出菜單增長菜單項:查找和替換。爲查找和替換菜單項單擊事件增長事件處理函數以下:

private void menuItemFindReplace_Click(object sender, System.EventArgs e)

{   FindPostion=0;

formAbout FindReplaceDialog=new formAbout(this);//注意this

    FindReplaceDialog.Show();//打開非模式對話框使用Show()方法

}

(30)爲在前邊定義的Form1主窗體的FindRichTextBoxString方法增長語句以下:

public void FindRichTextBoxString(string FindString)

{   if(FindPostion>=richTextBox1.Text.Length)//已查到文本底部

{   MessageBox.Show("已到文本底部,再次查找將從文本開始處查找",

"提示",MessageBoxButtons.OK);

FindPostion=0;

return;

}//下邊語句進行查找,返回找到的位置,返回-1,表示未找到,參數1是要找的字符串

//參數2是查找的開始位置,參數3是查找的一些選項,如大小寫是否匹配,查找方向等

FindPostion=richTextBox1.Find(FindString,

FindPostion,RichTextBoxFinds.MatchCase);

if(FindPostion==-1)//若是未找到

{   MessageBox.Show("已到文本底部,再次查找將從文本開始處查找",

"提示", MessageBoxButtons.OK);

FindPostion=0;//下次查找的開始位置

}

else//已找到

{   richTextBox1.Focus();//主窗體成爲注視窗口

FindPostion+=FindString.Length;

}//下次查找的開始位置在這次找到字符串以後

}

(31)爲在前邊定義的Form1主窗體的ReplaceRichTextBoxString方法增長語句以下:

public void ReplaceRichTextBoxString(string ReplaceString)

{   if(richTextBox1.SelectedText.Length!=0)//若是選取了字符串

    richTextBox1.SelectedText=ReplaceString;//替換被選的字符串

}

(32)編譯,運行,輸入若干字符,選中菜單項:編輯/查找和替換,打開對話框,注意該對話框能夠在不關閉的狀況下,轉到主窗體,而且老是在其它窗體的前邊,所以它是一個典型的非模式對話框。在對話框中輸入查找和替換的字符,單擊標題爲查找下一個的按鈕,能夠找到所選字符,並被選中,單擊標題爲替換所選字符按鈕,能夠看到查找到的字符被替換。運行效果如右圖:

4.7      提示用戶保存修改的文件

用戶在新建文本,打開其餘文本或者退出文本編輯器時,若是編輯內容發生了改變,應提示用戶是否保存已修改的文本內容。所以就須要在用戶關閉當前文件前,彈出提示對話框,提醒用戶是否保存當前文件。本節實現此功能。

4.7.1 對話框MessageBox

使用MessageBox能夠打開一個對話框,用法以下:

MessageBox.Show(this,"要保存當前更改嗎?","保存更改嗎?",

MessageBoxButtons.YesNoCancel,MessageBoxIcon.Question);

第一個參數是父窗口,第二個參數是提示信息,第三個參數是標題欄的內容,第四個參數是有那些按鈕,此例有YES,NO,CANCEL按鈕,還能夠使用AbortRetryIgnore(停止、重試和忽略按鈕)、OK(肯定按鈕)、OKCancel(肯定和取消按鈕)、RetryCance(重試和忽略按鈕)、YesNo(是和否按鈕)等選項。第五個參數是使用那一個圖標,此例是一個問號圖標,還能夠是Asterisk、Error、Exclamation、Hand、Stop、Warning等圖標,如爲None則無圖標。返回值是System.Windows.Forms.DialogResult變量,表明用戶按了那一個按鈕。若是返回值是System.Windows.Forms.DialogResult.Yes,則表示按了YES鍵,表示要存修改的文件。若是返回值是System.Windows.Forms.DialogResult.Cancel,按Cancel鍵,表示忽略這次操做。若是返回值是System.Windows.Forms.DialogResult.No,則表示按了No鍵,表示不存修改的文件。以上設計的對話框MessageBox以下圖:

 

4.7.2 提示用戶保存修改的文件的實現

(33)爲Form1類增長一個bool變量bSave=false做爲標記,用來跟蹤RichTextBox中文本內容改變的狀況。在程序開始運行、創建和打開一個新文件時,bSave=false,表示沒必要保存當前文本。RichTextBox控件有一個TextChanged事件,當文本發生改變的時候,這個事件就會被激活,在該事件處理函數中,使bSave=true。

(34)首先增長一個函數,其功能是判斷是否須要將已修改的文件存盤,之因此要增長這個函數是由於有三處要用到此函數。該函數返回true,表示繼續操做,該函數返回false,表示忽略這次操做,該函數定義以下:

public bool IfSaveOldFile()

{ bool ReturnValue=true;

if(bSave)

{ System.Windows.Forms.DialogResult dr;

dr=MessageBox.Show(this,"要保存當前更改嗎?","保存更改嗎?",

MessageBoxButtons.YesNoCancel,MessageBoxIcon.Question);

switch(dr)

{  case System.Windows.Forms.DialogResult.Yes://單擊了yes按鈕,保存修改

bSave=false;

if(s_FileName.Length!=0)

richTextBox1.SaveFile(s_FileName,RichTextBoxStreamType.PlainText);

else

{ SaveFileDialog saveFileDialog1=new SaveFileDialog();

saveFileDialog1.Filter="純文本文件(*.txt)|*.txt|全部文件(*.*)|*.*";

saveFileDialog1.FilterIndex=1;

if(saveFileDialog1.ShowDialog()==DialogResult.OK)

{ s_FileName=saveFileDialog1.FileName;

richTextBox1.SaveFile(saveFileDialog1.FileName,

RichTextBoxStreamType.PlainText);

}

}

ReturnValue=true;

break;

case System.Windows.Forms.DialogResult.No://單擊了no按鈕,不保存

bSave=false;

ReturnValue=true;

break;

case System.Windows.Forms.DialogResult.Cancel://單擊了Cancel按鈕

ReturnValue=false;

break;

}

}

return ReturnValue;

}

(35)在新建和打開菜單項的事件處理函數的頭部增長以下語句:

if(!IfSaveOldFile())//若是忽略,退出。

return;

(36)修改存文件菜單項單擊事件處理函數以下:

private void menuItemSaveFile_Click(object sender, System.EventArgs e)

{   if(s_FileName.Length!=0)

{   bSave=false;//陰影爲增長的語句

richTextBox1.SaveFile(s_FileName,RichTextBoxStreamType.PlainText);

}

else

menuItemSaveAs_Click(sender,e);

}

(37)修改另存爲菜單項單擊事件處理函數以下:

private void menuItemSaveAs_Click(object sender, System.EventArgs e)

{   SaveFileDialog saveFileDialog1=new SaveFileDialog();

saveFileDialog1.Filter="純文本文件(*.txt)|*.txt|全部文件(*.*)|*.*";

saveFileDialog1.FilterIndex=1;

if(saveFileDialog1.ShowDialog()==DialogResult.OK)

{   s_FileName=saveFileDialog1.FileName;

richTextBox1.SaveFile(saveFileDialog1.FileName,

RichTextBoxStreamType.PlainText);

bSave=false;//陰影爲增長的語句

}

}

(38)爲RichTextBox控件TextChanged事件增長事件處理函數以下:

private void richTextBox1_TextChanged(object sender, System.EventArgs e)

{   bSave=true;}

(39)爲Form1窗體Closing事件是在關閉窗口以前發送的事件,此時,窗體中的控件還存在,還能夠保存修改的內容,也能夠不退出。增長它的事件處理函數以下:

private void Form1_Closing(object sender,System.ComponentModel.CancelEventArgs e)

{   if(!IfSaveOldFile())

        e.Cancel=true;//不退出

}

(40)編譯,運行,鍵入若干字符,選中菜單項新建或打開,或退出,將看到提示信息,問是否保存修改的文件。有三種選擇:存文件,不存文件,忽略這次操做,試驗單擊不一樣按鈕的效果。

4.8      打印和打印預覽

打印和打印預覽是一個編輯器必須具備的功能,本節介紹實現打印和打印預覽的方法。通常要實現以下菜單項:打印、打印預覽、頁面設置。

4.8.1 PrintDocument類

PrintDocument組件是用於完成打印的類,其經常使用屬性、方法和事件以下:

l  屬性DocumentName:字符串類型,記錄打印文檔時顯示的文檔名(例如,在打印狀態對話框或打印機隊列中顯示)。

l  方法Print:開始文檔的打印。

l  事件BeginPrint:在調用Print方法後,在打印文檔的第一頁以前發生。

l  事件PrintPage:須要打印新的一頁時發生。

l  事件EndPrint:在文檔的最後一頁打印後發生。

若要打印,首先建立PrintDocument組件的對象。而後使用頁面設置對話框PageSetupDialog設置頁面打印方式,這些設置做爲要打印的全部頁的默認設置。使用打印對話框PrintDialog設置對文檔進行打印的打印機的參數。在打開兩個對話框前,首先設置對話框的屬性Document爲指定的PrintDocument類對象,修改的設置將保存到PrintDocument組件對象中。第三步是調用PrintDocument.Print方法來實際打印文檔。當調用該方法後,引起下列事件:BeginPrint、PrintPage、EndPrint。其中每打印一頁都引起PrintPage事件,打印多頁,要屢次引起PrintPage事件。完成一次打印,能夠引起一個或多個PrintPage事件。

程序員應爲這3個事件編寫事件處理函數。BeginPrint事件處理函數進行打印初始化,通常設置在打印時全部頁的相同屬性或共用的資源,例如全部頁共同使用的字體、創建要打印的文件流等。PrintPage事件處理函數負責打印一頁數據。EndPrint事件處理函數進行打印善後工做。這些處理函數的第2個參數System.Drawing.Printing.PrintEventArgs e提供了一些附加信息,主要有:

l e.Cancel:布爾變量,設置爲true,將取消此次打印做業。

l e.Graphics:所使用的打印機的設備環境,參見第五章。

l e.HasMorePages:布爾變量。PrintPage事件處理函數打印一頁後,仍有數據未打印,退出事件處理函數前設置HasMorePages=true,退出PrintPage事件處理函數後,將再次引起PrintPage事件,打印下一頁。

l e.MarginBounds:打印區域的大小,是Rectangle結構,元素包括左上角座標:Left和Top,寬和高:Width和Height。單位爲1/100英寸。

l e.MarginBounds:打印紙的大小,是Rectangle結構。單位爲1/100英寸。

l e.PageSettings:PageSettings類對象,包含用對話框PageSetupDialog設置的頁面打印方式的所有信息。可用幫助查看PageSettings類的屬性。

下邊爲這3個事件編寫事件處理函數,具體步驟以下:

(41)在最後一個using語句以後增長語句:

using System.IO;

using System.Drawing.Printing;

(42)本例打印或預覽RichTextBox中的內容,增長變量:StringReader streamToPrint=null。若是打印或預覽文件,改成:StreamReader streamToPrint,流的概念參見第六章。增長打印使用的字體的變量:Font printFont。

(43)放PrintDocument控件到窗體,屬性name爲printDocument1。

(44)爲printDocument1增長BeginPrint事件處理函數以下:

private void printDocument1_BeginPrint(object sender,

System.Drawing.Printing.PrintEventArgs e)

{   printFont=richTextBox1.Font;//打印使用的字體

streamToPrint=new StringReader(richTextBox1.Text);//打印richTextBox1.Text

}//如預覽文件改成:streamToPrint=new StreamReader("文件的路徑及文件名");

(45)printDocument1的PrintPage事件處理函數以下。streamToPrint.ReadLine()讀入一段數據,可能打印多行。本事件處理函數將此段數據打印在一行上,所以方法必須改進。

private void printDocument1_PrintPage(object sender,

System.Drawing.Printing.PrintPageEventArgs e)

{   float linesPerPage=0;//記錄每頁最大行數

    float yPos=0;//記錄將要打印的一行數據在垂直方向的位置

    int count=0;//記錄每頁已打印行數

    float leftMargin=e.MarginBounds.Left;//左邊距

    float topMargin=e.MarginBounds.Top;//頂邊距

    string line=null;//從RichTextBox中讀取一段字符將存到line中

    //每頁最大行數=一頁紙打印區域的高度/一行字符的高度

    linesPerPage=e.MarginBounds.Height/printFont.GetHeight(e.Graphics);

    //若是當前頁已打印行數小於每頁最大行數並且讀出數據不爲null,繼續打印

    while(count<linesPerPage&&((line=streamToPrint.ReadLine())!=null))

    {   //yPos爲要打印的當前行在垂直方向上的位置

yPos=topMargin+(count*printFont.GetHeight(e.Graphics));

        e.Graphics.DrawString(line,printFont,Brushes.Black,

leftMargin,yPos,new StringFormat());//打印,參見第五章

        count++;//已打印行數加1

    }

    if(line!=null)//是否須要打印下一頁

        e.HasMorePages=true;//須要打印下一頁

    else

        e.HasMorePages=false;//不須要打印下一頁

}

(46)爲printDocument1增長EndPrint事件處理函數以下:

private void printDocument1_EndPrint (object sender,

System.Drawing.Printing.PrintEventArgs e)

{   if(streamToPrint!=null)

        streamToPrint.Close();//釋放不用的資源

}

4.8.2 打印設置對話框控件PageSetupDialog

Windows窗體的PageSetupDialog控件是一個頁面設置對話框,用於在Windows應用程序中設置打印頁面的詳細信息,對話框的外觀如圖4.8.2。

 

圖4.8.2

用戶使用此對話框可以設置紙張大小(類型)、紙張來源、縱向與橫向打印、上下左右的頁邊距等。在打開對話框前,首先設置其屬性Document爲指定的PrintDocument類對象,用來把頁面設置保存到PrintDocument類對象中。爲文本編輯器增長頁面設置功能的具體步驟以下:

(47)爲文件頂級菜單項的彈出菜單增長菜單項:頁面設置。

(48)放PageSetupDialog控件到窗體,屬性name爲pageSetupDialog1。

(49)爲頁面設置菜單項增長單擊事件處理函數以下:

private void menuItem5_Click(object sender,System.EventArgs e)

{   pageSetupDialog1.Document=printDocument1;

pageSetupDialog1.ShowDialog();

}

(50)打開對話框pageSetupDialog1後,若是單擊了肯定按鈕,PageSetupDialog對話框中所作的的頁面設置被保存到PrintDocument類對象printDocument1中,若是單擊了取消按鈕,不保存這些修改,維持原來的值。當調用PrintDocument.Print方法來實際打印文檔時,引起PrintPage事件,該事件處理函數的第二個參數e提供了這些設置信息。

4.8.3 打印預覽

PrintPreviewDialog類能夠在屏幕上顯示PrintDocument的打印效果,既打印預覽。實現打印預覽的具體步驟以下:

(51)爲文件頂級菜單項的彈出菜單增長菜單項:打印預覽。

(52)放PrintPreviewDialog控件到窗體,屬性name爲printPreviewDialog1。

(53)爲打印預覽菜單項增長單擊事件處理函數以下:

private void menuItemPrintView_Click(object sender,System.EventArgs e)

{   printPreviewDialog1.Document=printDocument1;

printPreviewDialog1.ShowDialog();

}

(54)編譯,運行,輸入若干字符,試驗一下預覽的效果,預覽的效果如圖4.8.3。

 

圖4.8.3

4.8.4 用打印對話框PrintDialog實現打印

PrintDialog組件是類庫中預先定義的對話框,用來設置對文檔進行打印的打印機的參數,包括打印機名稱、要打印的頁(所有打印或指定頁的範圍)、打印的份數以及是否打印到文件等。在打開對話框前,首先設置其屬性Document爲指定的PrintDocument類對象,打開PrintDialog對話框後,修改的設置將保存到PrintDocument類的對象中。PrintDialog對話框的外觀如圖4.8.4。

 

圖4.8.4

增長打印功能的具體步驟以下:

(55)放PrintDialog控件到窗體屬性Name=printDialog1。

(56)爲文件頂級菜單項的彈出菜單增長菜單項:打印。

(57)爲打印菜單項增長單擊事件處理函數以下:(不能打印?)

private void menuItemPrint_Click(object sender, System.EventArgs e)

{   printDialog1.Document=printDocument1;

    if(printDialog1.ShowDialog(this)==DialogResult.OK)

        printDocument1.Print();

}

(58)編譯,運行,輸入若干字符,試驗一下打印效果。

4.9      編寫多文檔界面應用程序

本節首先介紹如何創建相似Microsoft Word的文本編輯器,而後介紹如何創建相似Visualstudio.Net的編輯器那樣的文本編輯器,有多個選項卡頁。

4.9.1創建相似Microsoft Word的編輯器

創建一個相似Microsoft Word的編輯器,能夠有多頁,每頁處理一個文檔。多文檔界面(MDI)應用程序具備一個主窗體(父窗體),主窗體在其工做區內包含一組窗體(子窗體)。每一個子窗體都是一個限制爲只能在該父窗體內出現的窗體。這些子窗體一般共享父窗體界面的菜單欄、工具欄以及其餘部分。建立多文當編輯器的具體步驟以下:

(1)  新建項目。修改主窗體屬性IsMdiContainer=true,表示主窗體是一個子窗體容器。

(2)  放主菜單控件Mainmenu到主窗體。增長頂級菜單項:文件,屬性Name=menuItemFile。爲文件菜單增長菜單項:新建、打開、另存爲、關閉當前窗口、退出,屬性Name分別爲menuItemNew、menuItemOpen、menuItemSaveAs、menuItemCloseChild、menuItemExit。增長頂級菜單項:窗口,屬性Name=menuItemWindow,屬性MdiList=true,該屬性將在窗口菜單下增長子窗口列表。爲窗口菜單增長菜單項:水平平鋪、層疊、垂直平鋪,屬性Name分別爲menuItemTileH、menuItemCascade、menuItemTileV。

(3)  建立子窗體,選擇菜單項:項目/添加Windows窗體,彈出對話框(見圖4.5),選擇Windows窗體,在名稱欄輸入窗體文件名稱:FormChild.cs,單擊打開按鈕,能夠見到一個新窗體。定義新窗體的類名也爲FormChild。此窗體做爲主窗體的子窗體。

(4)  放RichTextBox1控件到子窗體。修改屬性Dock=Fill,Text="",Modifiers=public,使RichTextBox1爲公有成員,在主窗體能夠訪問RichTextBox1。

(5)  爲主窗體菜單項新文件增長單擊事件處理函數以下:

private void menuItemNew_Click(object sender,System.EventArgs e)

{   FormChild formChild=new FormChild();

    formChild.MdiParent=this;

    formChild.Show();

}

(6)  把OpenFileDialog控件放到窗體中。單擊打開文件菜單項事件處理函數以下:

private void menuItemOpen_Click(object sender, System.EventArgs e)

{   if(openFileDialog1.ShowDialog(this)==DialogResult.OK)

    {   FormChild ChildForm=new FormChild();

        ChildForm.MdiParent=this;

        ChildForm.richTextBox1.LoadFile(openFileDialog1.FileName,

RichTextBoxStreamType.PlainText);

        ChildForm.Show();

    }

}

(7)  把SaveFileDialog控件放到子窗體中。另存爲菜單項事件處理函數以下:

private void menuItemChildSaveAs_Click(object sender, System.EventArgs e)

{   if(saveFileDialog1.ShowDialog(this)==DialogResult.OK)

    {   FormChild ChildForm=(FormChild)this.ActiveMdiChild;

        ChildForm.richTextBox1.SaveFile(saveFileDialog1.FileName,

RichTextBoxStreamType.PlainText);

    }

}

(8)  爲主窗體菜單項關閉當前窗口增長單擊事件函數以下:

private void menuItemCloseChild_Click(object sender, System.EventArgs e)

{   this.ActiveMdiChild.Close();}

(9)  爲主窗體菜單項退出增長單擊事件函數以下:

private void menuItemExit_Click(object sender, System.EventArgs e)

{   Close();}

(10)爲主窗體菜單項水平平鋪增長單擊事件函數以下:

private void menuItemTileH_Click(object sender, System.EventArgs e)

{   this.LayoutMdi(MdiLayout.TileHorizontal);}

(11)爲主窗體菜單項層疊增長單擊事件函數以下:

private void menuItemCascade_Click_1(object sender, System.EventArgs e)

{   this.LayoutMdi(MdiLayout.Cascade);}

(12)爲主窗體菜單項垂直平鋪增長單擊事件函數以下:

private void menuItemTileV_Click(object sender, System.EventArgs e)

{   this.LayoutMdi(MdiLayout. TileVertical);}

(13)運行,運行效果以下,子窗體爲層疊排列。

 

4.9.2主窗口和子窗口的菜單的融合

在許多多文檔編輯器應用程序中,在沒有子窗體打開時,菜單比較簡單,而有子窗體打開後,菜單增多。實現這種功能通常是在主窗體中建立一個簡單菜單,子窗體沒打開時,只顯示這個簡單菜單。在子窗體中也建立一個菜單,包含主窗體菜單中沒有的菜單項。打開子窗體後,子窗體的菜單和主窗體菜單合併成爲一個菜單,這個功能叫作主窗口和子窗口的菜單的融合。建立具備這種功能的多文檔編輯器應用程序能夠按下列步驟:

(1)    新建項目。修改主窗口屬性IsMdiContainer爲true。

(2)    把Mainmenu控件放到主窗體中。增長頂級菜單項:文件。其屬性MergeType=MergeItems,表示打開子窗體後,主窗體和子窗體中屬性MergeOrder相同的頂級菜單項的彈出菜單中的菜單項合併爲一個彈出菜單。屬性MergeOrder=0。子窗體的頂級菜單項文件的屬性MergeType也應爲MergeItems,MergeOrder屬性也應爲0,這樣打開子窗口後,才能合併爲一個彈出菜單。屬性Name=menuItemFile。爲文件菜單增長菜單項:新建、打開、退出,屬性Name分別爲menuItemNew、menuItemOpen、menuItemExit,屬性MergeType都爲Add,屬性MergeOrder依次爲一、二、6,目的是打開子窗口後,在新建和打開菜單項後加入子窗口菜單欄中的文件菜單的另存爲菜單項。增長菜單:幫助,其屬性MergeType=Add,屬性MergeOrder=7,屬性Name=menuItemHelp。爲幫助菜單增長菜單項:關於…,屬性Name=menuItemAbout。其他菜單在子窗口中實現。注意屬性MergeOrder分別爲0、7,打開子窗口後,子窗口中的菜單將按順序插入到主窗口的菜單中,例如,子窗口有菜單:編輯,其屬性MergeOrder=3,合併後,菜單排列順序爲:文件、編輯、幫助。

(3)    建立子窗體,選擇菜單項:項目/添加Windows窗體,彈出對話框,選擇Windows窗體,在名稱欄輸入窗體文件名稱:formChild.cs,單擊打開按鈕,能夠見到一個新窗體。定義新窗體的類名也爲formChild。

(4)    爲formChild窗體增長變量:Form1 MainForm1;

(5)    修改formChild類構造函數以下(陰影部分是所作的修改):

public formChild(Form1 form1)//增長參數

{

//Windows窗體設計器支持所必需的

InitializeComponent();

//TODO:在InitializeComponent調用後添加任何構造函數代碼

MainForm1=form1;//新增語句,這裏Form1是主窗體的屬性Name的值

}//有了Form1,能夠在formChild窗體中調用主窗體的公有方法

(6)    把Mainmenu控件放到子窗體中。增長頂級菜單項:文件,其屬性MergeType=MergeItems,屬性MergeOrder=0。爲文件頂級菜單項彈出菜單增長菜單項:另存爲…,屬性MergeType=Add,屬性MergeOrder=3,菜單合併後,另存爲…菜單項將出如今主窗口文件菜單的新建和打開菜單項以後。增長菜單項:關閉當前文件,屬性MergeType=Add,屬性MergeOrder=4。

(7)    增長頂級菜單項:編輯,其屬性MergeType=Add,屬性MergeOrder=3。注意屬性MergeOrder=3,菜單合併後,編輯菜單將出現出現菜單文件以後。爲編輯頂級菜單項彈出菜單增長菜單項:拷貝、剪貼、粘貼。

(8)    增長頂級菜單項:窗口,其屬性MergeType=Add,屬性MergeOrder=6,屬性Name=menuItemWindow,屬性MdiList=true,該屬性將在窗口菜單下增長子窗口列表。爲窗口菜單增長菜單項:層疊,屬性Name爲menuItemCascade。

(9)    放RichTextBox1控件到子窗體。修改屬性Dock=Fill,Text=」」,屬性 Modifiers=public,使RichTextBox1爲公有成員,在主窗體能夠訪問RichTextBox1。

(10)爲主窗體菜單項新文件增長單擊事件函數以下:

private void menuItemNew_Click(object sender, System.EventArgs e)

{   formChild ChildForm=new formChild(this);

ChildForm.MdiParent=this;

ChildForm.Show();

}

(11)把OpenFileDialog控件放到主窗體中。單擊打開文件菜單項事件處理函數以下:

private void menuItemOpen_Click(object sender, System.EventArgs e)

{   if(openFileDialog1.ShowDialog(this)==DialogResult.OK)

{   formChild ChildForm=new formChild(this);

ChildForm.MdiParent=this;

ChildForm.richTextBox1.LoadFile(openFileDialog1.FileName);

ChildForm.Show();

}

}

(12)爲主窗體菜單項退出增長單擊事件處理函數以下:

private void menuItemExit_Click(object sender, System.EventArgs e)

{   Close();}

(13)爲子窗體菜單項層疊增長單擊事件處理函數以下:

private void menuItemCascade_Click_1(object sender, System.EventArgs e)

{   MainForm1.LayoutMdi(MdiLayout.Cascade);}

(14)把SaveFileDialog控件放到子窗體中。爲子窗體菜單項另存爲增長單擊事件函數以下:

private void menuItemChildSaveAs_Click(object sender, System.EventArgs e)

{   if(saveFileDialog1.ShowDialog(this)==DialogResult.OK)

{   richTextBox1.SaveFile(saveFileDialog1.FileName,

RichTextBoxStreamType.PlainText);

}

}

(15)爲子窗體菜單項關閉當前窗口增長單擊事件函數以下:

private void menuItemCloseChild_Click(object sender, System.EventArgs e)

{   Close();}

(16)爲子窗體菜單項拷貝、剪貼和粘貼增長單擊事件函數以下:

語句分別爲:richTextBox1.Cut();richTextBox1.Copy();richTextBox1.Paste();

(17)運行效果以下圖。

 

 

4.9.3創建相似Visualstudio.Net的編輯器

Visualstudio.Net的編輯器有多個選項卡頁,能夠編輯多個文件。創建選項卡頁數固定,每選項卡頁顯示一行文本,相似Visualstudio.Net的編輯器的文本編輯器的具體實現步驟以下:

(1)  新建項目。放TabControl控件到子窗體。修改屬性Dock=Fill。

(2)  單擊TabControl屬性TabPages後按鈕,打開TabPage集合編輯器,單擊添加按鈕,增長1個選項卡頁。修改屬性Text分別爲:第一頁,第二頁。如圖4.9.3。

(3)      選中第一頁,能夠在頁中放置控件,例如放置Label控件,屬性Text=」這是第一個選項卡頁」。一樣在第二頁中也放置Label控件,屬性Text=」這是第二個選項卡頁」。若是放置RichTextBox控件,能夠作成多文檔編輯器。

(4)      運行,能夠看到多頁,單擊每頁的標題,能夠轉換選項卡頁。運行效果如右圖:

 

圖4.9.3

如能夠有多個選項卡頁,每選項卡頁處理一個文檔,並能動態增長新選項卡頁,關閉當前選項卡頁。實現步驟以下:

(1)      新建項目。放TabControl控件到子窗體。修改屬性Dock=Fill。

(2)      把Mainmenu控件放到主窗體中。增長頂級菜單項:文件,爲其彈出菜單增長4個菜單項:新頁、關閉當前頁、打開、另存爲。屬性Name分別爲:menuItemFile、menuItemFileNew、menuItemFileClose、menuItemFileOpen、menuItemFileSaveAs。

(3)      增長一個新方法MakeNewTbpage()以下:

private object  MakeNewTbpage()

{   //增長選項卡頁TabPage

TabPage tabPage1=new TabPage();

tabControl1.Controls.Add(tabPage1);//將tabPage1放到tabControl1中

tabPage1.Location=new Point(4, 21);

tabPage1.Size=new Size(284, 248);

tabPage1.Text="第"+tabPage1.TabIndex.ToString()+"頁";

//增長RichTextBox

RichTextBox richTextBox1=new RichTextBox();

richTextBox1.Dock=DockStyle.Fill;

richTextBox1.Size=new Size(284, 248);

richTextBox1.Text="";

tabPage1.Controls.Add(richTextBox1);//將richTextBox1放到tabPage1中

return (object)richTextBox1;

}

(4)      爲菜單項新頁增長事件處理函數以下:

private void menuItemFileNew_Click(object sender, System.EventArgs e)

{ MakeNewTbpage();}

(5)      爲菜單項關閉當前頁增長事件處理函數以下:

private void menuItemFileClose_Click(object sender, System.EventArgs e)

{   TabPage tabPage1=tabControl1.SelectedTab;//獲得當前選定的選項卡頁

tabControl1.Controls.Remove(tabPage1);//從tabControl1中移走該頁

//獲得當前選定的選項卡頁中第0個控件,即RichTextBox控件

RichTextBox richTextBox1=(RichTextBox)tabPage1.Controls[0];

if(richTextBox1!=null)

richTextBox1.Dispose();//刪除當前選定選項卡頁中RichTextBox控件對象

if(tabPage1!=null)

tabPage1.Dispose();//刪除當前選定的選項卡頁

}

(6)      把OpenFileDialog控件放到子窗體中。爲菜單項打開增長事件處理函數以下:

private void menuItemFileOpen_Click(object sender, System.EventArgs e)

{   if(openFileDialog1.ShowDialog()==DialogResult.OK)

{   RichTextBox richTextBox1=(RichTextBox)MakeNewTbpage();

richTextBox1.LoadFile(openFileDialog1.FileName,

RichTextBoxStreamType.PlainText);

}

}

(7)      把SaveFileDialog控件放到子窗體中。爲菜單項另存爲增長事件處理函數以下:

private void menuItemFileSaveAs_Click(object sender, System.EventArgs e)

{   if(saveFileDialog1.ShowDialog()==DialogResult.OK)

{   TabPage tabPage1=tabControl1.SelectedTab;

RichTextBox richTextBox1=(RichTextBox)tabPage1.Controls[0];

richTextBox1.SaveFile(saveFileDialog1.FileName,

RichTextBoxStreamType.PlainText);

}

}

(8)      編譯,運行,創建新文件,關閉當前選項卡頁,打開新文件,存文件,開是否正常。

習題

(1)  RichTextBox控件Lines屬性記錄控件中全部文本的字符串數組,每兩個回車之間字符串是數組的一個元素。定義一個數組,將屬性Lines 中的內容存到這個數組中。(提示:string[] s=new string [richTextBox1.Lines.Length];s= richTextBox1.Lines)

(2)  爲設計的單文檔寫字板增長工具欄,實現建新文件,打開文件,存文件等功能。

(3)  在工具欄中,增長2個下拉列表文本框,一個選擇使用的字體,一個選擇字體的字號。

(4)  在工具欄中,增長3個按鈕,分別設定字符爲黑體,斜體,增長下劃線。

(5)  在工具欄中,增長1個按鈕,用ColorDialog對話框選擇字體的顏色。

(6)  如何實現全選菜單項。

(7)  RichTextBox控件的屬性Modified能夠指示用戶是否修改文本框控件的內容。請修改4.7節程序,使用屬性Modified判斷用戶是否修改了RichTextBox控件中文本內容。

(8)  在查找對話框中,增長兩個多選框,選擇是否容許反向查和區分大小寫,並實現反向查找和不區分大小寫查找。

(9)  在實現打開文件和另存爲功能時,使用屬性InitialDirectory和屬性DefaultExt。

(10)  RichTextBox控件的屬性SelectionAlignment表示段落的對齊方式,在工具欄中增長三個按鈕,分別實現段落的左對齊(HorizontalAlignment.Left)、右對齊(HorizontalAlignment.Right)、中間對齊(HorizontalAlignment.Center)。(提示:3個按鈕應是互斥的,用分隔符表示3個按鈕是一組。工具條按鈕屬性Style設置爲ToolBarButtonStyle.Separator則按鈕將顯示爲一個按鈕分隔符,而不是按鈕。)

(11)  RichTextBox控件的屬性SelectionCharOffset能夠設定選中的字符爲上下標,能夠爲一個整數,爲0表示正常字符,負數表示下標,正數表示上標。請在工具條中增長三個按鈕,分別實現上下標功能。

(12)  請實現完整的單文檔編輯器,具備前邊介紹的單文檔編輯器的功能。

(13)  請實現完整的多文檔編輯器,具備前邊介紹的單文檔編輯器的功能。

(14)  請實現完整的選項卡式多文檔文本編輯器,具備前邊介紹的單文檔編輯器的功能。

 

 

第五章       圖形圖像編程

本章的目的是介紹圖形圖像編程的方法,但願在學了本章之後,能編制象Windows畫圖那樣的程序。本章的重點是學習Graphics類中對象(象筆、刷子等)及各類方法的使用,以及Bitmap類的應用。

5.1      圖形設備環境接口(GDI)

爲了在Windows窗口輸出數據(字符或圖形),Windows操做系統提供了一些工具和函數,例如提供筆用來定義圖形外輪廓線的顏色及粗細,提供刷子定義添充封閉圖形內部的顏色和格式,提供不一樣輸出字體,提供函數用來輸出字符或繪製圖形等等。全部這些工具和函數被放在圖形設備接口函數庫中(GDI32.DLL),它負責CRT顯示及打印。根據設備不一樣,能夠構造不一樣的設備環境(GDI),使輸出圖形或字符與設備無關,既不管是在CRT顯示仍是在打印機上打印同一個圖形或字符,都用相同的函數。GDI所扮演的角色以下圖所示:

 CRT顯示

打印機打印

  CRT驅動程序

打印機驅動程序

    GDI

  設備環境

    用戶

  應用程序

用戶應用程序根據是在CRT顯示仍是在打印機打印,首先選擇CRT顯示設備環境或打印設備環境,而後調用GDI中的同名函數實如今CRT顯示或在打印機上打印。而GDI設備環境根據選擇的不一樣設備,調用不一樣的設備驅動程序,在CRT上顯示或在打印機上打印。而這些驅動程序都是各個設備製造廠商提供的。這樣作的最大好處是應用程序和設備無關,應用程序沒必要爲不一樣的設備編制不一樣的程序。爲使用不一樣的設備,不管是不一樣的顯卡,仍是不一樣的打印機,只要安裝該設備的驅動程序,應用程序就能夠使用該設備,微軟的Word程序能夠使用不一樣的打印機就是使用了這個原理。

.NET系統的基礎類庫(.Net FrameWork)對Windows操做系統的圖形設備接口函數庫(GDI32.DLL)進行了擴充,並用類進行了封裝,通常叫作GDI+。使用GDI+繪圖更加方便快捷。爲了使用GDI+圖形功能,必須引入如下命名空間:System.Drawing,System.Drawing.Priniting,System.Drawing.Imaging,System.Drawing.Drawing2D,System.Drawing.Design,System.Drawing.Text。

5.2      Graphics類

System.Drawing.Graphics類對GDI+進行了封裝,Graphics類提供一些方法完成各類圖形的繪製。Graphics類對象與特定的設備關聯,爲了在不一樣的設備上用徹底相同的代碼完成一樣的圖形,應根據不一樣的設備創建不一樣的Graphics類對象。Graphics類是密封類,不能有派生類。

5.2.1使用Graphics類繪圖的基本步驟

GDI+大部分功能被封裝在Graphics類中,Graphics類提供了一些工具和函數,例如提供筆用來定義圖形外輪廓線的顏色及粗細,提供刷子定義添充封閉圖形內部的顏色和格式,提供不一樣輸出字體,提供函數用來輸出字符或繪製圖形等等。爲了在窗體中或其它控件中使用這些工具和函數繪圖,必須首先獲得這些窗體或控件的使用的Graphics類對象。下面的例子,在窗體中增長了一個按鈕,單擊按鈕將在窗體中畫一個邊界爲紅色,內部填充藍色的圓。該程序段說明了使用Graphics類繪圖的基本步驟。按鈕的單擊事件處理函數以下:

private void button1_Click(object sender,System.EventArgs e)

{   Graphics g=this.CreateGraphics();//獲得窗體使用的Graphics類對象

Pen pen1=new Pen(Color.Red);//建立紅色筆對象

SolidBrush brush1=new SolidBrush(Color.Blue);//建立藍色刷子對象

g.DrawEllipse(pen1,10,10,100,100);//用紅色筆畫圓的邊界

g.FillEllipse(brush1,10,10,100,100);//用藍色刷子填充圓的內部

}

運行後,單擊按鈕,出現邊界爲紅色,內部填充爲藍色的圓。

5.2.2窗體的Paint事件

運行上例,單擊按鈕,出現邊界爲紅色,內部填充藍色的圓。最小化後,再最大化,圖形不見了。這是由於用戶Form窗體用戶區內容可能被破壞,例如窗體最小化後,再最大化,菜單被打開再關閉,打開對話框再關閉等,用戶區內容被覆蓋。Windows並不保存被破壞的用戶區內容,而是由應用程序本身恢復被破壞的用戶區的內容。當應用程序窗口用戶區內容被破壞後需恢復時,Windows操做系統嚮應用程序發送Paint事件,應用程序應把在窗口用戶區輸出數據的語句放在Paint事件處理函數中,Windows發Paint事件時,能調用這些在窗口用戶區輸出數據的語句恢復被破壞的內容。Form窗體不能自動響應Paint事件,程序員必須生成Paint事件處理函數。修改上例,增長Form窗體的Paint事件處理函數以下:

private void Form1_Paint(object sender,System.Windows.Forms.PaintEventArgs e)

{   Graphics g=e.Graphics;//獲得窗體的使用的Graphics類對象

Pen pen1=new Pen(Color.Red);

SolidBrush brush1=new SolidBrush(Color.Blue);

g.DrawEllipse(pen1,10,10,100,100);

g.FillEllipse(brush1,10,10,100,100);

}

運行後,出現邊界爲紅色,內部填充藍色的圓。最小化後,再最大化,圖形不消失。

5.3      GDI+中三種座標系統:

GDI+定義了三種座標系統,並提供了三種座標轉換的方法Graphics.TransformPoints()。

l 全局座標系統。

l 頁面(Page)座標系統:左上角爲原點,橫向x軸向右爲正方向,縱向y軸向下爲正方向。單位爲像素。這是默認的座標系統。

l 設備座標系統:能夠指定特定測量單位的頁面(Page)座標系統。若是單位爲像素,和頁面(Page)座標系統相同。

5.4      GDI+中經常使用的結構

本節介紹GDI+中經常使用的結構,包括:Point、PointF、Size、SizeF、Rectangle、RectangleF、Color等。它們都在名字空間System.Drawing中定義的。

5.4.1   結構Point和PointF

點結構有兩個成員:X,Y,表示點的x軸和y軸的座標。其經常使用構造函數以下:

Point p1=new Point(int X,int Y);//X,Y爲整數

PointF p2=new PointF(float X,floa Y);//X,Y爲浮點數

5.4.2   結構Size和SizeF

Size和SizeF用來表示尺寸大小,有兩個成員:Width和Height。經常使用構造函數以下:

public Size(int width,int height);

public SizeF(float width,float height);

5.4.3   結構Rectangle和RectangleF

結構Rectangle和RectangleF用來表示一個矩形,經常使用屬性以下:

l Top:Rectangle結構左上角的y座標。

l Left:Rectangle結構左上角的x座標。

l Bottom:Rectangle結構右下角的y座標。

l Right:Rectangle結構右下角的x座標。

l Width:獲取或設置此Rectangle結構的寬度。

l Height:獲取或設置此Rectangle結構的高度。

l Size:獲取或設置此Rectangle的大小。

l X:獲取或設置此Rectangle結構左上角的x座標。

l Y:獲取或設置此Rectangle結構左上角的y座標。

其經常使用構造函數爲:

//參數爲矩形左上角座標的點結構location和表明矩形寬和高的Size結構size

Rectangle(Point location,Size size);//參數也可爲PointF和SizeF

//參數爲矩形左上角x和y座標,寬,高

Rectangle(int X,int Y,int width,int height);//X和Y也可爲float

5.4.4   結構Color

Color結構表示顏色,結構中包含一個無符號32位數表明顏色。任何一種顏色能夠用透明度(al),藍色(bb),綠色(gg),紅色(rr)合成,格式爲0xalrrbbgg,其中al,bb,gg,rr爲0到255間的二進制數。經常使用方法以下:

l public static Color FromArgb(int alpha,int rr,int gg,int bb);

從四個份量(透明度、紅色、綠色和藍色)值建立Color結構。每一個份量的值僅限於8位(小於256)。alpha值表示透明度,=0爲徹底透明,=255爲徹底不透明

l public static Color FromArgb(int rr,int gg,int bb);

從指定的8位顏色值(紅色、綠色和藍色)建立Color結構。透明度值默認爲255(徹底不透明)。每一個份量的值僅限於8位(小於256)。紅色爲(255,0,0),綠色爲(0,255,0),藍色爲(0,0,255)。

l public static Color FromArgb(int alpha,Color color);

從指定的Color結構建立新Color結構,使用新指定的透明度值alpha。alpha值僅限於8位。透明度及顏色的使用方法的例子以下:

private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)

{   Graphics g=e.Graphics;

SolidBrush RedBrush=new SolidBrush(Color.FromArgb(128,255,0,0));//半透明

SolidBrush GreenBrush=new SolidBrush(Color.FromArgb(128,0,255,0));

SolidBrush BlueBrush=new SolidBrush(Color.FromArgb(128,0,0,255));

g.FillRectangle(RedBrush,0,0,80,80);

g.FillRectangle(GreenBrush,40,0,80,80);

g.FillRectangle(BlueBrush,20,20,80,80);

}

效果如右圖,能夠將透明度alpha值設爲255,再運行一次,看看有何不一樣。C#中還預約義了一些顏色常數,例如黑色爲Color.Black,紅色爲Color.Red等等,可用幫助察看。

5.5      畫筆

Pen類對象指定繪製的圖形外輪廓線寬度和顏色。Pen類有4個構造函數,分別是:

l public Pen(Color color);//創建顏色爲color的筆,寬度默認爲1

l public Pen(Color color,float width);//創建顏色爲color的筆,寬度爲width

l public Pen(Brush brush);//使用刷子爲筆

l public Pen(Brush,float width);//使用刷子爲筆,寬度爲width

Pen類經常使用的屬性:Color爲筆的顏色,Width爲筆的寬度,DashStyle爲筆的樣式,EndCap和StartCap爲線段終點和起點的外觀。下例顯示各類筆的DashStyle、EndCap和StartCap不一樣選項的樣式(見下圖)。主窗體Paint事件處理函數以下:

private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)

{   Graphics g=e.Graphics;

Pen pen1=new Pen(Color.Red,6);//默認爲實線筆

g.DrawLine(pen1,10,10,100,10);//畫實線,圖中左邊第1條線

pen1.DashStyle=System.Drawing.Drawing2D.DashStyle.Dash;//虛線筆

g.DrawLine(pen1,10,20,100,20);//畫虛線,圖中左邊第2條線

pen1.DashStyle=System.Drawing.Drawing2D.DashStyle.DashDot;//點,短線風格的線

g.DrawLine(pen1,10,30,100,30);//圖中左邊第3條線

//雙點,短線風格的線

pen1.DashStyle=System.Drawing.Drawing2D.DashStyle.DashDotDot;

g.DrawLine(pen1,10,40,100,40);//圖中左邊第4條線

pen1.DashStyle=System.Drawing.Drawing2D.DashStyle.Dot;//由點組成的線

g.DrawLine(pen1,10,50,100,50);//圖中左邊第5條線

pen1.DashStyle=System.Drawing.Drawing2D.DashStyle.Solid;//實線筆

pen1.EndCap=System.Drawing.Drawing2D.LineCap.ArrowAnchor;//後箭頭

g.DrawLine(pen1,150,10,250,10);//圖中右邊第1條線

pen1.StartCap=System.Drawing.Drawing2D.LineCap.ArrowAnchor;//前箭頭

g.DrawLine(pen1,150,22,250,22);//圖中右邊第2條線

pen1.EndCap=System.Drawing.Drawing2D.LineCap.RoundAnchor;

g.DrawLine(pen1,150,34,250,34);//圖中右邊第3條線

pen1.EndCap=System.Drawing.Drawing2D.LineCap.SquareAnchor;

g.DrawLine(pen1,150,46,250,46);//圖中右邊第4條線

pen1.EndCap=System.Drawing.Drawing2D.LineCap.Triangle;

g.DrawLine(pen1,150,58,250,58);//圖中右邊第5條線

pen1.EndCap=System.Drawing.Drawing2D.LineCap.DiamondAnchor;

//圖中右邊第6條線

g.DrawLine(pen1,150,70,250,70);

}

運行效果如右圖:

 

 

5.6      建立畫刷

畫刷類對象指定填充封閉圖形內部的顏色和樣式,封閉圖形包括矩形、橢圓、扇形、多邊形和任意封閉圖形。GDI+系統提供了了幾個預約義畫刷類,包括:

l SolidBrush:單色畫刷。在名字空間System.Drawing中定義。

l HatchBrush:陰影畫刷。如下畫刷在名字空間System.Drawing.Drawing2D中定義。

l TextureBrush:紋理(圖像)畫刷。

l LinearGradientBrush:顏色漸變畫刷。

l PathGradientBrush:使用路徑及複雜的混合漸變畫刷。

5.6.1單色畫刷SolidBrush

前邊已使用過單色畫刷。其構造函數只有1個,定義以下:

SolidBrush brush1=new SolidBrush(Colorcolor);//創建指定顏色的畫刷

在使用中能夠修改其屬性Color來修改其顏色,例如:brush1.Color=Color.Green;

5.6.2陰影畫刷HatchBrush

用指定樣式(例如,多條橫線、多條豎線、多條斜線等)、指定線條的顏色和指定背景顏色定義的畫刷,陰影畫刷有兩個構造函數:

//指定樣式和線條的顏色的構造函數,背景色被初始化爲黑色。

HatchBrush brush1=new HatchBrush(HatchStyle h,Color c);

//指定樣式、線條的顏色和背景顏色的構造函數。

HatchBrush brush1=new HatchBrush(HatchStyle h,Color c1,Color c2);

有3個屬性以下:

l 屬性backgroundColor:畫刷背景顏色。

l 屬性foreColor:畫刷線條的顏色。

l 屬性HatchStyle:該屬性是隻讀的,不能修改,表示畫刷的不一樣樣式。

例子5.6.2:顯示了陰影畫刷屬性HatchStyle爲不一樣值時畫刷的不一樣樣式。在Form1.cs文件頭部增長語句:using System.Drawing.Drawing2D,主窗體Paint事件處理函數以下:

private void Form1_Paint(object sender,System.Windows.Forms.PaintEventArgs e)

{   Graphics g=e.Graphics;//獲得窗體的使用的Graphics類對象

HatchBrush b1=new

HatchBrush(HatchStyle.BackwardDiagonal,Color.Blue,Color.LightGray);

g.FillRectangle(b1,10,10,50,50);//矩形被填充左斜線,第1圖

HatchBrush b2=new HatchBrush(HatchStyle.Cross,Color.Blue,Color.LightGray);

g.FillRectangle(b2,70,10,50,50);//矩形被填充方格,第2圖

HatchBrush b3=new

HatchBrush(HatchStyle.ForwardDiagonal,Color.Blue,Color.LightGray);

g.FillRectangle(b3,130,10,50,50);//矩形被填充右斜線,第3圖

HatchBrush b4=new

HatchBrush(HatchStyle.DiagonalCross,Color.Blue,Color.LightGray);

g.FillRectangle(b4,190,10,50,50);//矩形被填充菱形,第4圖

HatchBrush b5=new

HatchBrush(HatchStyle.Vertical,Color.Blue,Color.LightGray);

g.FillRectangle(b5,250,10,50,50);//矩形被填充豎線,第5圖

HatchBrush b6=new

HatchBrush(HatchStyle.Horizontal,Color.Blue,Color.LightGray);

g.FillRectangle(b6,310,10,50,50);//矩形被填充橫線,第6圖

}

運行效果如右圖:

 

5.6.3紋理(圖像)畫刷TextureBrush

紋理(圖像)畫刷使用圖像來填充封閉曲線的內部,有8個構造函數,最簡單的構造函數以下,其他請用幫助查看。

TextureBrush(Image bitmap);//使用位圖類對象做爲畫刷構造函數的參數

下邊的例子使用文件n2k.bmp創建位圖類對象做爲畫刷的圖案,在Form1文件的頭部增長語句:using System.Drawing.Drawing2D,主窗體Paint事件處理函數以下:

private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)

{   Graphics g=e.Graphics;//獲得窗體的使用的Graphics類對象

    Pen pen1=new Pen(Color.Red);

//位圖類對象做爲畫刷圖案,使用文件n2k.bmp創建位圖類對象見5.10節

TextureBrush b1=

new TextureBrush(new Bitmap("C:\\WINNT\\system32\\n2k.bmp"));

    g.FillRectangle(b1,10,10,200,100);

    g.DrawRectangle(pen1,10,10,200,100);

}

文件C:\WINNT\system32\n2k.bmp定義的圖形的顯示效果以下:

 

運行效果如右圖。

5.6.4顏色漸變畫刷LinearGradientBrush

該類封裝雙色漸變和自定義多色漸變畫刷。全部顏色漸變都是沿由矩形的寬度或兩個點指定的直線定義的。默認狀況下,雙色漸變是沿指定直線從起始色到結束色的均勻水平線性變化。有8個構造函數,最簡單的構造函數以下,其他請用幫助查看。

public LinearGradientBrush(

Point point1,//point1做爲線性漸變直線開始點,也能夠爲PointF

Point point2,//point2做爲線性漸變直線結束點,也能夠爲PointF

Color color1,Color color2);//線性漸變開始顏色和結束顏色

下邊的例子顯示了不一樣線性漸變直線開始點和結束點,使用顏色漸變畫刷從黃漸變到藍的效果。在Form1文件的頭部增長語句:using System.Drawing.Drawing2D,主窗體Paint事件處理函數以下:

private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)

{   Graphics g=e.Graphics;//獲得窗體的使用的Graphics類對象

Pen pen1=new Pen(Color.Red);

Point p1=new Point(10,10);//p1做爲漸變直線開始點,也能夠爲PointF

Point p2=new Point(50,10);//p2做爲漸變直線結束點,也能夠爲PointF

LinearGradientBrush brush1=//從黃漸變到藍,見下圖左圖

new LinearGradientBrush(p1,p2,Color.Yellow,Color.Blue);

g.FillRectangle(brush1,10,10,200,100);

g.DrawRectangle(pen1,10,10,200,100);

p1=new Point(220,10);

p2=new Point(270,50);

LinearGradientBrush brush2=//從黃漸變到藍,見下圖右圖

new LinearGradientBrush(p1,p2,Color.Yellow,Color.Blue);

g.FillRectangle(brush2,230,10,200,100);

g.DrawRectangle(pen1,230,10,200,100);

}

運行效果以下圖:

 

5.6.5畫刷PathGradientBrush

畫刷PathGradientBrush能夠實現複雜的漸變顏色。有5個構造函數,這裏只介紹其中的一個,其參數GraphicsPath類使用見例子及5.7.11節。其他構造函數請用幫助查看。

public PathGradientBrush(GraphicsPath path);//畫刷PathGradientBrush構造函數

畫刷屬性SurroundColors:一個Color結構的數組,它表示與PathGradientBrush對象填充的路徑中的各點相關聯的顏色的數組。SurroundColors數組中的每一Color結構都對應於路徑中的點。

下邊的例子介紹畫刷PathGradientBrush的使用方法,在Form1.cs文件的頭部增長語句:using System.Drawing.Drawing2D,主窗體Paint事件處理函數以下,運行效果以下圖。

private void Form1_Paint(object sender,System.Windows.Forms.PaintEventArgs e)

{   Graphics g=e.Graphics;//獲得窗體使用的Graphics類對象

Point[] p1=new Point[6];//點結構數組,有6個元素

p1[0]=new Point(30,0);

p1[1]=new Point(160,30);

p1[2]=new Point(90,60);

p1[3]=new Point(100,90);

p1[4]=new Point(30,60);

p1[5]=new Point(0,30);

GraphicsPath path=new GraphicsPath(//創建GraphicsPath類對象

p1,//由點數組p1定義繪製刷子的外輪廓線的路徑

new Byte[]{//定義數組p1每一個點元素的關聯類型,第1點是開始點

//貝塞爾曲線必須由4點組成,所以第一、二、三、4點組成一條貝塞爾曲線,

(byte)PathPointType.Start,(byte)PathPointType.Bezier,

(byte)PathPointType.Bezier,(byte)PathPointType.Bezier,

//第五、6點是直線,從第4點到第5點和從第5點到第6點畫直線

(byte)PathPointType.Line,(byte)PathPointType.Line,});

//爲了造成閉合曲線,增長最後一條直線

PathGradientBrush brush1=new PathGradientBrush(path);//生成畫刷

brush1.SurroundColors=new Color[]{Color.Green,Color.Yellow,Color.Red,

Color.Blue,Color.Orange,Color.OliveDrab,};//設置屬性SurroundColors的值

g.FillPath(brush1,path);

}

5.7      基本圖形的繪製和填充

Graphics類提供了一些繪圖方法,用來繪製或填充各類圖形。本節介紹這些方法。

5.7.1   繪製線段

兩個繪製線段的函數和一個繪製多條線段的函數定義以下:

l void DrawLine(Pen pen,int x1,int y1,int x2,int y2);

其中pen爲畫筆,(x1,y1)爲畫線起點座標,(x2,y2)爲畫線終點座標。

l DrawLine(Pen pen,Point p1,Point p2);

其中pen爲畫筆,點p1爲畫線起點座標,點p2爲畫線終點座標。

l public void DrawLines(Pen pen,Point[] points);

此方法繪製多條線段。從points[0]到points[1]畫第1條線,從points[1]到points[2]畫第2條線,依此類推。

例子e5_7_1A:使用DrawLine()的例子,爲主窗體Paint事件增長事件處理函數以下:

private void Form1_Paint(object sender,System.Windows.Forms.PaintEventArgs e)

{   Graphics g=e.Graphics;

Pen pen1=new Pen(Color.Red);

g.DrawLine(pen1,30,30,100,100);//用筆pen1從點(30,30)到(100,100)畫直線

Point p1=new Point(30,40);

Point p2=new Point(100,110);

g.DrawLine(pen1,p1,p2);//用筆pen1從點(30,40)到(100,110)畫直線

}

例子e5_7_1B:使用繪製線段函數畫任意曲線(畫正弦曲線,注意如何使用數學函數)。

private void Form1_Paint(object sender,System.Windows.Forms.PaintEventArgs e)

{   Graphics g=this.CreateGraphics();//獲得窗體的使用的Graphics類對象

Pen pen1=new Pen(Color.Red);

float y=50,y1,x1,x2;

for(int x=0;x<720;x++)//畫正弦曲線

{   x1=(float)x;

x2=(float)(x+1);

y1=(float)(50+50*Math.Sin((3.14159/180.0)*(x+1)));

g.DrawLine(pen1,x1,y,x2,y1);

y=y1;

}

}

運行,在窗體中能夠看到一條紅色正弦曲線以下圖。

 

例子e5_7_1C:在畫圖程序中,能夠用鼠標畫任意曲線,現實現用拖動鼠標左鍵在主窗體中畫曲線。每條曲線都是由若干很短的線段組成。鼠標左鍵按下狀態下,移動鼠標,每移動很短距離,畫出這段線段,全部這些線段組合起來,造成一條曲線。

(1) 新建項目。增長兩個私有變量:

private bool mark=false;//表示鼠標左鍵是否按下,如按下鼠標再移動將畫曲線

private Point point;//記錄畫下一很短線段的起始點。

(2) 爲Form窗體的事件OnMouseDown,OnMouseUp,OnMouseMove增長事件函數以下:

private void Form11_MouseDown(object sender,//鼠標按下事件處理函數

System.Windows.Forms.MouseEventArgs e)

{   if(e.Button==MouseButtons.Left)//若是鼠標左鍵按下

{   point.X=e.X;//記錄曲線的第一個點的座標

point.Y=e.Y;

mark=true;//表示鼠標左鍵已按下,鼠標若是再移動,將畫曲線

}

}

private void Form1_MouseMove(object sender,//鼠標移動事件處理函數

System.Windows.Forms.MouseEventArgs e)

{   if(mark)//若是鼠標左鍵按下

{   Graphics g=this.CreateGraphics();//獲得窗體的使用的Graphics類對象

Pen pen1=new Pen(Color.Black);//黑筆

g.DrawLine(pen1,point.X,point.Y,e.X,e.Y);//畫線

point.X=e.X;//記錄畫下一線段的起始點的座標

point.Y=e.Y;

}

}

private void Form1_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)

{   mark=false;}//中止畫線

(3) 運行,在Form窗體拖動鼠標左鍵能夠畫線。但最小化後再最大化後,圖形消失。修改上例,使其能克服這個缺點。實現的思路是記錄每一條曲線的每一條很短線段的座標。使用ArrayList類對象記錄曲線以及曲線中的點,請注意ArrayList類使用方法。

(4) 爲定義主窗體的Form1類中增長私有變量:

private ArrayList Point_List;//用來記錄1條曲線的全部點。

private ArrayList Line_List;//用來記錄每條曲線,既Point_List對象。

在Form1類構造函數中增長語句:Line_List=new ArrayList();

(5) 修改主窗體事件OnMouseDown,OnMouseUp,OnMouseMove事件處理函數以下:

private void Form1_MouseDown(object sender,//陰影部分爲修改的內容

System.Windows.Forms.MouseEventArgs e)

{   if(e.Button==MouseButtons.Left)

{   Point_List=new ArrayList();//創建數組,記錄1條曲線的全部點

point.X=e.X;

point.Y=e.Y;

mark=true;

Point_List.Add(point);//曲線起點的座標

}

}

private void Form1_MouseMove(object sender,

System.Windows.Forms.MouseEventArgs e)

{   if(mark)

    {   Graphics g=this.CreateGraphics();

Pen pen1=new Pen(Color.Black);

g.DrawLine(pen1,point.X,point.Y,e.X,e.Y);

point.X=e.X;

point.Y=e.Y;

Point_List.Add(point);//記錄曲線中其它點的座標

    }

}

private void Form1_MouseUp(object sender,System.Windows.Forms.MouseEventArgs e)

{   mark=false;

Line_List.Add(Point_List);//記錄此條線,注意參數是Point_List

}

(6) 增長Form窗體的Paint事件函數以下:

private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)

{   Graphics g=e.Graphics;

Pen pen1=new Pen(Color.Black);

Point p1,p2;

foreach(ArrayList l in Line_List)//取出每條線

{   for(int k=0;k<(l.Count-1);k++)//重畫每條線的點

{   p1=(Point)l[k];

p2=(Point)l[k+1];

g.DrawLine(pen1,p1,p2);

}

}

}

(7)    運行,在Form窗體拖動鼠標能夠畫線。最小化後再最大化後,圖形不消失。

5.7.2   ArrayList類

ArrayList類是容量能夠動態增長的數組,其元素類型能夠是任意類型。和其它數組同樣,ArrayList類能夠使用對象名[索引號]引用其元素,索引號也從零開始。前邊已屢次使用此類,例如:控件ListBox和ComboBox的屬性Items,以及5.7.1節中的例子。其經常使用的屬性及方法以下:

l 屬性Count:ArrayList中實際包含的元素數。

l 方法Add:將參數指定的對象添加到ArrayList對象的結尾處。

l 方法Clear:從ArrayList中移除全部元素。

l 方法Contains:bool類型,肯定參數指定的元素是否在ArrayList中。

l 方法IndexOf:int類型,順序查找和參數指定對象相同的第一個元素的索引。

l 方法Insert:插入數據,第1個參數爲插入的位置(索引號),第2個參數爲插入的對象。

l 方法LastIndexOf:順序查找和參數指定對象相同的最後一個元素的索引。

l 方法RemoveAt:移除指定索引處的元素。

l 方法Sort:對整個ArrayList中的元素進行排序。

5.7.3   畫橢圓(圓)及鍵盤消息的使用

兩個畫橢圓的函數的功能是畫指定矩形的內切橢圓,如爲正方形則畫圓,兩個函數以下:

l void DrawEllipse(Pen pen,int x,int y,int width,int height);

其中pen爲畫筆,畫外輪廓線,(x1,y1)爲指定矩形的左上角座標,width爲指定矩形的寬,height爲指定矩形的高。

l void DrawEllipse(Pen pen,Rectangle rect);

其中pen爲畫筆,畫外輪廓線,rect爲指定矩形結構對象。

例子5_7_3A:畫橢圓。爲主窗體Paint事件增長事件處理函數以下:

private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)

{   Graphics g=this.CreateGraphics();

Pen pen1=new Pen(Color.Red);

g.DrawEllipse(pen1,10,10,200,100);

Rectangle rect=new Rectangle(20,20,100,100);

g.DrawEllipse(pen1,rect);

}

例子5_7_3B用四個箭頭鍵移動窗體中的圓球。移動圓球,實際是先把前邊畫的圓擦掉,在新的位置從新畫圓。如要擦掉圓,能夠用窗體背景色做爲筆和刷子的顏色,在圓的原先位置重畫和填充圓。注意鍵盤事件處理函數的使用。具體實現步驟以下:

(1) 新建項目。在Form1類中增長變量:int x,y,記錄定義圓位置的矩形左上角的座標。

(2) 在Form1類中增長一個方法,該方法按照參數指定顏色畫圓,方法定義以下:

void DrawCir(Color color)//參數是畫圓的筆和刷子的顏色

{   Graphics g=this.CreateGraphics();

Pen pen1=new Pen(color);

SolidBrush brush1=new SolidBrush(color);

g.DrawEllipse(pen1,x,y,100,100);

g.FillEllipse(brush1,x,y,100,100);

}

(3) 爲主窗體Paint事件增長事件處理函數以下:

private void Form1_Paint(object sender,System.Windows.Forms.PaintEventArgs e)

{   DrawCir(Color.Red);}

(4) 爲主窗體KeyDown事件增長事件函數以下:(注意不要使用KeyPress事件,其事件處理函數的第2個參數e的e.KeyChar是按下鍵的ASCII值,但不少鍵無ASCII值。)

private void Form1_KeyDown(object sender,System.Windows.Forms.KeyEventArgs e)

{   switch (e.KeyCode)//e.KeyCode是鍵盤每一個鍵的編號

{   case Keys.Left://左箭頭鍵編號

DrawCir(this.BackColor);//用Form窗體的背靜色畫圓,即擦除圓

x=x-10;//圓左移

DrawCir(Color.Red);//在新的位置用紅色畫圓,效果是圓左移

break;

case Keys.Right://圓右移

DrawCir(this.BackColor);

x+=10;

DrawCir(Color.Red);

break;

case Keys.Down://圓下移

DrawCir(this.BackColor);

y+=10;

DrawCir(Color.Red);

break;

case Keys.Up://圓上移

DrawCir(this.BackColor);

y=y-10;

DrawCir(Color.Red);

break;

}

}

(5)    運行,能夠用4個箭頭鍵移動紅色圓。

使用KeyDown事件,事件處理函數的第2個參數e的e.KeyCode是鍵盤每一個鍵的編號,其它經常使用鍵的編號以下:數字鍵0-9編號爲Keys.D0-Keys.D9;字母鍵A-Z爲Keys.A-Keys.Z;F0-F12鍵表示爲Keys.F0-Keys.F12等。

如使用KeyPress事件,事件處理函數的第2個參數e的e.KeyChar表示按鍵的ACSII值,例如可用以下語句if(e.KeyChar==(char)13)判斷是否按了回車鍵。

5.7.4   畫矩形

兩個繪製1個矩形(正方形)的函數和一個繪製多個矩形(正方形)的函數定義以下:

l void DrawRectangle(Pen pen,int x,int y,int width,int height);

其中pen爲畫筆,畫外輪廓線,(x1,y1)爲矩形的左上角座標,width爲指定矩形的寬,height爲指定矩形的高。

l void DrawRectangle(Pen pen,Rectangle rect);

其中pen爲畫筆,畫外輪廓線,rect爲矩形結構對象。

l public void DrawRectangles(Pen pen,Rectangle[] rects);

繪製一系列由Rectangle結構指定的矩形。

例子5_7_3:畫矩形。爲主窗體Paint事件增長事件處理函數以下:

private void Form1_Paint(object sender,System.Windows.Forms.PaintEventArgs e)

{   Graphics g=this.CreateGraphics();

Pen pen1=new Pen(Color.Red);

g.DrawRectangle(pen1,10,10,200,100);

Rectangle rect=new Rectangle(20,20,100,100);

g.DrawRectangle(pen1,rect);

}

5.7.5   繪製圓弧

DrawArc方法繪製指定矩形的內切橢圓(圓)中的一段圓弧,方法定義以下:

void DrawArc(Pen pen,int x,int y,int width,int height,int StartAngle,int EndAngle);

其中pen爲畫筆,畫外輪廓線,(x1,y1)爲矩形的左上角座標,width爲指定矩形的寬,height爲指定矩形的高。StartAngle爲圓弧的起始角度,EndAngle爲圓弧的結束角度,單位爲度。指定矩形的中心點作矩形寬和高的的垂線做爲x,y軸,中心點爲圓點。圓點右側x軸爲0度,順時針旋轉爲正角度,逆時針旋轉爲負角度。

例子5_7_4:畫圓弧。爲主窗體Paint事件增長事件處理函數以下:

private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)

{   Graphics g=this.CreateGraphics();

Pen pen1=new Pen(Color.Red);

g.DrawArc(pen1,10,10,200,100,0,30);

}

5.7.6   DrawPie方法

DrawPie方法方法繪製指定矩形的內切橢圓(圓)中的一段圓弧,而且用指定矩形的中心點鏈接開始點和結束點,這個圖形叫作餅圖,方法定義以下:

void DrawPie(Pen pen,int x,int y,int width,int height,int StartAngle,int EndAngle);

方法參數和DrawArc方法參數相同。

例子5_7_5:畫餅圖。爲主窗體Paint事件增長事件處理函數以下:

private void Form1_Paint(object sender,System.Windows.Forms.PaintEventArgs e)

{   Graphics g=this.CreateGraphics();

Pen pen1=new Pen(Color.Red);

g.DrawPie(pen1,10,10,200,100,0,30);

}

5.7.7   Bezier曲線

能夠使用DrawBezier方法畫一條Bezier曲線。它的兩個畫線函數定義以下:

l Void DrawBezier(Pen pen,float x1,float y1,

float x2,float y2,float x3,float y3,float x4,float y4);

其中pen是畫筆對象,畫輪廓線,(x1,y1)是起始點,(x2,y2)是第一控制點,(x3,y3)是第二控制點,(x4,y4)是結束點。

l Void DrawBezier(Pen pen,Point p1,Point p2,Point p3,Point P4);

其中pen是畫筆對象,畫輪廓線,p1是起始點,p2是第一控制點,p3是第二控制點,p4是結束點。

例子5_7_6:畫Bezier曲線。爲主窗體Paint事件增長事件處理函數以下:

private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)

{   Graphics g=this.CreateGraphics();

Pen pen1=new Pen(Color.Red);

g.DrawBezier(pen1,10,10,200,100,50,60,100,200);

}

5.7.8   DrawPolygon方法

該方法畫一個多邊形,使用點結構數組定義多邊形的頂點。兩個畫線函數定義以下:

l void DrawPolygon(Pen pen,Point[] points);

l void DrawPolygon(Pen pen,PointF[] points);//點座標能夠是小數

例子5_7_7:畫一個多邊形以下圖,爲主窗體Paint事件增長事件處理函數以下:

private void Form1_Paint(object sender,System.Windows.Forms.PaintEventArgs e)

{   Graphics g=this.CreateGraphics();

Pen pen1=new Pen(Color.Red);

Point[] p1=new Point[]

{   new Point(10,10),

new Point(60,40),

new Point(100,80),

new Point(60,100)

};

g.DrawPolygon(pen1,p1);

}

5.7.9   DrawClosedCurve方法

DrawClosedCurve方法用來繪製通過Point結構數組中每一個點的閉合基數樣條。基數樣條是一連串單獨的曲線,這些曲線鏈接起來造成一條較大的曲線。樣條由點的數組指定,並經過該數組中的每個點。基數樣條平滑地經過數組中的每個點,請比較一下本節的圖形和上節圖形的區別。若是最後一個點不匹配第一個點,則在最後一個點和第一個點之間添加一條附加曲線段以使該圖閉合,點Point結構數組必須至少包含四個元素,此方法使用默認張力0.5。有4個畫線函數,經常使用的2個畫線函數定義以下:

l void DrawClosedCurve(Pen pen,Point[] points);

l void DrawClosedCurve(Pen pen,PointF[] points);//點座標能夠是小數

例子e5_7_9:使用DrawClosedCurve方法,繪製有4個元素的Point結構數組定義的閉合基數樣條閉合曲線以下圖,爲主窗體Paint事件增長事件處理函數以下:

private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)

{   Graphics g=this.CreateGraphics();

Pen pen1=new Pen(Color.Red);

Point[] p1=new Point[]

{   new Point(10,10),

new Point(60,40),

new Point(100,80),

new Point(60,100)

};

g.DrawClosedCurve(pen1,p1);

}

5.7.10        DrawCurve方法

用DrawCurve方法和DrawClosedCurve方法同樣,用來繪製通過Point結構數組中每一個點的閉合基數樣條,但最後兩個點之間不連線。經常使用的兩個畫線函數定義以下:

l void DrawPolygon(Pen pen,Point[] points);

l void DrawPolygon(Pen pen,PointF[] points);

例子5_7_9:使用DrawCurve方法,繪製有4個元素的Point結構數組定義的閉合基數樣條閉合曲線以下圖,爲主窗體Paint事件增長事件處理函數以下:

private void Form1_Paint(object sender,System.Windows.Forms.PaintEventArgs e)

{   Graphics g=this.CreateGraphics();

Pen pen1=new Pen(Color.Red,3);

Point[] p1=new Point[]

{   new Point(10,10),

new Point(60,40),

new Point(100,80),

new Point(60,100)

};

g.DrawCurve(pen1,p1);

}

5.7.11        DrawPath方法和GraphicsPath類

用DrawPath方法能夠繪製多個曲線,方法參數GraphicsPath類對象path定義每一個曲線類型。DrawPath方法定義以下:

void DrawPath(Pen pen,GraphicsPath path);

例子5_7_10A:用DrawPath方法畫一個矩形和其內切橢圓以下圖,在Form1.cs文件的頭部增長語句:using System.Drawing.Drawing2D,主窗體Paint事件處理函數以下:

private void Form1_Paint(object sender,System.Windows.Forms.PaintEventArgs e)

{   Rectangle myEllipse=new Rectangle(20,20,100,50);

GraphicsPath myPath=new GraphicsPath();//創建GraphicsPath()類對象

myPath.AddEllipse(myEllipse);//追加一橢圓

myPath.Add Rectangle(myEllipse);//追加一矩形

Pen myPen=new Pen(Color.Black,2);

//畫這條曲線,即橢圓和矩形。

e.Graphics.DrawPath(myPen,myPath);

}

GraphicsPath類是表示一系列相互鏈接的直線和曲線的路徑,應用程序使用此路徑來繪製曲線的輪廓、填充形狀內部和建立剪輯區域。由屬性PathPoints(點數組)定義繪製直線和曲線的路徑。路徑可由任意數目的圖形(子路徑)組成,每一圖形都是由一系列相互鏈接的直線和曲線或幾何形狀基元構成的。由屬性PathTypes(字節數組)定義屬性PathPoints(點數組)中每一個點元素的關聯圖形或曲線類型,圖形的起始點是相互鏈接的一系列直線和曲線中的第一點。終結點是該序列中的最後一點。GraphicsPath在System.Drawing.Drawing2D名字空間。經常使用屬性、事件和方法定義以下:

l 構造函數GraphicsPath();//創建空對象

l 構造函數public GraphicsPath(Point[] pts,byte[] types);

參數pts爲Point結構數組,數組元素表示構造路徑所使用的點。參數types指定路徑中相應點的關聯圖形或曲線類型數組。參見5.6.5節。

l 屬性PointCount:獲取 PathPoints 或 PathTypes 數組中的元素數。

l 方法IsVisible:指定點是否包含在此 GraphicsPath 對象內。

l 方法:void AddArc(Rectangle rect,float startAngle,float sweepAngle);

在表明要描繪圖形的GraphicsPath類對象中追加一段橢圓弧。

l 方法:void AddEllipse(Rectangle rect),追加一橢圓(圓)

l 方法:void AddLine(Point pt1,Point pt2),追加一線段

l 方法:void AddRectangle(Rectangle rect),追加一矩形

還有其它增長曲線的方法,例如:AddBezier 方法、AddBeziers 方法、AddClosedCurve 方法、AddCurve 方法、AddLines 方法、AddPath 方法、AddPie 方法、AddPolygon 方法、AddRectangles 方法、AddString 方法等,請用幫助查看。

5.7.12 DrawString方法

DrawString方法在指定位置而且用指定的Brush和Font對象繪製指定的文本字符串。有6個重載方法,經常使用的一個是:

public void DrawString(string s,//s是爲要顯示的字符串

Font font,//顯示的字符串使用的字體

Brush brush,//用刷子寫字符串

PointF point);//顯示的字符串左上角的座標

最後一個參數也能夠是RectangleF對象,仍表示顯示的字符串位置。還能夠再增長一個參數,即第5個參數,StringFormat對象,它指定應用於所繪製文本的格式化屬性(如行距和對齊方式)。在打印和打印預覽一節已使用了這個方法。

例子5_7_12:用DrawString方法顯示字符串,主窗體Paint事件處理函數以下:

private void Form1_Paint(object sender,System.Windows.Forms.PaintEventArgs e)

{   String drawString="Sample Text";//要顯示的字符串

Font drawFont=new Font("Arial",16);//顯示的字符串使用的字體

SolidBrush drawBrush=new SolidBrush(Color.Black);//寫字符串用的刷子

PointF drawPoint=new PointF(20.0F,20.0F);//顯示的字符串左上角的座標

e.Graphics.DrawString(drawString,drawFont,drawBrush,drawPoint);

}

5.7.13 DrawImage和DrawIcon方法

用來在指定的位置繪製指定的Image對象和圖標。Graphics類中有多個DrawImage重載方法,最簡單的是如下方法:

l public void DrawImage(Image image,Point point);

在指定的位置使用原始物理大小繪製指定的Image對象。參數1爲要繪製的Image對象,參數2表示所繪製圖像的左上角在窗體中的位置。

l public void DrawImage(Image image,Point[] destPoints);

在指定位置而且按指定形狀和大小繪製指定的Image對象。參數1爲要繪製的Image對象,參數2表示有3個元素的Point結構數組,三個點定義一個平行四邊形。縮放和剪切image參數表示的圖像,以在此平行四邊形內顯示。參數2也能夠是一個矩形結構。

l public void DrawImage(Image image,//要繪製的Image對象

Rectangle destRect,//指定所繪製圖像的位置和大小,圖像進行縮放以適合該矩形

Rectangle srcRect,//指定image對象中要繪製的部分

GraphicsUnit srcUnit);//枚舉的成員,指定srcRect參數所用的度量單位

例子5_7_1A:在指定位置繪製Image對象指定部分。

private void Form1_Paint(object sender,System.Windows.Forms.PaintEventArgs e)

{   Image newImage=Image.FromFile("d:\\CSARP\\1.jpg");//創建要繪製的Image圖像

Rectangle destRect=new Rectangle(10,10,150,150);//顯示圖像的位置

Rectangle srcRect=new Rectangle(50,50,150,150);//顯示圖像那一部分

GraphicsUnit units=GraphicsUnit.Pixel;//源矩形的度量單位設置爲像素

e.Graphics.DrawImage(newImage,destRect,srcRect,units);//顯示

}//若是把顯示圖像的位置變寬,看一下效果,爲何?其它重載方法可用幫助查看。

l public void DrawIcon(Icon icon,Rectangle targetRect);

在Rectangle結構指定的區域內繪製指定的Icon對象表示的圖標。

例子5_7_1B:在指定位置畫圖標。

private void Form1_Paint(object sender,System.Windows.Forms.PaintEventArgs e)

{   Icon newIcon=new Icon("d:\\CSARP\\TASKS.ICO");

Rectangle rect=new Rectangle(100,100,200,200);

e.Graphics.DrawIcon(newIcon,rect);

}

5.7.14        FillEllipse方法

該方法用指定畫刷來填充指定矩形的內切橢圓(圓)。兩個填充函數的定義以下:

l void FillEllipse(Brush brush,int x,int y,int width,int height);

其中brush爲指定畫刷,(x1,y1)爲指定矩形的左上角座標,width爲指定矩形的寬,height爲指定矩形的高。

l void DrawEllipse(Pen pen,Rectangle rect);

其中brush爲指定畫刷,rect爲指定矩形結構對象。

例子5_7_13:用指定畫刷來填充指定矩形的內切橢圓。

private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)

{   Graphics g=this.CreateGraphics();

SolidBrush brush=new SolidBrush(Color.Blue);

g.FillEllipse(brush,10,10,200,100);

Rectangle rect=new Rectangle(120,120,100,100);

g.FillEllipse(brush,rect);

}

5.7.15        FillRectangle方法

FillRectangle方法用指定畫刷來填充指定矩形。兩個填充函數定義以下:

l void FillRectangle(Brush brush,int x,int y,int width,int height);

其中brush爲指定畫刷,(x1,y1)爲矩形的左上角座標,width爲指定矩形的寬,height爲指定矩形的高。

l void FillRectangle(Brush brush,Rectangle rect);

其中brush爲指定畫刷,rect爲矩形結構對象。

例子5_7_14:用指定畫刷來填充指定矩形。

private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)

{   Graphics g=this.CreateGraphics();

SolidBrush brush=new SolidBrush(Color.Blue);

g.FillRectangle(brush,10,10,200,100);

Rectangle rect=new Rectangle(120,120,100,100);

g.FillRectangle(brush,rect);

}

5.7.16        FillPie方法

FillPie方法用指定畫刷來填充指定餅圖。函數定義以下:

void FillPie(Brush brush,int x,int y,int width,

int height,int StartAngle,int EndAngle);

其中brush爲指定畫刷,方法其它參數和DrawArc方法參數相同。

例子5_7_15:用指定畫刷來填充指定餅圖。

private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)

{   Graphics g=this.CreateGraphics();

SolidBrush brush=new SolidBrush(Color.Blue);

g.FillPie(brush,10,10,200,100,0,30);

}

5.7.17        FillRegion方法和Region類

FillRegion方法用刷子填充區域Region類對象內部。Region類對象由矩形和路徑構成。若是區域不閉合,則在最後一個點和第一個點之間添加一條額外的線段來將其閉合。方法定義以下:

public void FillRegion(Brush brush,Region region);

第1個參數是填充使用的刷子,第2個參數是指定的區域。

例子5.7.16A:用純藍色刷子,使用FillRegion方法填充一個矩形區域。

private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)

{   SolidBrush blueBrush=new SolidBrush(Color.Blue);

Rectangle fillRect=new Rectangle(10,10,100,100);

Region fillRegion=new Region(fillRect);

e.Graphics.FillRegion(blueBrush,fillRegion);

}

區域是輸出設備顯示區域的一部分。區域能夠是簡單的(單個矩形)或複雜的(多邊形和閉合曲線的組合)。下圖中的左數第1圖顯示了兩個區域:一個利用矩形構造,另外一個利用路徑構造。能夠經過合併現有的區域來建立複雜區域。Region類提供瞭如下合併區域的方法:Intersect、Union、Xor、Exclude和Complement。兩個區域的交集是同時屬於兩個區域的全部點的集合,方法Intersect能夠獲得兩個Region類對象的交集。並集是多個區域的全部點的集合,方法Union能夠獲得兩個Region類對象的並集。方法Xor能夠獲得兩個Region類對象的並集減去這二者的交集,即下圖中的左數第4圖顯示的藍色區域。方法Exclude和Complement能夠獲得1個Region類對象和參數指定的Region類對象的不相交的部分,即下圖中的左數第5圖顯示區域。

 

Region類經常使用的方法以下:

l 構造函數Region:能夠沒有參數,即建立一個空區域。也能夠有一個參數,能夠是GraphicsPath、Rectangle、RectangleF和RegionData類型,由今生成一個區域。

l 方法Exclude和Complement:獲得1個Region類對象和參數指定的Region類對象的不相交的部分。參數能夠是GraphicsPath、Rectangle、RectangleF和Region類型。

l 方法Equals:比較2個區域是否相等。參數1是要比較的區域,參數2是要繪製表面的Graphics對象。

l 方法Intersect:能夠獲得兩個Region類對象的交集。參數能夠是GraphicsPath、Rectangle、RectangleF和Region類型。

l 方法IsEmpty:測試是否爲空區域。

l 方法IsVisible:測試參數指定的點或矩形是否在區域中。

l 方法Union:能夠獲得兩個Region類對象的並集。

l 方法Xor:能夠獲得兩個Region類對象的並集減去這二者的交集。

例子5_7_16B:創建2個矩形,有部分相交,將相交部分填充爲藍色。在Form1.cs文件的頭部增長語句:using System.Drawing.Drawing2D,主窗體Paint事件處理函數以下:

private void Form1_Paint(object sender,System.Windows.Forms.PaintEventArgs e)

{   Graphics g=e.Graphics;

    Rectangle regionRect=new Rectangle(10,10,50,50);

    Pen pen1=new Pen(Color.Black);

    g.DrawRectangle(pen1,regionRect);//繪製第1個矩形           

    RectangleF unionRect=new RectangleF(25,25,50,50);//第2個矩形

    pen1.Color=Color.Red;

    g.DrawEllipse(pen1,unionRect);//畫橢圓

    GraphicsPath myPath=new GraphicsPath();//創建GraphicsPath()類對象

    myPath.AddEllipse(unionRect);//追加一橢圓

    Region myRegion=new Region(regionRect);//創建表示第1個矩形的區域

    myRegion.Intersect(myPath);//獲得兩個區域的交集

    SolidBrush myBrush=new SolidBrush(Color.Blue);

e.Graphics.FillRegion(myBrush,myRegion);//填充區域

}

運行效果如右圖。除了以上介紹的填充方法,還有以下方法:FillClosedCurve方法、FillPath方法、FillPolygon方法等,請用幫助查看。

5.8    Matrix類和圖形的平移、變形、旋轉

本節介紹使用Matrix類實現圖形的平移、變形、旋轉。

5.8.1  Matrix類

Matrix類封裝了表示幾何變形的3行3列仿射矩陣,能夠記錄圖形的平移、變形、旋轉等操做。主要包括以下方法:

l 構造函數Matrix():建立一個空Matrix類對象。

l 方法Rotate:在Matrix類對象中增長相對於原點順時針旋轉指定角度的操做。參數指定旋轉角度。

l 方法RotateAt:在Matrix類對象中增長相對於指定點順時針旋轉指定角度的操做。參數1指定旋轉角度。參數2指定相應的點。

l 方法Scale:在X軸或Y軸方向對圖形放大或縮小。參數1指定在X軸方向縮放的值,參數2指定在Y軸方向縮放的值。

l 方法Translate:使圖形在X軸或Y軸方向移動。參數1指定在X軸方向移動的值,參數2指定在Y軸方向移動的值。

例子5_8_1:下面的示例建立了複合變形(先旋轉30度,再在y方向上縮放2倍,而後在x方向平移5個單位)的Matrix類對象。注意變形得順序很是重要。通常說來,先旋轉、再縮放、而後平移,與先縮放、再旋轉、而後平移是不一樣的。

Matrix myMatrix=new Matrix();

myMatrix.Rotate(30);

myMatrix.Scale(1,2,MatrixOrder.Append);

myMatrix.Translate(5,0,MatrixOrder.Append);

5.8.2    圖形的平移、變形、旋轉

GraphicsPath類的Transform方法能夠縮放、轉換、旋轉或扭曲GraphicsPath對象,參數Matrix對象表示須要的變形。

例子5_8_2A:下面的示例代碼執行下列操做:建立一個路徑並向該路徑添加一個橢圓。將路徑繪製到主窗體上。建立一個Matrix類對象,在對象中增長在X軸方向上將路徑移動100個單位操做。將該已變形的路徑繪製到屏幕。觀察一下變換前和變換後的不一樣,注意,初始橢圓是以黑色繪製的,而變形後的橢圓是以紅色繪製的。在Form1.cs文件的頭部增長語句:using System.Drawing.Drawing2D,主窗體Paint事件處理函數以下:

private void Form1_Paint(object sender,System.Windows.Forms.PaintEventArgs e)

{   GraphicsPath myPath=new GraphicsPath();//建立一個路徑

myPath.AddEllipse(0,0,50,70);//向路徑添加一個橢圓

e.Graphics.DrawPath(Pens.Black,myPath);//用黑筆畫出這個橢圓

Matrix translateMatrix=new Matrix();//建立一個Matrix類對象

translateMatrix.Translate(25,0);//在X軸方向上移動25個單位

//根據Matrix類對象修改路徑myPath

myPath.Transform(translateMatrix);

//用紅筆按新路徑畫這個橢圓

e.Graphics.DrawPath(new Pen(Color.Red,2),myPath);

}

運行效果如右圖。請讀者實現變形、旋轉。

5.8.3  仿射矩陣

m×n矩陣是以m行和n列排列的一組數字,例如一個3×3矩陣記爲以下圖形式,也可簡記爲:[a33]。

 

兩個行、列分別相同的矩陣能夠相加,例如:[a33]+[b33]=[c33],矩陣相加運算的規則是:ci j=ai j+bi j,i和j爲常量,即相對應位置的項相加。若是有矩陣[am n]和[bn k],[am n]矩陣的列數等於[bn k]矩陣的行數,兩個矩陣能夠相乘,記爲:[am n]*[bn k]=[cm k],矩陣相乘的運算的規則是:ci j=∑(ai t+bt j),其中,i和j爲常量,t爲變量,初始值爲1,最大值爲n。

若是將平面中的點視爲1×2矩陣,則可經過將該點乘以2×2變換矩陣來變形該點。下圖是點(2,1)在X軸按比例3放大,Y軸不變。

 

下圖表示點(2,1)旋轉了90度。

 

下圖表示點(2,1)以x軸爲對稱軸的新點。

 

假定要從點(2,1)開始,將其旋轉90度,在x方向將其平移3個單位,在y方向將其平移4個單位。可經過先使用矩陣乘法再使用矩陣加法來完成此操做。

 

若是用矩陣[2 1 1]表明點(2,1),使用一個3×3變換矩陣,能夠用一個矩陣乘法代替以上的兩個矩陣運算,見下圖:

 

注意運運結果的矩陣[2 6 1]表明點(2,6),即點(2,1)映射到了點(2,6)。這個3×3矩陣叫做仿射矩陣,Matrix類中用這個仿射矩陣記錄增長的各類變換操做。它和前邊的兩個2×2矩陣的關係以下圖,其中第三列固定爲0、0、1。

 

Matrix類增長了一些方法處理這個仿射矩陣,主要包括:逆轉方法Invert、相乘方法Multiply、重置爲單位矩陣方法Reset等。

5.9           圖形文件格式

在磁盤中存儲圖形和圖像的文件格式有多種。GDI+支持如下圖形文件格式。

l 位圖文件(.bmp):

位圖文件是Windows使用的一種標準格式,用於存儲設備無關和應用程序無關的圖像。BMP文件一般不壓縮,所以不太適合Internet傳輸。

l 可交換圖像文件格式(.gif):

GIF是一種用於在Web頁中顯示圖像的通用格式。GIF文件是壓縮的,可是在壓縮過程當中沒有信息丟失,解壓縮的圖像與原始圖像徹底同樣。GIF文件中的一種顏色能夠被指定爲透明,這樣,圖像將具備顯示它的任何Web頁的背景色。在單個文件中存儲一系列GIF圖像能夠造成一個動畫GIF。GIF文件每一個像素顏色最多用8位表示,因此它們只限於使用256種顏色。

l JPG文件(.jpg):

JPEG是聯合攝影專家組提出的一種適應於天然景觀(如掃描的照片)的壓縮方案。一些信息會在壓縮過程當中丟失,可是這些丟失人眼是察覺不到的。JPEG文件每像素顏色用24位表示,所以可以顯示超過16,000,000種顏色。JPEG文件不支持透明或動畫。JPEG圖像中的壓縮級別是能夠控制的,可是較高的壓縮級別(較小的文件)會致使丟失更多的信息。對於一幅以20:1壓縮比生成的圖像,人眼難以把它和原始圖像區別開來。JPEG是一種壓縮方案,不是一種文件格式。「JPEG文件交換格式(JFIF)」是一種文件格式,經常使用於存儲和傳輸根據JPEG方案壓縮的圖像。Web瀏覽器顯示的JFIF文件使用.jpg擴展名。

l 可移植網絡圖形(.PNG)

PNG格式不但保留了許多GIF格式的優勢,還提供了超出GIF的功能。像GIF文件同樣,PNG文件在壓縮時也不損失信息。PNG文件能以每像素八、24或48位來存儲顏色,並以每像素一、二、四、8或16位來存儲灰度。相比之下,GIF文件只能使用每像素一、二、4或8位。PNG文件還可爲每一個像素存儲一個透明度alpha值,該值指定了該像素顏色與背景顏色混合的程度。PNG優於GIF之處在於它可以逐漸顯示一幅圖像,也就是說,當圖像經過網絡鏈接到達時顯示將愈來愈近似。PNG文件可包含伽瑪校訂和顏色校訂信息,以便圖像可在各類各樣的顯示設備上精確地呈現。

l 圖元文件(.emf):

GDI+提供Metafile類,以便可以記錄和顯示圖元文件。圖元文件,也稱爲矢量圖像,是一種存儲爲一系列繪圖命令和設置的圖像。Metafile對象記錄的命令和設置能夠存儲在內存中或保存到文件或流。下面示例在主窗體顯示了一個圖元文件的圖形。

       Graphics g=this.CreateGraphics();

Metafile myMetafile=new Metafile("SampleMetafile.emf");

myGraphics.DrawImage(myMetafile,10,10);//圖形左上角的位置是(10,10)

l 支持的文件格式還有:圖標文件(.ico)、.EXIF、.TIFF、.ICON、.WMF等

5.10圖形框PictureBox控件

PictureBox控件經常使用於圖形設計和圖像處理程序,又稱爲圖形框,該控件可顯示和處理的圖像文件格式有:位圖文件(.bmp)、圖標文件(.ico)、GIF文件(.gif)和JPG文件(.jpg)。其經常使用的屬性、事件和方法以下:

l  屬性Image:指定要顯示的圖像,通常爲Bitmap類對象。

l  屬性SizeMode:指定如何顯示圖像,枚舉類型,默認爲Normal,圖形框和要顯示的圖像左上角重合,只顯示圖形框相同大小部分,其他不顯示;爲CentreImage,將圖像放在圖形框中間,四周多餘部分不顯示;爲StretchImage,調整圖像大小使之適合圖片框。

l  方法CreateGraphics():創建Graphics對象。

l  方法Invalidate():要求控件對參數指定區域重畫,如無參數,爲整個區域。

l  方法Update():方法Invalidate()並不能使控件當即重畫指定區域,只有使用Update()方法才能當即重畫指定區域。使用見5.10.4節中的鼠標移動事件處理函數。

例子e5_10使用PictureBox控件顯示圖像

(1)新建項目。放PictureBox控件到窗體。屬性Name=pictureBox1。

(2)放Button控件到窗體。屬性Name=button1。

(3)放OpenFileDialog控件到窗體。屬性Name=openFileDialog1。

(4)能夠在設計階段修改屬性Image爲指定圖形文件,設定初始顯示的圖像。

(5)button1控件事件處理函數以下:

private void button1_Click(object sender, System.EventArgs e)

{   if(openFileDialog1.ShowDialog()==DialogResult.OK)

{   Bitmap p1=new Bitmap(openFileDialog1.FileName);//Bitmap類見下節

pictureBox1.Image=p1;

}

}

5.11  Bitmap類

System.Drawing命名空間有一個類Image,用來處理圖像。Image類的派生類Bitmap類封裝了GDI+中的位圖,能夠處理由像素數據定義的圖像。Image類的派生類metafile處理元文件,此類文件用記錄繪圖命令的方法存儲圖像。

5.11.1    Bitmap類支持的圖像類型

使用Bitmap類能夠顯示和處理多種圖像文件,可處理的文件類型及文件擴展名以下:擴展名爲.bmp的位圖文件、擴展名爲.ico的圖標文件、擴展名爲.gif的GIF文件、擴展名爲.jpg的JPG文件。當使用構造函數Bitmap(string FileName)創建Bitmap類對象時,若是文件是以上類型,將自動轉換爲位圖格式存到Bitmap類對象中。可以使用Bitmap類方法Save(string FileName,ImageFormat imageFormat)把Bitmap類對象中的位圖存到文件中,其中第1個參數是選定的文件名,第2個參數是指定文件存爲那種類型,能夠是以下類型:System.Drawing.Imaging.ImageFormat.bmp(或.ico、.gif、.jpg)。

5.11.2    Bitmap類的方法

l  方法SetPixel():畫點方法,前2個參數是指定點的位置,第3個參數是顏色值。

l  方法GetPixle():獲得指定點的顏色,2個參數是指定點的位置,返回顏色值。

l  有多個構造函數例如:new Bitmap(」圖像文件名」),new Bitmap(寬,高)等。

l  方法Save():第1個參數是文件名,第2個參數是指定文件存爲那種類型,能夠是以下類型:System.Drawing.Imaging.ImageFormat.bmp(或.ico、.gif、.jpg)。

l  方法Dispose():釋放位圖對象

5.11.3    畫點

例子e5_11_3用SetPixel畫點,GetPixle獲得指定點的顏色。放Button和PictureBox控件到主窗體。增長Button控件單擊事件函數以下:

private void button1_Click(object sender,System.EventArgs e)

{   pictureBox1.Width=720;//設定pictureBox1的寬和高

pictureBox1.Height=110;

Bitmap bits=new Bitmap(720,110);//創建位圖對象,寬=720,高=110

int x,y;

for(x=0;x<720;x++)//畫正弦曲線

{   y=(int)(50+50*Math.Sin((3.14159/180.0)*x));

bits.SetPixel(x,y,Color.Red);

}

pictureBox1.Image=bits;//位圖對象在pictureBox1中顯示

Color c1=bits.GetPixel(20,20);

string s="R="+c1.R+",G="+c1.B+",G+"+c1.G;

MessageBox.Show(s);

}

5.11.4    在PictureBox中畫任意曲線

例子e5_11_4:例子5_7_1C實現了畫任意曲線程序,用ArrayList類對象記錄繪製的曲線。在該程序中增長橡皮功能、圖像的拷貝、圖像的剪貼、圖像的粘貼比較困難,也不能和畫圖程序交換文件。爲了實現這些功能,用圖形框(PictureBox控件)顯示繪製圖形。繪製圖形必須存在圖形框屬性Image引用的位圖對象中,圖形框顯示的圖像被破壞,圖形框響應Paint事件,將用其屬性Image引用的位圖對象恢復所繪製的圖形。僅將圖形繪製在圖形框表面,圖形框響應Paint事件,繪製的圖形將不能被恢復,也就是說,繪製在圖形框表面的圖形丟失了。具體實現步驟以下:

(1)    新建項目。增長4個私有變量:private bool mark=false;   private Point point;

private Bitmap bits;     private Graphics bitG;

(2)    放PictureBox控件到窗體,修改屬性Dock=Fill。

(3)    在構造函數中增長語句:

//創建位圖對象,寬和高爲指定值

bits=new Bitmap(pictureBox1.Width,pictureBox1.Height);

bitG=Graphics.FromImage(bits);//獲得位圖對象的Graphics類的對象

bitG.Clear(Color.White);//用白色清除位圖對象中的圖像

pictureBox1.Image=bits;//位圖對象在pictureBox1中顯示

(4)    爲控件PictureBox事件OnMouseDown,OnMouseUp,OnMouseMove增長事件處理函數:

private void pictureBox1_MouseDown(object sender,//鼠標按下事件處理函數

System.Windows.Forms.MouseEventArgs e)

{   if(e.Button==MouseButtons.Left)//是不是鼠標左鍵按下

{   point.X=e.X;

point.Y=e.Y;//畫線段開始點

mark=true;//鼠標左鍵按下標識

}

}

private void pictureBox1_MouseMove(object sender,//鼠標移動事件處理函數

System.Windows.Forms.MouseEventArgs e)

{   if(mark)//若是鼠標左鍵按下

{   Graphics g=pictureBox1.CreateGraphics();

Pen pen1=new Pen(Color.Black);

g.DrawLine(pen1,point.X,point.Y,e.X,e.Y);//圖形畫在PictureBox表面

bitG.DrawLine(pen1,point.X,point.Y,e.X,e.Y);//圖形畫在位圖對象bits中

EndPoint.X=e.X;

EndPoint.Y=e.Y;//下次繪製畫線段開始點

}

}

private void pictureBox1_MouseUp(object sender,

System.Windows.Forms.MouseEventArgs e)

{   mark=false;

pictureBox1.Image=bits;//保存了所畫的圖形

}

(5)    運行,在PictureBox控件拖動鼠標能夠畫線。最小化後再最大化後,圖形不消失。

5.11.5    存取位圖文件

例子e5_11_5:爲上例增長存取位圖文件功能。

(6)    把Mainmenu控件放到主窗體中。增長菜單:文件,屬性Name=menuItemFile。爲文件菜單增長菜單項:新建、打開、另存爲、退出,屬性Name分別爲menuItemNew、menuItemOpen、menuItemSaveAs、menuItemExit。

(7)    爲主窗體菜單項新文件增長單擊事件函數以下:

private void menuItemNew_Click(object sender, System.EventArgs e)

{   bitG.Clear(Color.White);//用白色清空位圖對象bitG

pictureBox1.Image=bits;//pictureBox1顯示用白色清空位圖對象bitG

}

(8)    把OpenFileDialog控件放到窗體中。爲主窗體菜單項打開文件增長單擊事件函數以下:

private void menuItemOpen_Click(object sender,System.EventArgs e)

{   if(openFileDialog1.ShowDialog(this)==DialogResult.OK)

{   bits.Dispose();//撤銷bitG所引用的對象

bits=new Bitmap(openFileDialog1.FileName);//創建指定文件的新位圖對象

bitG=Graphics.FromImage(bits);//獲得位圖對象使用的Graphics類對象

pictureBox1.Image=bits;

}

}

(9)    把SaveFileDialog控件放到子窗體中。爲主窗體菜單項另存爲增長單擊事件函數以下:

private void menuItemSaveAs_Click(object sender,System.EventArgs e)

{   if(saveFileDialog1.ShowDialog(this)==DialogResult.OK)

{   string s=saveFileDialog1.FileName+".bmp";

bits.Save(s,System.Drawing.Imaging.ImageFormat.Bmp);

}

}//也能夠存爲其它格式,例如:Jpg,Gif等。請讀者試一下。

(10)爲主窗體菜單項退出增長單擊事件函數以下:

private void menuItemExit_Click(object sender, System.EventArgs e)

{   Close();}

(11)運行,在PictureBox控件拖動鼠標能夠畫線。存所畫的圖形到文件,再從新讀出該文件,看是否正常運行。

5.11.6    用拖動鼠標方法畫橢圓或圓

例5_11_6:畫筆程序中,拖動鼠標方法畫橢圓或圓,拖動鼠標時顯示橢圓或圓的輪廓,鼠標擡起時,按指定條件畫橢圓或圓。若是圖形僅畫在圖形框(PictureBox控件)上,而不保存到其屬性Image引用的位圖對象中,當調用圖形框的Invalidate()方法,圖形框響應Paint事件,用圖形框屬性Image引用的位圖對象恢復圖像,將擦除僅畫在圖形框上的圖形。拖動鼠標方法畫橢圓或圓時,僅將橢圓或圓畫在PictureBox上,在鼠標拖動到下一個位置,用圖形框的Invalidate()方法將前一位置所畫的圖形擦除。實現步驟以下:

(1)    新建項目。增長5個私有變量:private bool mark=false;private Point StartPoint; private Bitmap bits;private Graphics bitG;private Point EndPoint;

(2)    放PictureBox控件到子窗體。修改屬性Dock=Fill。

(3)    在構造函數中增長語句:

//bits用來保存pictureBox1中位圖圖像

bits=new Bitmap(pictureBox1.Width,pictureBox1.Height);

bitG=Graphics.FromImage(bits);

bitG.Clear(Color.White);

pictureBox1.Image=bits;

(4)    在Form1類中增長MakeRectangle方法返回由參數指定的兩個點定義的矩形。方法以下:

private Rectangle MakeRectangle(Point p1,Point p2)

{   int top,left,bottom,right;

top=p1.Y<=p2.Y? p1.Y:p2.Y;//計算矩形左上角點的y座標

left=p1.X<=p2.X? p1.X:p2.X;//計算矩形左上角點的x座標

bottom=p1.Y>p2.Y? p1.Y:p2.Y;//計算矩形右下角點的y座標

right=p1.X>p2.X? p1.X:p2.X;//計算矩形右下角點的x座標

return(new Rectangle(left,top,right-left,bottom-top));//返回矩形

}

(5)    爲PictureBox事件OnMouseDown、OnMouseUp、OnMouseMove增長事件處理函數以下:

private void pictureBox1_MouseDown(object sender,//鼠標按下事件處理函數

System.Windows.Forms.MouseEventArgs e)

{   if(e.Button==MouseButtons.Left)

{   StartPoint.X=e.X;

StartPoint.Y=e.Y;

EndPoint.X=e.X;

EndPoint.Y=e.Y;

mark=true;

}

}

private void pictureBox1_MouseMove(object sender,//鼠標移動事件處理函數

System.Windows.Forms.MouseEventArgs e)

{   if(mark)

{   Rectangle r1=MakeRectangle(StartPoint,EndPoint);//計算重畫區域

r1.Height+=2;

r1.Width+=2;//區域增大些

pictureBox1.Invalidate(r1);//擦除上次鼠標移動時畫的圖形,r1爲擦除區域

pictureBox1.Update();//當即重畫,即擦除

Graphics g=pictureBox1.CreateGraphics();

Pen pen1=new Pen(Color.Black);

EndPoint.X=e.X;

EndPoint.Y=e.Y;

r1=MakeRectangle(StartPoint,EndPoint);//計算橢圓新位置

g.DrawEllipse(pen1,r1);//在新位置畫橢圓

}

}

private void pictureBox1_MouseUp(object sender,//鼠標擡起事件處理函數

System.Windows.Forms.MouseEventArgs e)

{   Pen pen1=new Pen(Color.Black);

EndPoint.X=e.X;

EndPoint.Y=e.Y;

Rectangle r1=MakeRectangle(StartPoint,EndPoint);

bitG.DrawEllipse(pen1,r1);

mark=false;

pictureBox1.Image=bits;

}

(6)    運行,在PictureBox控件中拖動鼠標能夠畫圓或橢圓。

5.12  圖像剪貼板功能

Windows中的許多程序都支持剪貼板功能。經過剪貼板能夠完成顯示數據的剪貼(Cut),複製(Copy),粘貼(Paste)等功能。剪貼板能夠理解爲一塊存儲數據的公共區域,用戶能夠用菜單項複製(Copy)或剪貼(Cut)把數據放入到剪貼板中,當本任務或其它任務要用剪貼板中的數據時,能夠用菜單項粘貼(Paste)從剪貼板中把數據取出。存入剪貼板中的數據,能夠是字符,位圖,或者其它格式數據。在圖形模式下使用剪貼板包括以下動做:選定剪貼區域、剪貼(Cut)、複製(Copy)、粘貼(Paste)等。使過畫圖程序的讀者都知道,在使用剪貼和複製前,必須首先選定剪貼或複製區域,首先按一個按鈕,通知程序要選定剪貼或複製區域,而後在要選定區域的左上角按下鼠標左鍵,拖動鼠標畫出一個矩形,擡起鼠標後顯示一個矩形既爲要選定剪貼或複製區域。剪貼或複製後,矩形自動消失。下面詳細介紹實現以上功能的方法。

5.12.1    剪貼區域選定

剪貼區域選定的方法和前邊章節中拖動鼠標方法繪製橢圓或圓的方法基本同樣,只是在這裏繪製的是矩形,並且在鼠標擡起時,不把矩形存入PictureBox控件屬性Image引用的位圖對象中,僅僅記錄矩形的位置。請讀者本身實現此功能。

5.12.2    剪貼板複製功能的實現

假定已選定剪貼區域,例如爲區域Rectangle(10,10,50,50),把此區域的圖形或圖像放到剪貼板中。具體實現步驟以下:

(1)    新建項目。放PictureBox控件到窗體,修改屬性Dock=Fill。屬性Name=pictureBox1,修改屬性Image,使其顯示一幅圖。

(2)    把Mainmenu控件放到主窗體中。增長頂級菜單項:編輯,屬性Name=menuItemEdit。爲編輯彈出菜單增長菜單項:複製、剪貼、粘貼。屬性Name分別爲menuItemCopy、menuItemCut、menuItemPaste。

(3)    爲窗體菜單項複製增長單擊事件函數以下:

private void menuItemCopy_Click(object sender, System.EventArgs e)

{   Bitmap myBitmap=new Bitmap(pictureBox1.Image);

Rectangle cloneRect=new Rectangle(10,10,50,50);

System.Drawing.Imaging.PixelFormat format=myBitmap.PixelFormat;

Bitmap cloneBitmap=myBitmap.Clone(cloneRect,format);

Clipboard.SetDataObject(cloneBitmap);

}

(4)    運行,選中複製菜單項,複製圖形到剪貼板。打開畫圖程序,選中畫圖程序粘貼菜單項,能夠看到被複制的圖形能正確粘貼到畫圖程序中。

5.12.3    剪貼板剪貼功能的實現

(5)    剪貼是先複製,再把選中區域圖形清除,菜單項剪貼單擊事件處理函數以下:

private void menuItemCut_Click(object sender,System.EventArgs e)

{   menuItemCopy_Click(sender,e);//調用複製菜單項單擊事件處理函數

Bitmap bits=new Bitmap(50,50);//創建位圖對象,寬和高爲選中區域大小

Graphics g=Graphics.FromImage(bits);//獲得位圖對象的Graphics類的對象

g.Clear(Color.White);//用白色清除位圖對象中的圖像

Bitmap myBitmap=new Bitmap(pictureBox1.Image);

g=Graphics.FromImage(myBitmap);

g.DrawImage(bits,10,10,50,50);

pictureBox1.Image=myBitmap;//位圖對象在pictureBox1中顯示,即清除

}

(6)    運行,選中剪貼菜單項,拷貝圖形到剪貼板,原位置圖形被清空爲白色,最小化後再最大化,圖形不變。打開畫圖程序,選中畫圖程序粘貼菜單項,能夠看到被拷貝的圖形能正確粘貼到畫圖程序中。

5.12.4    剪貼板粘貼功能的實現

(7)    爲窗體菜單項粘貼增長單擊事件函數以下:

private void menuItemPaste_Click(object sender, System.EventArgs e)

{   IDataObject iData=Clipboard.GetDataObject();//獲得剪貼板對象

if(iData.GetDataPresent(DataFormats.Bitmap))//判斷剪貼板有無位圖對象

{   Bitmap bits=(Bitmap)iData.GetData(DataFormats.Bitmap);//獲得剪貼板位圖

Bitmap myBitmap=new Bitmap(pictureBox1.Image);

Graphics g=Graphics.FromImage(myBitmap);

g.DrawImage(bits,30,30);

pictureBox1.Image=myBitmap;//位圖對象在pictureBox1中顯示

}

}

(8)     運行畫圖程序,選中拷貝菜單項,拷貝圖形到剪貼板。運行本身編制的程序,選中粘貼菜單項,能夠看到畫圖程序中被拷貝的圖形能正確粘貼到本身編制的程序中。

(9)    畫圖程序粘貼後,能用鼠標移動粘貼的圖形,現實現此功能。放PictureBox控件到窗體,屬性Name=pictureBox2,屬性Visable=false。這裏把粘貼後的圖形放到PictureBox2中,使其能夠移動。爲Form1類增長變量:bool mark=false;int x=0,y=0;爲pictureBox2控件的事件OnMouseDown,OnMouseUp,OnMouseMove增長事件函數以下:

private void pictureBox2_MouseDown(object sender,

System.Windows.Forms.MouseEventArgs e)

{   mark=true;

x=e.X;

y=e.Y;

}

private void pictureBox2_MouseMove(object sender,

System.Windows.Forms.MouseEventArgs e)

{   if(mark)

{   int x1,y1;

x1=e.X-x;

y1=e.Y-y;

pictureBox1.Invalidate();//擦除上次鼠標移動時畫的圖形

pictureBox1.Update();//當即重畫,即擦除

pictureBox2.Left+=x1;

pictureBox2.Top+=y1;

x=e.X;//原來沒有此2句

y=e.Y;

}

}

private void pictureBox2_MouseUp(object sender,

System.Windows.Forms.MouseEventArgs e)

{   mark=false;}

(10)修改窗體菜單項粘貼單擊事件函數以下:

private void menuItemPaste_Click(object sender,System.EventArgs e)

{   IDataObject iData=Clipboard.GetDataObject();

if(iData.GetDataPresent(DataFormats.Bitmap))

{   Bitmap bit=(Bitmap)iData.GetData(DataFormats.Bitmap);

pictureBox2.Width=bit.Width;//陰影爲修改部分

pictureBox2.Height=bit.Height;

pictureBox2.Image=bit;

pictureBox2.Top=pictureBox1.Top;

pictureBox2.Left=pictureBox1.Left;

pictureBox2.Parent=pictureBox1;

pictureBox2.Visible=true;

}

}

(11)在pictureBox1控件任意位置單擊鼠標,表示已將粘貼圖像拖到指定位置,需將粘貼圖像粘貼到pictureBox1控件。爲pictureBox1控件的事件OnMouseDown增長事件函數以下:

private void pictureBox1_MouseDown(object sender,

System.Windows.Forms.MouseEventArgs e)

{   if(pictureBox2.Image!=null&&pictureBox2.Visible)

{   Bitmap bits=new Bitmap(pictureBox2.Image);

Bitmap myBitmap = new Bitmap(pictureBox1.Image);

Graphics g=Graphics.FromImage(myBitmap);

g.DrawImage(bits,pictureBox2.Left,pictureBox2.Top);

pictureBox1.Image=myBitmap;//位圖對象在pictureBox1中顯示

pictureBox2.Visible=false;

}

}

(12)運行畫圖程序,選中拷貝菜單項,拷貝圖形到剪貼板。運行本身編制的程序,選中粘貼菜單項,能夠看到畫圖程序中被拷貝的圖形能正確粘貼到本身編制的程序中。拖動被拷貝的圖形,使其運動到指定位置,在pictureBox2外,單擊鼠標右鍵,圖形固定到指定位置。

5.13  圖像的處理

本節介紹圖像的處理的最基礎知識,要想深刻了解這方面的知識,還要讀這方面的專著。

5.13.1    圖像的分辨力

例子e5.13.1:將原圖形的分辨率下降16倍,其方法是將原圖形分紅4*4的圖形塊,這16個點的顏色都置成這16個點中某點的顏色,例如4*4的圖形塊左上角的顏色。

(1)    新建項目。放兩個PictureBox控件到窗體,屬性Name分別爲pictureBox1,pictureBox2,修改pictureBox1屬性Image,使其顯示一幅圖。

(2)    放Button控件到窗體,爲其增長事件處理函數以下:

private void button1_Click(object sender,System.EventArgs e)

{   Color c;

int i,j,size,k1,k2,xres,yres;

xres=pictureBox1.Image.Width;//pictureBox1顯示的圖像的寬

yres=pictureBox1.Image.Height;//pictureBox1顯示的圖像的高

size=4;

pictureBox2.Width=xres;//令pictureBox2和pictureBox1同寬,同高。

pictureBox2.Height=yres;

Bitmap box1=new Bitmap(pictureBox1.Image);

Bitmap box2=new Bitmap(xres,yres);

for(i=0;i<=xres-1;i+=size)

{   for(j=0;j<=yres-1;j+=size)

{   c=box1.GetPixel(i,j);

for(k1=0;k1<=size-1;k1++)

{   for(k2=0;k2<=size-1;k2++)

box2.SetPixel(i+k1,j+k2,c);

}

}

}

pictureBox2.Image=box2;

}

(3)    運行,單擊按鈕,在PictureBox2中能夠看到分別率低的圖形。

5.13.2    彩色圖像變換爲灰度圖像

例子e5.13.2:本例把彩色圖像變換爲灰度圖像。其方法是將原彩色圖形每個點的顏色取出,求出紅色、綠色、藍色份量的平均值,即(紅色+綠色+藍色)/3,做爲這個點的紅色、綠色、藍色份量,這樣就把彩色圖像變成了灰度圖像。具體步驟以下:

(1)    新建項目。放兩個PictureBox控件到窗體,屬性Name分別爲pictureBox1,pictureBox2,修改pictureBox1屬性Image,使其顯示一幅圖。

(2)    放Button控件到窗體,爲其增長事件函數以下:

private void button1_Click(object sender, System.EventArgs e)

{   Color c;

int i,j,xres,yres,r,g,b;

xres=pictureBox1.Image.Width;

yres=pictureBox1.Image.Height;

pictureBox2.Width=xres;

pictureBox2.Height=yres;

Bitmap box1=new Bitmap(pictureBox1.Image);

Bitmap box2=new Bitmap(xres,yres);

for(i=0;i<xres;i++)

{   for(j=0;j<yres;j++)

{   c=box1.GetPixel(i,j);

r=c.R;

g=c.G;

b=c.B;

r=(r+g+b)/3;

c=Color.FromArgb(r,r,r);

box2.SetPixel(i,j,c);

}

}

pictureBox2.Image=box2;

}

(3)    運行,單擊按鈕,在PictureBox2中能夠看到黑白圖形。

5.13.3    灰度圖像處理

例子e5.13.3:將一幅灰度圖像變換爲另外一幅灰度圖像,兩幅灰度圖形的灰度知足以下關係:設圖1和圖2的灰度分別爲d1和d2,如d1<85,d2=0;如85<=d1<=170,d2=(d1-85)*3;如d1>170,d2=255。變換的效果是加強了對比度。具體步驟以下:

(1)    新建項目。放兩個PictureBox控件到窗體,屬性Name分別爲pictureBox1,pictureBox2,修改pictureBox1屬性Image,使其顯示一黑白幅圖。

(2)    放Button控件到窗體,爲其增長事件函數以下:

private void button1_Click(object sender, System.EventArgs e)

{   Color c;

int i,j,xres,yres,m;

xres=pictureBox1.Image.Width;

yres=pictureBox1.Image.Height;

pictureBox2.Width=xres;

pictureBox2.Height=yres;

Bitmap box1=new Bitmap(pictureBox1.Image);

Bitmap box2=new Bitmap(xres,yres);

int[] lut=new int[256];

for(i=0;i<85;i++)

lut[i]=0;

for(i=85;i<=170;i++)

lut[i]=(i-85)*3;

for(i=171;i<256;i++)

lut[i]=255;

for(i=0;i<xres;i++)

{   for(j=0;j<yres;j++)

{   c=box1.GetPixel(i,j);

m=lut[c.R];

c=Color.FromArgb(m,m,m);

box2.SetPixel(i,j,c);

}

}

pictureBox2.Image=box2;

}

(3)    運行,單擊按鈕,在PictureBox2中能夠看到對比度加強的黑白圖形。

5.13.4    動畫

學習了以上知識,製做一些簡單動畫是比較容易的。例如,若是一段動畫,要求一個動畫小人從窗體左側走到右側,如何實現呢?首先,爲了看到人在走動,應該有3個動做:右腳在前,左腳在後;兩腳並排;左腳在前,右腳在後。所以應制做3幅圖畫,表示這三個動做。每當轉換一幅圖畫,圖畫應在X軸方向右移一步的距離。將3幅圖畫放到3個PictureBox控件中,用定時器產生中斷,中斷處理程序負責使其中一幅圖畫顯示,其他兩幅不顯示,同時,修改PictureBox控件屬性Left,使其在正確的位置上。這樣就能夠看到人的走動了。請讀者本身完成這段動畫。

習題

(1)使用PictureBox控件顯示圖像,修改屬性SizeMode爲不一樣值,例如pictureBox1.SizeMode=PictureBoxSizeMode.StretchImage看一下效果。

(2)  實現畫圖程序的橡皮功能。

(3)  有時爲了很快找到一幅圖像,把不少圖像都壓縮後在窗體中並排顯示,如但願更仔細的查看某幅圖像,單擊這幅壓縮圖像,放大這幅圖像。請實現此功能。

(4)  實現設定剪貼板剪貼區域爲矩形的功能。

(5)  實現設定剪貼板剪貼區域爲任意封閉曲線的功能。(提示:使用GraphicsPath類)

(6)  如何將PictureBox控件顯示圖像存爲其它格式文件,例如:Jpg,Gif等。

(7)  完成5.11.4所要求的動畫,並能走到窗體右邊界後,從右向左走回來,到左邊界後,再向右走回去。若是有背景,如何處理。

(8)  製做本身的畫圖程序,看一看能完成那些功能。

(9)  有些時候,爲突出圖形的分界,例如醫院的X片時黑白的,爲了使醫生能更清楚的看到腫瘤,將黑白圖形變爲彩色的圖形,在分界兩側用不一樣顏色表示,這種方法叫僞彩色。實現的原理,就是在黑白圖像灰度變化很大處,認爲是邊界。試一下,可否實現黑白圖像的僞彩色。

 

 

第六章       文件和流

編程語言在如何處理輸入/輸出問題方面已經通過了不少變革。早期語言,例如Basic語言,使用I/O語句。後來的語言,例如C語言,使用標準的I/O庫(stdio.h)。在C++和Java語言中,引入了抽象的概念:流。流的概念不只可用於文件系統,也可用於網絡。但在C++和Java語言中流的概念比較複雜。C#語言也採用了流的概念,可是使用起來要簡單的多。本章介紹C#語言中,如何處理目錄和文件夾,如何處理文件,如何使用流的概念讀寫文件。

6.1   用流讀寫文件

C#把每一個文件都當作是順序的字節流,用抽象類Stream表明一個流,能夠從Stream類派生出許多派生類,例如FileStream類,負責字節的讀寫,BinaryRead類和BinaryWrite類負責讀寫基本數據類型,如bool、String、int1六、int等等,TextReader類和TextWriter類負責文本的讀寫。本節介紹這些類的用法。

6.1.1   用FileStream類讀寫字節

寫字節代碼段以下:

byte[] data=new byte[10];

For(int i=0;i<10;i++)

data[i]=(byte)i;

System.IO.FileStream fs=new System.IO.FileStream("g1",FileMode.OpenOrCreate);

fs.Write(data,0,10);

讀字節代碼段以下:

byte[] data=new byte[10];

System.IO.FileStream fs=new System.IO.FileStream("g1",FileMode.OpenOrCreate);

fs.Seek(-5,SeekOrigin.End);

int n=fs.Read(data,0,10);//n爲所讀文件字節數

6.1.2   用BinaryReader和BinaryWriter類讀寫基本數據類型

C#中除了字節類型之外,還有許多其它基本數據類型,例如,int、bool、float等等,讀寫這些基本數據類型須要使用BinaryReader和BinaryWriter類。寫int類型數據代碼段以下:

System.IO.FileStream fs=new System.IO.FileStream("g1",FileMode.OpenOrCreate);

System.IO.BinaryWrite w=new System.IO. BinaryWrite(fs);

For(int i=0;i<10;i++)

w.Write(i);

w.Close();

讀int類型數據代碼段以下:

int[] data=new int[10];

System.IO.FileStream fs=new System.IO.FileStream("g1",FileMode.OpenOrCreate);

System.IO.BinaryReader r=new System.IO. BinaryReader(fs);

For(int i=0;i<10;i++)

data[i]=r.ReadInt();

r.Close();

6.1.3   用StreamReader和StreamWriter類讀寫字符串

讀寫字符串能夠用StreamReader和StreamWriter類。寫字符串類型數據代碼段以下:

System.IO.FileStream fs=new System.IO.FileStream("g1",FileMode.OpenOrCreate);

System.IO.StreamWrite w=new System.IO.StreamWrite(fs);

w.Write(100);

w.Write("100個");

w.Write("End of file");

w.Close();

讀字符串代碼段以下:

String[] data=new String[3];

System.IO.FileStream fs=new System.IO.FileStream("g1",FileMode.OpenOrCreate);

System.IO.StreamReader r=new System.IO.StreamReader(fs);

For(int i=0;i<3;i++)

data[i]=r.ReadLine();

r.Close();

6.2   File類和FileInfo類

C#語言中經過File和FileInfo類來建立、複製、刪除、移動和打開文件。在File類中提供了一些靜態方法,使用這些方法能夠完成以上功能,但File類不能創建對象。FileInfo類使用方法和File類基本相同,但FileInfo類能創建對象。在使用這兩個類時須要引用System.IO命名空間。這裏重點介紹File類的使用方法。

6.2.1   File類經常使用的方法

l  AppendText:返回StreamWrite,向指定文件添加數據;如文件不存在,就建立該文件。

l  Copy:複製指定文件到新文件夾。

l  Create:按指定路徑創建新文件

l  Delete:刪除指定文件。

l  Exists:檢查指定路徑的文件是否存在,存在,返回true。

l  GetAttributes:獲取指定文件的屬性。

l  GetCreationTime:返回指定文件或文件夾的建立日期和時間。

l  GetLastAccessTime:返回上次訪問指定文件或文件夾的建立日期和時間。

l  GetLastWriteTime:返回上次寫入指定文件或文件夾的建立日期和時間。

l  Move:移動指定文件到新文件夾。

l  Open:返回指定文件相關的FileStream,並提供指定的讀/寫許可。

l  OpenRead:返回指定文件相關的只讀FileStream。

l  OpenWrite:返回指定文件相關的讀/寫FileStream。

l  SetAttributes:設置指定文件的屬性。

l  SetCretionTime:設置指定文件的建立日期和時間。

l  SetLastAccessTime:設置上次訪問指定文件的日期和時間。

l  SetLastWriteTime:設置上次寫入指定文件的日期和時間。

下面經過程序實例來介紹其主要方法:

6.2.2   文件打開方法:File.Open

該方法的聲明以下:public static FileStream Open(string path, FileMode mode)。下面的代碼打開存放在c:\Example目錄下名稱爲e1.txt文件,並在該文件中寫入hello。

FileStream TextFile=File.Open(@"c:\ Example\e1.txt",FileMode.Append);

byte [] Info={(byte)'h',(byte)'e',(byte)'l',(byte)'l',(byte)'o'};

TextFile.Write(Info,0,Info.Length);

TextFile.Close();

6.2.3   文件建立方法:File.Create

該方法的聲明以下:public static FileStream Create(string path)。下面的代碼演示如何在c:\Example下建立名爲e1.txt的文件。

FileStream NewText=File.Create(@"c:\Example\e1.txt");

NewText.Close();

6.2.4   文件刪除方法:File.Delete

該方法聲明以下:public static void Delete(string path)。下面的代碼演示如何刪除c:\Example目錄下的e1.txt文件。

File.Delete(@"c:\Example\e1.txt");

6.2.5   文件複製方法:File.Copy

該方法聲明以下:

public static void Copy(string sourceFileName,string destFileName,bool overwrite);

下面的代碼將c:\Example\e1.txt複製到c:\Example\e2.txt。因爲Cope方法的OverWrite參數設爲true,因此若是e2.txt文件已存在的話,將會被複制過去的文件所覆蓋。

File.Copy(@"c:\Example\e1.txt",@"c:\Example\e2.txt",true);

6.2.6   文件移動方法:File.Move

該方法聲明以下:public static void Move(string sourceFileName,string destFileName);下面的代碼能夠將c:\Example下的e1.txt文件移動到c盤根目錄下。注意:只能在同一個邏輯盤下進行文件轉移。若是試圖將c盤下的文件轉移到d盤,將發生錯誤。

File.Move(@"c:\Example\BackUp.txt",@"c:\BackUp.txt");

6.2.7   設置文件屬性方法:File.SetAttributes

方法聲明以下:public static void SetAttributes(string path,FileAttributes fileAttributes);下面的代碼能夠設置文件c:\Example\e1.txt的屬性爲只讀、隱藏。

File.SetAttributes(@"c:\Example\e1.txt",

FileAttributes.ReadOnly|FileAttributes.Hidden);

文件除了經常使用的只讀和隱藏屬性外,還有Archive(文件存檔狀態),System(系統文件),Temporary(臨時文件)等。關於文件屬性的詳細狀況請參看MSDN中FileAttributes的描述。

6.2.8   判斷文件是否存在的方法:File.Exist

該方法聲明以下:public static bool Exists(string path);下面的代碼判斷是否存在c:\Example\e1.txt文件。

if(File.Exists(@"c:\Example\e1.txt"))//判斷文件是否存在

{…}//處理代碼

6.2.9   獲得文件的屬性

用下面的代碼能夠獲得文件的屬性,例如文件建立時間、最近訪問時間、最近修改時間等等。

FileInfo fileInfo=new FileInfo(「file1.txt」);

string s=fileInfo.FullName+」文件長度=」+fileInfo.Length+」,創建時間=」+ fileInfo.CreationTime+」;

也可用以下代碼:

string s=」創建時間=」+File.File.GetCreationTime(「file1.txt」)+」最後修改時間=」+ File.GetLastWriteTime(「file1.txt」)+」訪問時間=」+File.GetLastAccessTime(「file1.txt」);

6.3   Directory類和DirectoryInfo類

C#語言中經過Directory類來建立、複製、刪除、移動文件夾。在Directory類中提供了一些靜態方法,使用這些方法能夠完成以上功能。但Directory類不能創建對象。DirectoryInfo類使用方法和Directory類基本相同,但DirectoryInfo類能創建對象。在使用這兩個類時須要引用System.IO命名空間。這裏重點介紹Directory類的使用方法。

6.3.1   Directory類經常使用的方法以下:

l  CreateDirectory:按指定路徑建立全部文件夾和子文件夾。

l  Delete:刪除指定文件夾。

l  Exists:檢查指定路徑的文件夾是否存在,存在,返回true。

l  GetCreationTime:返回指定文件或文件夾的建立日期和時間。

l  GetCurrentDirectory:獲取應用程序的當前工做文件夾。

l  GetDirectories:獲取指定文件夾中子文件夾的名稱。

l  GetDirectoryRoot:返回指定路徑的卷信息、根信息或二者同時返回。

l  GetFiles:返回指定文件夾中子文件的名稱。

l  GetFileSystemEntries:返回指定文件夾中全部文件和子文件的名稱。

l  GetLastAccessTime:返回上次訪問指定文件或文件夾的建立日期和時間。

l  GetLastWriteTime:返回上次寫入指定文件或文件夾的建立日期和時間。

l  GetLogicalDrives:檢索計算機中的全部驅動器,例如A:、C:等等。

l  GetParent:獲取指定路徑的父文件夾,包括絕對路徑和相對路徑。

l  Move:將指定文件或文件夾及其內容移動到新位置。

l  SetCreationTime:設置指定文件或文件夾的建立日期和時間。

l  SetCurrentDirectory:將應用程序的當前工做文件夾設置指定文件夾。

l  SetLastAccessTime:設置上次訪問指定文件或文件夾的日期和時間。

l  SetLastWriteTime:設置上次寫入指定文件夾的日期和時間。

6.3.2   目錄建立方法:Directory.CreateDirectory

方法聲明以下:public static DirectoryInfo CreateDirectory(string path);下面的代碼演示在c:\Dir1文件夾下建立名爲Dir2子文件夾。

Directory.CreateDirectory(@"c:\Dir1\Dir2");

6.3.3   目錄屬性設置方法:DirectoryInfo.Atttributes

下面的代碼設置c:\Dir1\Dir2目錄爲只讀、隱藏。與文件屬性相同,目錄屬性也是使用FileAttributes來進行設置的。

DirectoryInfo DirInfo=new DirectoryInfo(@"c:\Dir1\Dir2");

DirInfo.Atttributes=FileAttributes.ReadOnly|FileAttributes.Hidden;

6.3.4   目錄刪除方法:Directory.Delete

該方法聲明以下:public static void Delete(string path,bool recursive);下面的代碼能夠將c:\Dir1\Dir2目錄刪除。Delete方法的第二個參數爲bool類型,它能夠決定是否刪除非空目錄。若是該參數值爲true,將刪除整個目錄,即便該目錄下有文件或子目錄;若爲false,則僅當目錄爲空時纔可刪除。

Directory.Delete(@"c:\Dir1\Dir2",true);

6.3.5   目錄移動方法:Directory.Move

該方法聲明以下:public static void Move(string sourceDirName,string destDirName);下面的代碼將目錄c:\Dir1\Dir2移動到c:\Dir3\Dir4。

File.Move(@"c:\Dir1\Dir2",@"c:\Dir3\Dir4");}

6.3.6   獲取當前目錄下全部子目錄:Directory.GetDirectories

該方法聲明以下:public static string[] GetDirectories(string path;);下面的代碼讀出c:\Dir1\目錄下的全部子目錄,並將其存儲到字符串數組中。

string [] Directorys;

Directorys = Directory. GetDirectories (@"c:\Dir1");

得到全部邏輯盤符:

string[] AllDrivers=Directory.GetLogicalDrives();

6.3.7   獲取當前目錄下的全部文件方法:Directory.GetFiles

該方法聲明以下:public static string[] GetFiles(string path;);下面的代碼讀出c:\Dir1\目錄下的全部文件,並將其存儲到字符串數組中。

string [] Files;

Files = Directory. GetFiles (@"c:\Dir1",);

6.3.8   判斷目錄是否存在方法:Directory.Exist

該方法聲明以下:public static bool Exists(string path;);下面的代碼判斷是否存在c:\Dir1\Dir2目錄。

if(File.Exists(@"c:\Dir1\Dir2"))//判斷目錄是否存在

{…}//處理語句

注意:路徑有3種方式,當前目錄下的相對路徑、當前工做盤的相對路徑、絕對路徑。以C:\dir1\dir2爲例(假定當前工做目錄爲C:\Tmp)。「dir2」,「\dir1\dir2」,「C:\dir1\dir2」都表示C: \dir1\dir2。另外,在C#中 「\」是特殊字符,要表示它的話須要使用「\\」。因爲這種寫法不方便,C#語言提供了@對其簡化。只要在字符串前加上@便可直接使用「\」。因此上面的路徑在C#中應該表示爲」dir2」,@」\dir1\dir2」,@」C:\dir1\dir2」。

6.4   例子:查找文件

6.4.1   Panel和ListView控件

 

6.4.2   在指定文件夾中查找文件

Windows操做系統提供了一個查找文件的程序,能夠查找指定文件夾中的指定文件,本例也實現了一樣的功能。具體實現步驟以下:

(1)    新建項目。

(2)    放Panel控件到窗體,屬性Dock=Left。Panel控件能夠把窗體分割爲多個部分,這裏將窗體分割爲左右兩部分。

(3)    在Panel控件中增長兩個Label控件,屬性Text分別爲」要搜索的文件或文件夾」和」搜索範圍」。

(4)    在Panel控件中增長一個TextBox控件,屬性Name=textBox1,屬性Text爲空,用來輸入要搜索的文件或文件夾。

(5)    在Panel控件中增長一個TextBox控件,屬性Name=textBox2,屬性Text爲空,用來輸入搜索範圍。在其後增長一個Button控件,屬性Name=Broswer,屬性Text=」瀏覽」。

(6)    爲」瀏覽」按鈕增長事件函數以下:

private void Broswer_Click(object sender, System.EventArgs e)

{

OpenFileDialog dlg=new OpenFileDialog();

if(dlg.ShowDialog()==DialogResult.OK)

{

textBox2.Text=dlg.FileName;

}

}

(7)    在Panel控件中增長一個Button控件,屬性Name分別爲Start和Stop,屬性Text分別爲」開始搜索」和」中止搜索」。

(8)    放分割器控件Splitter到窗體,屬性Dock=Left。

(9)    在分割器控件右側放置視圖控件ListView,屬性Dock=Right,屬性SmallImgeList =」imageList」,屬性View=」Detail」。點擊屬性Column右側標題爲…的按鈕,在彈出的ColumnHeader編輯對話框中添加4個列頭,屬性Name分別爲:FileName、FileDirectory、FileSize和LastWriteTime,屬性Text分別爲:名稱、所在文件夾、大小和修改時間。

(10)爲窗體增長一個方法:FindFiles(DirectoryInfo dir,string FileName),該方法是在第一個參數指定的文件夾中查找第二個參數指定的全部文件。在一個文夾中可能還有子文件夾,子文件夾中可能還有子文件夾,所以要在第一個參數指定的文件夾中和其子文件夾中查找第二個參數指定的全部文件。爲了實現可以查找全部文件夾中的同名文件,採用遞歸調用方法,若是在一個文件夾中存在子文件夾,在一次調用函數本身,查找子文件夾中的文件。具體實現代碼以下:

void FindFiles(DirectoryInfo dir,string FileName)

{

 FileInfo[] files=dir.GetFiles(FileName);//查找全部文件並在ListView中顯示

 If(files.Length!=0)

 {

   foreach(FileInfo aFile in files)

   {

ListViewItem lvi;

lvi=new ListViewItem(aFile.Name,aFile.Directory.FullName,aFile.Length.ToString, aFile.LastWriteTime.ToShortDateString());

lvi.ImageIndex=0;

listView1.Items.Add(lvi);

   }

 }

   DirectoryInfo[] dirs=dir.GetDirectories();//查找子文件夾中的匹配文件

   If(dirs.Length!=0)

   {

foreach(DirectoryInfo aDir in dirs)

{

   FindFiles(aDir,FileName);

}

   }

}

(11)爲」開始搜索」按鈕增長事件函數以下:

private void Start_Click(object sender, System.EventArgs e)

{

 DirectoryInfo aDir=CreateDirectorie(comboBox1.Text);

 FindFiles(aDir,textBox1.Text);

}

(12)爲」中止搜索」按鈕增長事件函數以下:

private void Stop_Click(object sender, System.EventArgs e)

{

}

(13)編譯、運行,

6.5   例子:拆分和合並文件

在將一個文件做爲電子郵件的附件傳送時,因爲附件的大小有限制,能夠將較大的文件分割爲較小的多個文件,傳送後再合併爲一個文件,下邊兩個方法實現文件的拆分和合並。首先是拆分方法,參數1時要拆分的文件名,參數2是拆分後的文件名,文件名後邊由拆分方法自動增長序號,參數3是被拆分後的文件大小。拆分方法定義以下:

void SplitFile(string f1,string f2,int f2Size)

{

FileStream inFile=new FileStream(f1,FileMode.OpenOrCreate,FileAccess.Read);

bool mark=true;

int i=0;

int n=0;

byte[] buffer=new byte[f2Size];

while(mark)

{

FileStream OutFile=new FileStream(f2+i.ToString+」.fsm」,

FileMode.OpenOrCreate,FileAccess.Read);

if((n=inFile.Read(buffer,0,f2Size))>0)

{

OutFile.Write(buffer,0,n);

i++;

OutFile.Close();

}

else

{

mark=false;

}

}

inFile.Close();

}

合併文件方法,參數1時要合併的文件名,參數2是被拆分的文件名,文件名後邊有序號,要將這些文件合併到一塊兒,參數3是要合併的文件數。合併方法定義以下:

void MergeFile(string f1,string f2,int f2Num)

{

FileStream OutFile=new FileStream(f1,FileMode.OpenOrCreate,FileAccess.Write);

int n,l;

for(int i=0;i<f2Num;i++)

{

FileStream InFile=new

FileStream(f2+i.ToString+」.fsm」,FileMode.OpenOrCreate,FileAccess.Read);

l=InFile.Length;

byte[] buffer=new byte[l];

n=inFile.Read(buffer,0,l);

OutFile.Write(buffer,0,n);

InFile.Close();

}

OutFile.Close();

}

習題:

(1)  實現拆分和合並文件的完整程序。

 

 

第七章       多線程程序設計

若是在一個程序中,有多個工做要同時作,能夠採用多線程。在Windows操做系統中能夠運行多個程序,把一個運行的程序叫作一個進程。一個進程又能夠有多個線程,每一個線程輪流佔用CPU的運算時間,Windows操做系統將時間分爲許多個時間片,一個線程使用一個時間片後,操做系統將此線程掛起,將另外一個線程喚醒,使其使用下一個時間片,操做系統不斷的把線程掛起,喚醒,再掛起,再喚醒,如此反覆,因爲如今CPU的速度比較快,給人的感受象是多個線程同時執行。Windows操做系統中有不少這樣的例子,例如複製文件時,一方面在進行磁盤的讀寫操做,同時一張紙不停的從一個文件夾飄到另外一個文件夾,這個飄的動做其實是一段動畫,兩個動做是在不一樣線程中完成的,也就是說兩個動做是同時完成的。又如Word程序中的拼寫檢查也是在另外一個線程中完成的。每一個進程最少有一個線程,叫主線程,是進程自動建立的,每進程能夠建立多個線程。

不一樣語言和操做系統對線程提供了不一樣支持,編寫多線程應用程序的方法也不盡相同。例如,VB6沒有提供對線程的支持,程序員不能處理本身的線程。VC++6.0開發人員必須充分理解Windows線程和處理模型的複雜性,同時擁有這種線程模型的強大功能。C++程序員能夠建立出多線程程序,但必須學習掌握不少複雜的技巧,以確保線程在本身的控制之下。

.NET Framework提供了一個完整而功能強大的線程模型,該模型容許編程人員精確控制線程中運行的內容,線程什麼時候退出,以及它將訪問多少數據等。因此,在.NET中,既提供了C++的強大功能,又具備VB6的簡單性。

7.1   線程類(Thread)的屬性和方法

線程類在命名空間System..Threading中定義的,所以若是要建立多線程,必須引入命名空間System..Threading。Thread類的經常使用方法以下:

l  屬性ThreadPriority:設置線程優先級,有5種優先級類別:(AboveNormal)稍高、(BelowNormal)稍低、Normal(中等,默認值)、Highest(最高)和Lowest(最低)。

l  構造函數:new Thread(new ThreadStart(線程首先執行的方法名)),構造方法參數中指定的方法須要程序員本身定義,在這個方法中完成線程要完成的任務,退出該方法,線程結束。該方法必須爲公有void類型的方法,不能有參數。

l  方法Start():創建線程類對象後,線程並不能自動運行,用這個方法啓動線程。

l  方法IsAlive():判斷線程對象是否存在,=true,存在。

l  方法Abort():撤銷線程對象。不能撤銷一個已不存在的線程對象,所以在撤銷一個線程對象前,必須用方法IsAlive()判斷線程對象是否存在。

l  方法Sleep():參數爲毫秒,線程暫時中止參數指定的時間,容許其它線程運行。

l  方法Suspend():線程掛起。如只是暫時中止線程的運行,可用此函數將線程掛起。必須用Resume()方法喚醒線程。

l  方法Resume():恢復掛起線程。如但願繼續運行掛起線程,可用此方法喚醒線程。須要注意的是,若是線程屢次被掛起,調用一次Resume()方法就能夠把線程喚醒。

7.2   線程的建立

例子:多線程程序設計,該程序包括一個子線程,在標籤控件中顯示子線程運行的時間。增長4個按鈕,分別單擊按鈕,能夠創建、掛起、恢復和中止線程。

(1)                           新建項目。在窗體中放置4個按鈕和一個標籤控件,屬性Name分別爲button一、button二、button三、button4和label1,按鈕屬性Text分別爲新線程、掛起、恢復和撤銷。button1屬性Enabled=true,其他按鈕的屬性Enabled=false。

(2)                           在Form1.cs頭部增長語句:using System.Threading。

(3)                           爲Form1類定義一個線程類變量:private Thread thread;

(4)                           爲新線程按鈕(button1)增長單擊事件函數以下:

thread= new Thread(new ThreadStart(fun);//生成線程類對象

label1.Text=」0」;

thread.Start();

button1.Enabled=false;

button2.Enabled=true;

button3.Enabled=false;

button4.Enabled=true;

(5)                           爲掛起按鈕(button2)增長單擊事件函數以下:

thread. Suspend();

button1.Enabled=false;

button2.Enabled=false;

button3.Enabled=true;

button4.Enabled=false;

(6)                           爲恢復按鈕(button3)增長單擊事件函數以下:

thread. Resume();

button1.Enabled=false;

button2.Enabled=true;

button3.Enabled=false;

button4.Enabled=true;

(7)                           爲撤銷按鈕(button4)增長單擊事件函數以下:

if(thread.IsAlive())

{

thread.Abort();//撤銷線程對象

button1.Enabled=true;

button2.Enabled=false;

button3.Enabled=false;

button4.Enabled=false;

}

(8)                           C#線程模型因爲容許將任何一個原型爲void類型的公有類成員方法(靜態或非靜態)做爲線程方法,所以它實際上容許在任何一個類(不要求這個類是某個類的子類)中實現線程方法,並且同一個類中能夠實現多個線程方法。爲Form1類定義一個方法以下:

public void fun()//在線程中執行的方法,必須爲公有void類型方法,不能有參數。

{

while(true)//死循環,線程將一直運行

{

int x=Convert.ToInt(label1.Text);

x++;

label1.Text=Convert.ToString(x);

thread.Sleep(1000);//休眠1秒鐘,休眠一次,線程運行了1秒鐘

}

}

(9)                                                                      編譯,運行,按新線程(Button1)按鈕,新線程開始,計數器從0開始計數。按掛起(Button2)按鈕,線程暫停,計數器也暫停。按恢復(Button3)按鈕,線程從新啓動,計數器也從新計數。按撤銷(Button4)按鈕,線程對象被撤銷,線程對象不存在,計數器中止計數。

7.3   創建線程類

有時須要創建多個線程,每一個線程要實現的功能基本相同,但有個別參數不一樣,例如,每一個線程完成一樣的任務,但控制的對象不一樣。線程構造函數參數指定的方法須要本身定義,在這個方法中完成一些任務,但該方法不能有參數,所以不能經過方法的參數傳遞不一樣設置。爲解決這個問題,能夠定義一個線程類。具體實現方法件下例。

例子:創建兩個線程,分別控制進度條(ProgressBar)控件,每一個進度條的速度不同。首先介紹進度條(ProgressBar)控件。

7.3.1   進度條(ProgressBar)控件

進度條(ProgressBar)控件常常用來顯示一個任務的進度。有時,要在後臺完成一個長時間的任務,例如一個軟件的安裝,若是沒有任何提示,使用者可能分不清任務是在進行中,仍是死機了,爲了讓用戶知道安裝正在進行,能夠使用進度條控件顯示一個安裝進度。進度條控件經常使用的屬性以下:

l  屬性Maximum:進度條所表明的整數最大值,等於此值,任務完成。默認值100。

l  屬性Minimum:進度條所表明的整數最小值,等於此值,任務開始。默認值0。

l  屬性Step:變化的步長,默認值爲10。

l  屬性Value:進度條當前位置表明的值。修改該值,達到一個Step,進度增長一格。

7.3.2   用線程控制進度條

例子實現的具體實現步驟以下:

(1)  新建項目。在Form1.cs頭部增長語句:using System.Threading。

(2)  在窗體中放置2個進度條(ProgressBar)控件和一個標籤控件,屬性Name分別爲progressBar一、progressBar2和label1。Label1的屬性Text=」」。

(3)  在文件Form1.cs的最後創建線程類以下:

public class myThread

{

private int SleepTime;

private ProgressBar progressBar;

private Thread thread1;

public myThread(int Time,ProgressBar p1)

{

SleepTime=Time;

progressBar=p1;

thread1=new Thread(new ThreadStart(Fun));

Thread1.Start();

}

public void fun()

{

while(progressBar.Value!=100)

{

progressBar.Value+=1;

thread1.Sleep(SleepTime);

}

if(label.Text==」」)

label1.Text=」第一個線程結束」;

else

label.Text+=」,第二個線程結束」;

}

}

(4)  爲Form1類增長變量:myThread  myThread1,myThread2。

(5)  爲Form1類構造函數增長語句以下:

myThread1=new myThread(100,progressBar1);

myThread2=new myThread(200,progressBar2);

(6)  編譯,運行,能夠看到兩個進度條以不一樣的速度前進,當進度條被添滿,線程中止。

7.4   線程的優先級

當一個程序被調入內存準備運行時,操做系統自動建立一個進程和一個主線程,併爲進程指定基本優先級,進程基本優先級分爲如下四種:

l  IDLE_PROCESS_CLASS                          系統空閒時才執行

l  NORMAL_PROCESS_CLASS                   系統默認進程優先級

l  BELOW_NORMAL_PROCESS_CLASS     比系統默認進程優先級低一級

l  ABOVE_NORMAL_PROCESS_CLASS     比系統默認進程優先級高一級

l  HIGH_PROCESS_CLASS                         高進程優先級

l  REALTIME_PROCESS_CLASS                進程最高(實時)優先級

操做系統通常分配用戶應用程序進程爲NORMAL_PROCESS_CLASS系統默認進程優先級。對於進程中的各個子線程,能夠修改屬性ThreadPriority來調整其的優先級,屬性ThreadPriority能夠取以下值:

l  THREAD_PRIORITY_IDLE                      系統空閒時才執行

l  THREAD_PRIORITY_LOWEST                比NORMAL低2級

l  THREAD_PRIORITY_LOWER                 比NORMAL低1級

l  THREAD_PRIORITY_NORMAL        系統默認線程優先級

l  THREAD_PRIORITY_HIGHT                   比NORMAL高1級

l  THREAD_PRIORITY_HIGHTEST             比NORMAL高2級

l  THREAD_PRIORITY_TIME_CRITICAL    線程最高(實時)優先級

一個線程的優先權並非越高越好,應考慮到整個進程中全部線程以及其餘進程的狀況作出最優選擇。優先級相同的線程按照時間片輪流運行。優先級高的線程先運行,只有優先級高的線程中止、休眠或暫停時,低優先級線程才能運行。

7.5   多個線程互斥

多個線程同時修改同一個共享數據可能發生錯誤,例如,兩個線程記錄不一樣入口進入的人數,用一個變量實時顯示總人數。每一個線程都要對這個總人數變量執行加1操做,這個加1操做是一個高級語言語句,可能包含若干機器語言語句,例如,可能先從內存取數,加1,再存回內存。假如,當前人數爲100,第一個線程運行,從內存取出總人數100,時間片時間到,第2個線程啓動,執行加1操做,總人數變爲101,第2個線程退出運行。第一個線程恢復運行,執行加1操做,存回內存,總數本應爲102,實際爲101,少計算了一個。爲了防止此類錯誤,在一個線程操做這個總人數變量時,不容許其它線程對它進行操做,這叫線程的互斥。

7.5.1   多個線程同時修改共享數據可能發生錯誤

例子e7_5_1:下邊的例子模擬多個線程同時修改同一個共享數據發生的錯誤。

(1)  新建項目。在Form1.cs頭部增長語句:using System.Threading。

(2)  在窗體中放置一個標籤控件,屬性Name=label1。

(3)  爲Form1類定義2個線程類變量:Thread thread1,thread2。定義1個整形變量:int num=0。

(4)  爲Form1類構造函數增長語句以下:

thread1= new Thread(new ThreadStart(Fun1);

thread2= new Thread(new ThreadStart(Fun2);

(5)  爲Form1類定義Fun1()和Fun2()方法以下:

public void Fun1()

{

int k,n;

for(k=0;k<4;k++)

{

n=num;

n++;

thread1.Sleep(100);

num=n;

}

label1.Text=Convert.ToString(num);

}

public void Fun2()

{

int k,n;

for(k=0;k<4;k++)

{

n=num;

n++;

thread2.Sleep(200);

num=n;

}

label1.Text=Convert.ToString(num);

}

(6)  編譯,運行,標籤控件應顯示8,實際運行屢次,顯示的數要小於8。

7.5.2   用LOCK語句實現互斥

 

7.5.3   用Mutex類實現互斥

 

7.5.4   用Monitor類實現互斥

 

7.6   Monitor類

 

7.7   線程的同步:生產者和消費者關係

在生產者和消費者關係中,生產者線程產生數據,並把數據存到公共數據區,消費者線程使用數據,從公共數據區取出數據,並進行分析。很顯然,若是公共數據區只能存一個數據,那麼在消費者線程取出數據前,生產者線程不能放新數據到公共數據區,不然消費者線程將丟失數據。一樣,只有在生產者線程把數據已經放到公共數據區,消費者線程才能取出數據,若是新數據未放到公共數據區,消費者線程不能取數據。這些就是所謂的生產者和消費者關係,這要求生產者線程和消費者線程同步。

7.7.1   生產者線程和消費者線程不一樣步可能發生錯誤

例子e7_7_1:下邊的例子模擬生產者線程和消費者線程不一樣步可能發生錯誤。有一個公共變量,要求生產者線程順序放1到4到這個公共變量中,每放一個變量,消費者線程取出這個數求和,最後把和顯示出來,顯然和應爲10。如不採起同步措施,和的結果不正確。

(1)  新建項目。在Form1.cs頭部增長語句:using System.Threading。

(2)  在窗體中放置一個標籤控件,屬性Name=label1。

(3)  爲Form1類定義2個線程類變量:Thread thread1,thread2。

(4)  爲Form1類定義2個整形變量:int sum=0,x=-1。

(5)  爲Form1類構造函數增長語句以下:

thread1= new Thread(new ThreadStart(Fun1);

thread2= new Thread(new ThreadStart(Fun2);

(6)  爲Form1類定義Fun1()和Fun2()方法以下:

public void Fun1()//生產數據

{

int k,n;

for(k=1;k<5;k++)

{

x=i;

thread1.Sleep(200);

}

}

public void Fun2()//消費數據

{

int k,n;

for(k=0;k<4;k++)

{

sum+=x;

thread2.Sleep(100);

}

label1.Text=Convert.ToString(sum);

}

(7)  編譯,運行,標籤控件應顯示10,實際運行屢次,顯示的數要小於10。

7.7.2   生產者線程和消費者線程同步的實現

修改上例,爲Form1類定義1個布爾變量:bool mark=false。其值爲false,表示數據還未放到公共數據區(即x)中,生產者線程能夠放數據到公共數據區中,因爲沒有數據,消費線程不能取數據,必須等待。mark=true,表示數據已未放到公共數據區(即x)中,消費線程還未取數據,生產者線程不能再放數據到公共數據區中,必須等待。因爲有了數據,消費線程能夠取數據。修改Fun1()以下:

public void Fun1()//生產數據

{

int k,n;

for(k=1;k<5;k++)

{

Monitor.Enter(this);

If(mark)

Monitor.Wait(this);//若是消費者數據未取走,生產者等待

!mark;

x=i;

Monitor.Pulse(this);//激活消費者線程

Monitor.Exit(this);

}

}

修改Fun2()以下:

public void Fun2()//消費數據

{

int k,n;

for(k=0;k<4;k++)

{

Monitor.Enter(this);

If(!mark)

Monitor.Wait(this);//若是生產者未放數據,消費者等待

!mark;

sum+=x;

Monitor.Pulse(this);

Monitor.Exit(this);

}

label1.Text=Convert.ToString(sum);

}

編譯,運行,標籤控件應顯示10。

習題:

(1)  修改例子e7_5,用線程類實現。

 

 

第八章       ADO.NET與數據操做

8.1   數據庫基本概念

數據庫系統提供了一種將信息集合在一塊兒的方法。數據庫主要由三部分組成:數據庫管理系統(DBMS),是針對全部應用的,例如ACCESS。數據庫自己,按必定的結構組織在一塊兒的相關數據。數據庫應用程序,它是針對某一具體數據庫應用編制的程序,用來獲取,顯示和更新數據庫存儲的數據,方便用戶使用。這裏講的就是如何編寫數據庫應用程序。

常見的數據庫系統有:FoxPro,Access,Oracle,SQLserver,Sybase等。數據庫管理系統主要有四種類型:文件管理,層次數據庫,網狀數據庫和關係數據庫。目前最流行,應用最普遍的是關係數據庫,以上所列舉的數據庫系統都是關係數據庫。關係數據庫以行和列的形式來組織信息,一個關係數據庫由若干表組成,一個表就是一組相關的數據按行排列,例如一個通信錄就是這樣一個表,表中的每一列叫作一個字段,例如通信錄中的姓名,地址,電話都是字段。字段包括字段名及具體的數據,每一個字段都有相應的描述信息,例如數據類型,數據寬度等。表中每一行稱爲一條記錄。

數據庫可分爲本地數據庫和遠程數據庫,本地數據庫通常不能經過網絡訪問,本地數據庫每每和數據庫應用程序在同一系統中,本地數據庫也稱爲單層數據庫。遠程數據庫一般位於遠程計算機上,用戶經過網絡來訪問遠程數據庫中的數據。遠程數據庫能夠採用兩層,三層和四層結構,兩層結構通常採用C/S模式,即客戶端和服務器模式。三層模式通常採用B/S模式,用戶用瀏覽器訪問WEB服務器,WEB服務器用CGI,ASP,PHP,JSP等技術訪問數據庫服務器,生成動態網頁返回給用戶。四層模式是在WEB服務器和數據庫服務器中增長一個應用服務器。利用ADO.NET能夠開發數據庫應用程序。

因爲ADO.Net的使用,設計單層數據庫或多層數據庫應用程序使用的方法基本一致,極大地方便了程序設計,所以,這裏討論的內容也適用於後邊的Web應用程序設計。

8.2   設計鏈接和不鏈接數據庫應用程序的基本步驟:

設計一個數據庫應用程序能夠採用鏈接和不鏈接方式。所謂鏈接方式,是數據庫應用程序運行期間,一直保持和數據庫鏈接,數據庫應用程序經過SQL語句直接對數據庫操做,例如,查找記錄、刪除記錄、修改記錄。所謂不鏈接方式,是數據庫應用程序把數據庫中感興趣的數據讀入創建一個副本,數據庫應用程序對副本進行操做,必要時將修改的副本存回數據庫。設計一個不鏈接方式數據庫應用程序通常包括如下基本步驟:

(1)  創建數據庫,包括若干個表,在表中添入數據。

(2)  創建和數據庫的鏈接。

(3)  從數據庫中取出感興趣的數據存入數據集DataSet對象,包括指定表和表中知足條件的記錄,DataSet對象被創建在內存中,能夠包含若干表,能夠認爲是數據庫在內存中的一個子集。而後斷開和數據庫的聯接。

(4)  用數據綁定的方法顯示這個子集的數據,供用戶瀏覽、查詢、修改。

(5)  把修改的數據存回源數據庫。

設計一個鏈接方式數據庫應用程序通常包括如下基本步驟:

(1)  創建數據庫,包括若干個表,在表中添入數據。

(2)  創建和數據庫的鏈接。

(3)  使用查詢、修改、刪除、更新等Command對象直接對數據庫操做。

如下章節將按以上步驟說明數據庫應用程序的具體設計方法。

8.3   用ACCESS建立數據庫

本例建立一個學生信息管理系統,包括兩個表,第一個表記錄學生的基本狀況,包括如下字段:學號、姓名、性別等。第二個表記錄學生的學習成績,包括如下字段:記錄編號、課程名稱、分數、擁有該課程成績學生的學號。注意,把學習成績表字段定義爲:學號、語文成績、數學成績、物理成績等字段是不合適的,這樣作,增長一門課程,就要增長一個字段,字段要動態增長,這顯然不合理。用Access2000程序建立數據庫具體步驟以下:

(1)運行microsoft Access2000程序,出現《microsoft Access》對話框以下圖,選擇空Access數據庫,單擊肯定按鈕,打開標題爲《文件新建數據庫》對話框。

 

(2)在標題爲《文件新建數據庫》對話框中,添入數據庫文件名:StudentI,選擇保存位置和保存類型以下圖。單擊建立按鈕,出現《StudentI:數據庫》對話框。

 

(3)在《StudentI:數據庫》對話框中,雙擊《使用設計器建立數據表》,出現《表1:表》對話框。在表中能夠建立數據庫表的字段。

 

(4)在《表1:表》對話框中,建立字段StudentNum,數字類型的整形,必填字段,默認值爲0,標題爲學生編號。字段StudentName,文本,字段大小8,必填字段,默認值爲空,標題爲學生姓名。字段StudentSex,文本,字段大小2,標題爲性別。右擊字段StudentNum,在彈出菜單中選擇主鍵菜單項,設置字段StudentNum爲主關鍵字。以下圖。

 

(5)選擇《文件》彈出菜單的《保存》菜單項,出現《另存爲》對話框,在對話框中的《表名稱(N)》編輯框中輸入表名:Student,單擊肯定按鈕。關閉《表1:表》對話框。

(6)在《StudentI:數據庫》對話框左側,選擇對象爲:表,在右測出現Student表,雙擊Student表,出現《Student:表》對話框。

 

(7)在《Student:表》對話框中爲各個字段輸入數據:例如:1,張三,男;2,李四,女;3,王五,男;4,魯六,女。而後存盤。以下圖。

 

(8)一樣方法創建表Score,記錄全部學生學習成績。包括字段ScoreID(記錄編號),自動編號;ClassName(課程名稱),文本,字段大小26,必填字段,默認值爲空;Score(分數),字節類型,必填字段,默認值爲0;StudentNum(擁有該課程成績學生的學號),數字類型的整形,必填字段,默認值爲空。設置字段ScoreID爲主關鍵字。增長若干數據。

(9)  退出microsoft Access2000程序。

8.4   結構化查詢語言SQL

用戶經過SQL(Structed Query Language,結構化查詢語言)來訪問數據庫中的數據,使用SQL語句能夠對數據庫中的數據進行查詢、增長、刪除記錄,修改記錄中的數據。幾乎全部的數據庫都支持SQL語言,編寫數據庫應用程序必須學習SQL語言。

8.4.1 Select語句

Select語句是最經常使用的語句,能夠從數據庫的表中得到知足一些條件的數據集。常見的Select語句以下:

l select * from student

從表Student表中選擇全部字段的全部記錄

l select StudentNum,StudentName from student

從表Student表中選擇字段StudentNum和字段StudentName的全部記錄

l select * from score where StudentNum=1

從表score表中查找學號StudentNum=1同窗的全部課程的成績。

8.4.2 Insert語句

用於向數據庫表中插入一個新記錄。例如,向表student中插入一個新紀錄的語句以下:

Insert student (StudentNum,StudentName,StudentSex)Value(5,"田七","男")

8.4.3 Delete語句

用於刪除數據庫表中的一個記錄。例如,刪除student表中學號爲1的學生,語句以下:

Delete From student where StudentNum=1

8.4.4 Update語句

更新數據庫的Student表中學號爲1的學生名字爲"陳七":

Update Student Set StudentName="陳七" Where StudentNum=1。

8.5   用Connection對象鏈接數據庫。

Connection類對象用來鏈接數據庫。ADO.NET中有兩類Connection對象,一類用於微軟的Sql Server數據庫,該對象鏈接微軟SQL數據庫時效率較高,另外一類用於其它支持ODBC的數據庫。鏈接Sql Server數據庫序應引用以下命名空間:

Using System.Data;

using System.Data.SqlClient;

鏈接其它數據庫序應引用以下命名空間:

Using System.Data;

using System.Data.OleDb;

使用SqlConnection的例子:

string txtConn="DATABASE=Northwind;SERVER=localhost;UID=sa;PWD=;";

SqlConnection conn=new SqlConnection(txtConn);//創建鏈接

其中,DATABASE爲數據庫名稱,這裏爲Northwind,是微軟Sql Server數據庫自帶的數據庫例子,必須安裝此數據庫才能使用。UID爲用戶名,PWD爲密碼,Northwind數據庫安裝後的用戶名爲sa,密碼爲空。SERVER爲所使用的數據庫服務器,這裏數據庫服務器和數據庫應用程序在同一臺計算機中,所以爲localhost,中文意義是本地主機。

使用OleDbConnection的例子:

string txtConn=

"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:\\VC#\\studentI.mdb";

OleDbConnection conn = new OleDbConnection(txtConn);//創建鏈接

Provider爲所使用的數據庫驅動程序。DataSource爲數據庫的位置,有時還增長參數ConnectionTimeOut,爲連接超時時間,默認爲15秒。

也能夠使用Visual Stutdio.Net創建鏈接,例子見8.10B。

Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\myFolder\*.accdb;Persist Security Info=False;

http://zm10.sm.cn/?src=http%3A%2F%2Fwww.codefans.net%2Farticles%2F321.shtml&uid=56c023f99f0b87c81990565cfbf7702e&hid=3f68bec9381b228930fa08d2f35779b4&pos=8&cid=9&time=1431233777690&from=click&restype=1&pagetype=0300004000000402&bu=web&uc_param_str=pidi

8.6   Command對象

創建鏈接後,ADO.Net經過Command對象用SQL語句來訪問數據庫中的數據,對數據庫中的數據進行查詢,增長、刪除記錄,修改記錄中的數據。具體用法以下:

string txtCommand="SELECT * FROM student";

使用OleDbCommand

OleDbCommand Command1=new OleDbCommand(txtCommand,conn);

使用SQLCommand

SQLCommand Command1=new SQLCommand(txtCommand,conn);

例子8.6:鏈接方式數據庫應用程序。有時,數據庫應用程序使用鏈接方式可能更方便一些,例如,用戶的註冊信息應該當即存到數據庫中。下邊的例子模擬用戶註冊,首先請用戶輸入我的信息,單擊註冊按鈕,用SQL語句把數據存到StudentI數據庫的Student表中。具體步驟以下:

(1)新建項目。放三個Label控件到窗體,修改屬性Text分別爲:學號、姓名、性別。

(2)放三個TextBox控件到窗體,修改屬性Text都爲空。TextBox1輸入學號,TextBox2輸入學生姓名,TextBox3輸入學生性別。

(3)引入命名空間using System.Data.OleDb;

(4)增長變量:OleDbConnection conn;    OleDbCommand da;

(5)增長一個按鈕,屬性Text="增長記錄"。界面以下圖。爲其增長單擊事件函數以下:

private void button1_Click(object sender, System.EventArgs e)

{   if(textBox1.Text==""&&textBox2.Text==""&&textBox3.Text=="")

{   MessageBox.Show("全部項都必須填寫!");

return;

}//注意,下邊語句必須保證數據庫文件studentI.mdb在文件夾D:\\vc#中

string txt1=

"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:\\vc#\\studentI.mdb";

string txt2=

"Insert Into Student(StudentNum,StudentName,StudentSex) Values('";

txt2+=textBox1.Text + "' , '";

txt2+=textBox2.Text + "' , '";

txt2+=textBox3.Text+"')";//最後結果要保證在TextBox中輸入的內容被單引號括住

conn = new OleDbConnection(txt1);

conn.Open();

da=new OleDbCommand();

da.CommandText=txt2;

da.Connection=conn;

da.ExecuteNonQuery();

textBox1.Text="";

textBox2.Text="";

textBox3.Text="";

conn.Close();

}

(6)運行,輸入學號,姓名,性別,單擊《增長記錄》按鈕,察看數據庫,能夠看到增長了一個記錄。請讀者修改成刪除一個記錄,修改一個記錄。

8.7   DataAdapter對象

DataAdapter對象包含4個Command對象:SelectCommand對象,InsertCommand對象,UpdateCommand對象,DeleteCommand對象,完成對數據庫中的數據的選擇,插入,更新,刪除等功能。DataAdapter對象隱藏了Connection對象和Command對象溝通的細節,方便使用,在許多數據庫應用中,都使用DataAdapter對象。使用DataAdapter對象例子以下:

string txtConn=

"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:\\VC#\\studentI.mdb";

OleDbConnection conn=new OleDbConnection(txtConn);//創建鏈接

string txtCommand="SELECT * FROM student";

OleDbDataAdapter da=new OleDbDataAdapter(txtCommand,conn);

8.8   DataSet對象

DataSet對象從數據庫中取出感興趣的數據,包括指定表和表中知足條件的記錄,DataSet對象被創建在內存中,能夠包含若干表,能夠認爲是數據庫在內存中的一個子集。DataSet對象只在獲取或更新數據時保持和數據庫鏈接,其它時間都是斷開的。

8.8.1 使用DataSet的優勢

在傳統的數據庫應用程序中,必須創建與數據庫的鏈接,並在數據庫應用程序運行過程當中保持鏈接狀態。出於各類緣由,該方法在許多數據庫應用程序中是不實用的。

l 通常狀況下,數據庫只能夠維持少許的併發鏈接。維持過多併發鏈接將下降數據庫的整體性能,增長數據庫應用程序的訪問時間。保持四個用戶鏈接的執行也許還能夠接受,但鏈接100個用戶時可能就不行了。同時訪問Web數據庫的訪問者可能很是多,例如大型網上商店,全部訪問都保持鏈接是不現實的。

l 在Web應用程序中,瀏覽器從服務器請求網頁,服務器發送該頁後,服務器就再也不與瀏覽器有任何鏈接,直到下一次請求爲止。在這種狀況下,維持打開的數據庫鏈接是不可行的,由於沒有辦法知道數據使用者(客戶端)是否還將對數據庫訪問。

l 若是數據庫應用程序的多個控件需對數據庫數據操做,則多個控件都必須和數據庫創建鏈接,或者爲這些控件設計一種方式以相互傳遞數據。這使問題變得複雜。

出於以上這些緣由,ADO.NET數據庫訪問被設計爲以不鏈接的數據模型爲基礎,應用程序只在獲取或更新數據時保持鏈接,其它時間都是斷開的。因爲數據庫並未被大部分時間空閒的鏈接佔用,因此它能夠爲更多用戶服務。

8.8.2 數據集DataSet概念

在不鏈接的數據模型中,每次數據庫應用程序須要處理下一條記錄時都鏈接回數據庫是不可行的,這樣作會大大消除使用不鏈接數據的優越性。解決方案是臨時存儲從數據庫檢索的記錄,而後使用該臨時集。這即是數據集的概念。數據集DataSet是從數據庫檢索的記錄的緩存。數據集DataSet中包含一個或多個表(這些表基於源數據庫中的表),而且還能夠包含有關這些表之間的關係,以及對錶包含數據的約束信息。數據集DataSet的數據一般是源數據庫內容的子集,能夠用與操做實際數據庫十分相似的方式操做數據集DataSet,但操做時,將保持與源數據庫的不鏈接狀態,使數據庫能夠自由執行其餘任務。

由於數據集DataSet是數據庫數據的私有子集,因此它不必定反映源數據庫的當前狀態,所以,須要常常更新數據集DataSet中的數據。能夠修改數據集DataSet中的數據,而後把這些修改寫回到源數據庫。爲了從源數據庫獲取數據和將修改寫回源數據庫,請使用數據適配器DataAdapter對象。數據適配器DataAdapter對象包含更新數據集DataSet和將修改寫回源數據庫的方法。DataAdapter.Fill()方法執行更新數據集DataSet操做。DataAdapter.Update()方法執行將修改寫回源數據庫操做。

儘管數據集是做爲從數據庫獲取的數據的緩存,但數據集與數據庫之間沒有任何實際關係。數據集是容器,它用數據適配器的SQL命令或存儲過程填充。

8.8.3 使用DataSet對象

使用DataSet對象例子以下:

string txtConn=

"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:\\VC#\\studentI.mdb";

OleDbConnection conn=new OleDbConnection(txtConn);//創建鏈接

string txtCommand="SELECT * FROM student";//將表student全部記錄從數據庫取出

OleDbDataAdapter da=new OleDbDataAdapter(txtCommand,conn);

DataSet MyDataSet=new DataSet();//創建DataSet對象MyDataSet

da.Fill(MyDataSet,"MyTable");//將數據填充到數據集MyDataSet中,新表名爲:MyTable

下例說明了DataSet的使用方法:

l 添加記錄

DataRow dr=MyDataSet.Tables["Student"].NewRow();

dr["StudentNum"]=4;

dr["StudentName"]="魯豫";

dr["StudentSex"]="女"

l 修改Student表中第0個記錄的"StudentName"字段的值爲"田歌"

MyDataSet.Tables["Student"].Rows.[0]["StudentName"]="田歌";

l 刪除Student表中第0個記錄

MyDataSet.Tables["Student"].Rows.[0].Delete();

l 恢復數據

if(MyDataSet.HasErros)

MyDataSet.RejectChanges();

l 檢查DataSet是否有改動

if(MyDataSet.HasChanges())

da.Update(MyDataSet);//更新數據庫

8.8.4 爲DataSet對象中的表指定主鍵、創建關係

爲DataSet對象中的表指定主鍵、創建關係,能夠保證數據的完整性,例如,主鍵取值不能重複,不能刪除主表中的數據(例如某個學生),而不刪除另外一個表中和其有關的數據(例如另外一個表中的學生成績)等等。

l 設置表的主鍵:

DataColumn[] pKey=new DataColumn[1];

pKey[0]=MyDataSet.Tables["Student"].Columns["StudentNum"];

MyDataSet.Tables["Student"].PrimaryKey=pKey;

l 創建兩個表的聯繫:

MyDataSet.Relations.Add("StudentNum",

MyDataSet.Tables["Student"].Columns["StudentNum"],

MyDataSet.Tables["Score"].Columns["StudentNum"]);

8.9   用DataGraid控件顯示數據和數據綁定

DataGraid控件用來按行和列格式顯示數據表中的數據。DataGraid控件屬性DataSource用來指定數據表所在的數據集DataSet對象。DataGraid控件屬性DataMember用來指定在數據集DataSet對象中要顯示的數據表的名字。當這兩個屬性被正確設定,DataGraid控件將以網格形式正確顯示指定數據表。DataGraid控件中的數據被修改後,DataSet對象中相應數據表中的數據也被修改。這叫作數據綁定。數據綁定有兩個要點:第一,數據綁定控件能按綁定的數據源正確顯示數據源的數據,第二,在數據綁定控件中被修改的數據能被正確寫回數據源,這裏的數據源通常是數據集DataSet對象中的一個表或者是表中的一個字段。許多控件均可以數據綁定。

8.10     不鏈接數據庫應用程序的完整的例子

例8.10A:

(1)  新建項目。增長語句using System.Data.OleDb;

(2)  添加控件DataGraid,屬性Name=dataGrid1

(3)  爲Form1類增長變量:OleDbConnection conn; OleDbDataAdapter da; DataSet ds;

(4)  爲Form1類增長一個方法:

private void OnLoadData()

{   string txtConn=

"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:\\vc#\\studentI.mdb";

conn=new OleDbConnection(txtConn);

string txtCommand="SELECT StudentName, StudentNum, StudentSex FROM Student";

da=new OleDbDataAdapter(txtCommand,conn);

ds=new DataSet("ds");

da.Fill(ds,"Student");

dataGrid1.DataSource=ds;

dataGrid1.DataMember="Student";

}

(5)  在構造函數中增長語句

OnLoadData();

(6)  運行,能夠看到表Student中的信息。運行效果如上圖。

8.10B使用Visual Stutdio.Net鏈接數據庫StudentI並顯示Student表,具體步驟以下:

(1)  新建項目。在窗體中放置控件OleDbConnection,其屬性Name=OleDbConnection1。單擊控件oleDbConnection屬性ConnectionString的下拉列表的箭頭,在列表中選擇新建鏈接,打開《數據連接屬性》對話框,選擇提供程序選項卡頁,選擇OLE DB提供程序爲Microsoft.Jet.OLEDB.4.0後,單擊下一步按鈕,在1.選擇或輸入數據庫名稱下的編輯框中,單擊其後按鈕,選擇數據庫StudentI。在2.輸入登陸服務器信息下,選中使用指定的用戶名稱和密碼單選按鈕,在用戶名稱中輸入Admin,選中空白密碼多選按鈕。單擊測試鏈接按鈕,應出現測試鏈接成功對話框。按肯定按鈕退出。

(2)  在窗體中放置控件DataGrid,其屬性Name=dataGrid1。

(3)  選擇菜單項視圖/服務器資源管理器,打開服務器資源管理器窗口,能夠看到新創建的鏈接,單擊前邊的加號,展開此鏈接樹後,再展開表(Table)樹,能夠看到數據庫中的全部表名。拖表Student到窗體控件DataGrid中,將自動增長控件oleDbDataAdapter1到窗體。

(4)  單擊oleDbDataAdapter1選中它,單擊菜單項數據/生成數據集…,打開生成數據集對話框,他選擇默認值。按肯定按鈕退出。自動增長數據集DataSet對象dataSet11。

(5)  修改DataGrid1屬性DataSource= dataSet11,屬性Datamember=Student,Student爲表名。此時在DataGrid1中可看到表的表頭。

(6)  在構造函數中增長語句以下:

oleDbDataAdapter1.Fill(dataSet11);

(7)  運行,能夠在控件DataGrid1中看到表Student的內容。

(8)  如下將標題改成中文。選中控件DataGrid1,單擊其屬性TableStyles後的標題爲…的按鈕,打開DataGridTableStyle集合編輯器對話框,單擊添加按鈕,增長一個dataGridTableStyle對象。從屬性MapingName的下拉列表中選擇Student表。單擊其屬性GridColumnStyles後的標題爲…的按鈕,打開DataGridTextBoxColumn集合編輯器對話框,單擊添加按鈕,增長一個dataGridTextBoxColumn對象。修改HeadText屬性爲:學生姓名,從屬性MapingName的下拉列表中選擇Student表的StudentName字段。按此辦法,再增長兩個dataGridTextBoxColumn對象,修改HeadText屬性分別爲:學生學號、學生性別,屬性MapingName分別爲:StudentNum、StudentSex。

(9)  運行,能夠在控件DataGrid1中看到表頭爲中文。

8.11     修改數據並保存修改的數據到源數據庫

在控件DataGrid1中能夠修改數據,能夠增長記錄。現增長一個按鈕,標題爲:刪除,單擊此按鈕後,將刪除控件DataGrid1中選定的紀錄。爲其增長單擊事件函數以下:

private void button1_Click(object sender, System.EventArgs e)

{   int x;

x=dataGrid1.CurrentRowIndex;

dataSet11.Tables["Student"].Rows[x].Delete();

}

運行,選中一個控件DataGrid中某行(一條記錄),單擊按鈕能夠刪除此行。因爲排序等緣由,控件DataGrid中數據記錄的順序可能和dataSet11中表的記錄的順序不一致,所以此方法刪除數據可能出出錯。修改按鈕單擊事件函數以下:

private void button1_Click(object sender, System.EventArgs e)

{   int x;

object z;

x=dataGrid1.CurrentRowIndex;

z=dataGrid1[x,1];

DataRow foundRow;

object[] findTheseVals = new object[1];

findTheseVals[0] = z;

foundRow = dataSet11.Tables["Student"].Rows.Find(findTheseVals);

if(foundRow != null)

foundRow.Delete();

}

爲了保存修改的數據到源數據庫,現增長一個按鈕,標題爲:保存數據,單擊此按鈕後,將保存修改的數據到源數據庫。爲其增長單擊事件函數以下:

private void button2_Click(object sender, System.EventArgs e)

{   if(dataSet11.HasChanges())//在退出程序時,也應用此函數檢查,提醒用戶是否存盤

oleDbDataAdapter1.Update(dataSet11);

}

運行,增長一個記錄,單擊第二個按鈕,關閉程序,再打開,能夠看到新增的記錄被顯示,說明新增記錄已被存到源數據庫。

8.12     其它數據綁定控件

本例用TextBox控件顯示Student表,具體步驟以下:

(1)  新建項目。

(2)  從工具箱中,將3個Label控件放到窗體上,屬性Text分別爲:學號、姓名、性別。

(3)  從工具箱中,將 3個TextBox控件放到窗體上,屬性Text都爲空。

(4)  從「工具箱」的「數據」選項卡中,將 OleDbDataAdapter 對象拖到窗體上。「數據適配器配置嚮導」啓動,它將幫助您建立鏈接和適配器。

(5)  在該向導中,執行下列操做:

l 在第二個窗格中,建立或選擇一個指向數據庫StudentI的鏈接。

l 在第三個窗格中,指定您要使用 SQL 語句來訪問數據庫。

l 在第四個窗格中建立如下 SQL 語句:SELECT * FROM Student

l 單擊「完成」完成該向導。

(6)  從「數據」菜單中選擇「生成數據集」。 若是看不到「數據」菜單,請在窗體中單擊;該窗體必須具備焦點,該菜單纔會出現。

(7)  選擇「新建」選項,將該數據集命名爲 DataSet1。在「選擇要添加到數據集中的表」下面的列表中,確保選擇了「Student」。 選中「將此數據集添加到設計器」,而後單擊「肯定」。 從「文件」菜單中選擇「所有保存」,存全部文件。

(8)  選中textBox1控件的屬性DataBindings,單擊前邊+號展開,選中Text屬性,從下拉列表中選擇dataSet11 - Student.StudentNum。一樣辦法textBox2爲dataSet11 - Student.StudentName,textBox3爲dataSet11 - Student.StudentSex。

(9)  增長主窗體Form1的Load事件函數以下:

private void Form1_Load(object sender, System.EventArgs e)

{   dataSet11.Clear();

oleDbDataAdapter1.Fill(dataSet11);

}

(10)運行,能夠看到第一個學生狀況。現增長移動記錄功能,以顯示不一樣學生狀況。

(11)增長變量:BindingManagerBase Navigator;

(12)修改主窗體Form1的Load事件函數以下:

private void Form1_Load(object sender, System.EventArgs e)

{   dataSet11.Clear();

oleDbDataAdapter1.Fill(dataSet11);

Navigator=this.BindingContext[dataSet11,"Student"];

}

(13)從工具箱中,將 4個Button控件放到窗體上,屬性Text分別爲:第一記錄、下一記錄、前一記錄、最後記錄。各個按鈕的單擊事件函數以下:

private void button1_Click(object sender, System.EventArgs e)

{   Navigator.Position=0;//第一記錄

}

private void button2_Click(object sender, System.EventArgs e)

{   if(Navigator.Position!=Navigator.Count-1)

Navigator.Position+=1;//下一記錄

}

private void button3_Click(object sender, System.EventArgs e)

{   if(Navigator.Position!=0)

Navigator.Position-=1;//前一記錄

}

private void button4_Click(object sender, System.EventArgs e)

{   Navigator.Position=Navigator.Count-1;//最後記錄

}

(14)運行,能夠看到第一個學生狀況。單擊4個按鈕能夠移動記錄。

8.13     創建主從關係表

在數據庫StudentI中,在顯示錶Student和Score時,但願選中某個學生時,表Score只顯示此學生的成績,兩個表的這種關係叫作主從關係。如今實現這兩個表的主從關係。具體步驟以下:

(1)  新建項目。

(2)  從「工具箱」的「數據」選項卡中,將 OleDbDataAdapter 對象拖到窗體上。「數據適配器配置嚮導」啓動,它將幫助您建立鏈接和適配器。

(3)  在該向導中,執行下列操做:

l 在第二個窗格中,建立或選擇一個指向數據庫StudentI的鏈接。

l 在第三個窗格中,指定您要使用 SQL 語句來訪問數據庫。

l 在第四個窗格中建立如下 SQL 語句:SELECT * FROM Student

l 單擊「完成」完成該向導。

(4)  將第二個 OleDbDataAdapter 對象拖到窗體上。「數據適配器配置嚮導」再次啓動。

(5)  重複第(3)步,其中有如下差別:

l 在第二個窗格中,選擇上次所使用或建立的同一鏈接。

l 建立下列 SQL 語句來訪問Score表:SELECT Score.* FROM Score

(6)  從「數據」菜單中選擇「生成數據集」。 若是看不到「數據」菜單,請在窗體中單擊;該窗體必須具備焦點,該菜單纔會出現。

(7)  選擇「新建」選項,將該數據集命名爲 DataSet1。在「選擇要添加到數據集中的表」下面的列表中,確保選擇了「Student」和「Score」。 選中「將此數據集添加到設計器」,而後單擊「肯定」。從「文件」菜單中選擇「所有保存」,存全部文件。

(8)  Visual Studio 生成某類型化數據集類 (DataSet1) 和定義該數據集的架構。將在「解決方案資源管理器」中看到新架構 (DataSet1.xsd)。

(9)  在「解決方案資源管理器」中,雙擊剛建立的數據集的架構(名爲 DataSet1.xsd)。「XML 設計器」在「架構」視圖中打開,顯示數據集內的兩個表。

(10)從「工具箱」的「XML 架構」選項卡中,將 Relation 對象拖到Score表(子表)上。「編輯關係」對話框打開,其中帶有從這兩個表中派生的默認值。父元素爲Student表,子元素爲Score表,鍵字段和外鍵字段都爲StudentNum。其它不修改選默認值。單擊「肯定」按鈕,關閉「編輯關係」對話框。在「XML 設計器」中,這兩個表之間顯示一個關係圖標。若是須要更改關係設置,則能夠右擊相應的關係,選擇「編輯關係」。

(11)保存該架構並關閉XML設計器。此刻,爲執行從數據庫獲取信息並轉移到數據集的操做所需的所有設置均已完成。能夠向窗體添加顯示數據的控件了。

(12)返回到建立該項目時已打開的默認窗體 (Form1)。從「工具箱」的「Windows 窗體」選項卡中,將 DataGrid 控件拖到窗體上,Name=dataGrid1。RowHeadersVisable=false。在「屬性」窗口中,將 DataSource 屬性設置爲 dataSet11,DataMember屬性設置爲Student。

(13)從「工具箱」的「Windows 窗體」選項卡中,將 DataGrid 控件拖到窗體上,Name=dataGrid2。在「屬性」窗口中,將 DataSource 屬性設置爲 dataSet11,DataMember屬性設置爲Student.StudentScore,設置這兩個屬性將網格綁定到關係對象,以便網格只包含dataGrid1表中選擇的學生成績。

(14)增長主窗體Form1的Load事件函數以下:

private void Form1_Load(object sender, System.EventArgs e)

{   dataSet11.Clear();

oleDbDataAdapter1.Fill(dataSet11);

oleDbDataAdapter2.Fill(dataSet11);

}

(15)運行,能夠看到兩個DataGrid 控件,dataGrid1顯示學生狀況表,dataGrid2顯示dataGrid1表中選中的學生的成績。在dataGrid1表中選擇不一樣學生,dataGrid2顯示相應學生的成績。

 

 

第九章       ASP.Net編程基礎知識

本章首先介紹用ASP.Net技術編制服務器端動態網頁所需的網絡和HTML標記語言方面有關的知識。而後介紹ASP.Net技術基礎。

9.1   網絡基礎

用ASP.Net技術編制服務器端動態網頁,必然要和網絡打交道,具有一些網絡方面的知識是必要的。這裏假設讀者已經學過計算機基礎課程,在此基礎上,進一步介紹用ASP.Net技術編制服務器端動態網頁所需的必備網絡基礎知識。

9.2.1   局域網、廣域網和INTERNET

把分佈在不一樣地理區域的計算機以及專門的外部設備利用通訊線路互連,使各個計算機之間可以相互通信,實現信息和資源共享,就組成了計算機網絡。在一個較小區域,例如在單位內部組成的計算機網絡,稱爲局域網。一個較大區域的計算機網絡,稱爲廣域網。爲了使各個局域網之間互相通信,能夠把各個局域網連起來,組成廣域網。如將全世界範圍的計算機網絡採用TCP/IP網絡傳輸協議聯到一塊兒,則組成INTERNET。

INTERNET提供了許多服務,例如:遠程登陸服務Telnet、文件傳送服務FTP、電子郵件服務E-mail、電子公告板系統BBS、萬維網WWW(Web)、電子商務、IP電話等等。本課程主要介紹萬維網WWW中服務器端動態網頁的設計方法。

9.2.2   網絡傳輸協議

網絡的目的是爲了通信,共享資源。通信即傳輸數據,爲傳輸數據應遵照必定規則,這個規則叫網絡傳輸協議。不一樣的網絡操做系統採用不一樣的網絡傳輸協議。而在INTERNET中,爲了傳輸數據,你們都必須採用相同的傳輸協議,即TCP/IP協議。

9.2.3   IP地址

INTERNET中有成千上萬臺計算機,它容許任何兩臺計算機之間進行通信,爲了區分不一樣的計算機,必須給每一臺計算機一個惟一的編號,這個編號叫計算機的IP地址,它是一個32位二進制數,用四個十進制數表示,中間用點隔開,每一個十進制數容許值爲0-255(一個字節),例如,202.112.10.105,這種記錄方法叫點數記法。一個IP地址通常由兩部分組成,網絡標誌號及此網絡中的計算機號,例如,202.112.10.105若是是一個C類地址,其網絡標誌號爲202.112.10.0,網絡中的計算機號爲105。一個局域網絡中,全部計算機中都應有相同的網絡標誌號,每一個計算機有不一樣的計算機號,兩個不一樣局域網絡,其網絡標誌號必須不一樣,但不一樣網絡中,主機號能夠相同。每一個計算機要和INTERNET聯接,必須有本身的IP地址。

32位IP地址被分爲5類,即A、B、C、D和E類地址。A類地址的第一字節爲網絡標誌號,其他3字節爲計算機號。B類地址的前兩個字節爲網絡標誌號,其他2字節爲計算機號。C類地址的前三個字節爲網絡標誌號,最後一字節爲計算機號。D爲特殊地址,E爲私有地址。設置TCP/IP時,有一項叫子網掩碼,用子網掩碼錶示IP地址是哪類地址,A類地址的子網掩碼是:255.0.0.0,B類地址的子網掩碼是:255.255.0.0,C類地址的子網掩碼是:255.255.255.0。我國大部分單位的IP地址爲C類地址。

9.2.4   域名

用點數法表示的IP地址,雖然簡單,但很難記憶,爲了解決此問題,能夠爲INTERNET網中的每臺計算機起一個名字,在INTERNET中叫域名,並使此計算機的名字和IP地址對應起來,使咱們能夠使用名字訪問計算機,就象咱們使用IP地址同樣。例如微軟的域名www.microsoft.com,清華大學的域名www.tsinghua.deu.cn。

在INTERNET中訪問其它計算機必須使用IP地址,所以域名必須轉換爲IP地址。實現域名(和WINDOWS/2000/98中計算機名有區別)和IP地址轉換的軟件叫DNS(域名服務器)。在網內有一臺計算機運行DNS服務器軟件,這臺計算機叫DNS服務器。它負責必定區域內的計算機域名和IP地址的轉換,這個區域通常是一個網的內部的全部計算機。當網內的計算機用域名和其它計算機通信時,則首先呼叫DNS服務器,DNS服務器送出此域名對應的IP地址,網內的計算機收到IP地址後,再利用IP地址和其它計算機通信。若是,本DNS不能轉換相應的域名,則向上一級DNS申請轉換。計算機要和INTERNET聯接,設置TCP/IP時,必須設置DNS服務器IP地址。

9.2.5   URL

咱們在用瀏覽器瀏覽網頁時,其實是用URL來定位一個網頁的。URL是Uniform Resource Location(統一資源定位器)的簡稱。他的通常格式是:傳輸協議://域名:端口號/全路徑文件名。http:爲www專用超文本傳輸協議。域名,即上邊講到,例如www.microsoft.com微軟域名,此處能夠是IP地址,其格式爲http://IP地址:端口號/全路徑文件名。全路徑文件名:它指示訪問文件的全路徑,只寫出宿主目錄如下的全路徑文件名。若是在訪問主頁時不指定此項,則訪問其默認主頁,例如當咱們在瀏覽器的URL(地址)處鍵入http://www.sun.com/時,將訪問sun公司默認主頁。當光標移到某關鍵詞,光標變爲手型,單擊此關鍵詞則顯示和此關鍵詞相聯繫的URL所指定的網頁。此網頁可能在Internet中某網站的計算機中。在www系統中,每個網頁都有本身的URL,由它決定此網頁在www網中的具體位置。它很象計算機文件系統中的文件全路徑名。

9.2.6   端口號

一臺計算機上可能運行多個服務器軟件,如www服務器軟件(可能不僅一個)、ftp服務器軟件等,它們的IP地址是相同的。爲了區分不一樣的服務器,爲每一個服務器編一個號,叫端口號。此項不是必須的,若是一臺計算機僅運行一個www服務器軟件,則通常使用默認端口號80,運行一個ftp服務器軟件,其端號爲採用默認值20或21等,如採用默認端口號,端口號能夠不寫。但若有多個相同服務器運行,則應指定不一樣端口,其中不是採用默認端口號值的服務器軟件在使用URL定位時,則應指明使用的端口號。

9.2.7   HTML,HTTP和網頁

網頁使用HTML標記語言寫成。HTML標記是用特殊的ASCII字符來定義網頁中的格式、字體、顏色等內容。因爲各類系統中,例如Windows、Linux、Unix和蘋果系統,都支持ASCII字符標準,不一樣系統中的瀏覽器均可以解釋這些ASCII標記,將其所表示的網頁在屏幕中顯示。這樣,不一樣的系統均可以使用統一的ASCII標記,訪問其它系統中的網頁。網頁是WWW系統最小傳輸單位,它是用HTML語言寫的具備必定格式的數據集合,可供瀏覽器顯示。HTTP是超文本傳輸協議,用在WWW服務器和瀏覽器之間傳輸網頁。本質上是TCP/IP協議,全部的WWW服務器和瀏覽器都應遵照HTML和HTTP協議,才能使同一網頁在任何計算機中,使用任何瀏覽器都能顯示同一畫面,但實際上各公司瀏覽器軟件是有差別的,最明顯的是IE和Netscape之間在顯示同一網頁時,是有差異的。作好網頁後,應用不一樣瀏覽器測試一下,看是都能經過

9.2.8   Web服務器和瀏覽器工做方式

Web是基於客戶機/服務器模式,運行Web服務器軟件的計算機叫Web服務器,運行瀏覽器的計算機叫客戶機。服務器24小時開機,在指定的文件夾(宿主目錄)上存貯大量的網頁,這些網頁用URL定位,Web服務器軟件老是在監視是否有瀏覽器訪問本身。客戶機用瀏覽器訪問Web服務器,在瀏覽器上鍵入要訪問的網頁的URL,例如:http://www.sun.com/,用DNS(域名系統)轉換www.sun.com域名爲IP地址,經過IP地址和sun公司的Web服務器通信,sun公司的Web服務器接到信息後,因爲未指定文件名,將默認主頁送出。瀏覽器接到主頁數據,將其顯示。主頁中列出各項主題,每當鼠標通過這些主題時,鼠標變爲手形,雙擊此主題,將和主題有關的網頁調入並顯示。這種方法叫超連接。超連接的本質是:單擊該題目,轉換爲所聯繫網頁的URL,在此URL中,在文件路徑名處,指出了網頁在Web服務器中路徑及文件名,當把這些信息送給Web服務器後,Web服務器就送出指定的網頁。

9.2.9   宿主目錄、默認主頁及網站

默認文檔(主頁)就是當用戶用不帶文件名的URL訪問www服務器時送出去的網頁。它所在的目錄,叫宿主目錄。宿主目錄下的文件對訪問者都是可見的。宿主目錄和默認文檔名在不一樣的Web服務器中是不一樣的。Windows2000的IIS服務器宿主目錄爲…\InetPub\wwwroot,默認文件名(主頁名)爲Default.htm。大部分www服務器容許修改宿主目錄。當用戶使用不帶文件名的URL訪問www服務器時,而且宿主目錄中不存在默認文檔,並且www服務器容許列出宿主目錄下的全部目錄列表,將返回宿主目錄下的全部目錄列表。

由此,能夠看出,建立一個網站,就是建立一個文件夾,在文件夾中存入預先設計好的網頁。而後,把此文件夾設定爲宿主目錄,例如Windows2000的IIS服務器默認的宿主目錄爲…\InetPub\wwwroot。而後運行WEB服務器軟件,例如微軟的IIS服務器軟件。網絡上的其它計算機就能夠經過URL訪問該計算機中宿主目錄中的網頁。

9.2.10        靜態網頁

建立一個網站,必須編制若干網頁,網站纔算建成。靜態網頁是預先作好的網頁,在被訪問時不被修改。相對講靜態網頁製做比較容易,即便不懂超文本語言,使用FrontPage,Dreamerware就能夠完成,而動態網頁製做則比較困難。

9.2.11        客戶端動態網頁

例如,網頁根據上下午,晚上問客人早上好,下午好和晚上好,又如,網頁對於用戶輸入的內容進行檢查,根據用戶的選擇完成不一樣的功能。有時,但願在瀏覽器內實現動畫,放映影片等,這些都是客戶端動態網頁的例子。這能夠在HTML語言加入Javascript或VBscript腳本語言來實現。也能夠在HTML語言嵌入Java小程序(Applet)來實現。所以應比較系統的學習一下HTML語言,還應該學習Javascript或VBscript腳本語言,進一步還能夠學習Java語言。另外使用微軟的AxtiveX控件也是實現客戶端動態網頁的一種方法。

9.2.12        服務器端動態網頁

舉一個客戶登記的例子,當客人在客戶機端用瀏覽器填好表格後,將表格數據返回Web服務器,應把這些信息存入運行Web服務器的計算機內的數據庫。Web服務器並不能完成此工做,它調用運行Web服務器的計算機上的其它程序完成,這個程序叫Web服務器應用程序。又如,創建一箇中學校園網,能夠創建一個學生狀況數據庫,可供校長、教導處、老師查詢,可能要根據一些條件進行查詢,如某班的學生,得到三好生的學生等,瀏覽器把所查找的條件送給Web服務器後,Web服務器必須調用Web服務器應用程序完成此項工做,此程序查到有關數據後,要變成用HTML語言的網頁,送給Web服務器,再送給請求此項內容的客戶機。編制服務器端的Web服務器應用程序的方法主要有以下幾種:CGI,ISAPI,NSAPI,ASP,ASP.NET,JSP,PHP等。ASP.NET技術是微軟最新提出的編制動態網頁技術。如今Web數據庫比較流行的方法是三層數據庫,以下圖:

瀏覽器

Web服務器

Web服務器應用程序

數據庫

 

 

 

 

 

                                      訪問數據庫的方法

這裏的3層是指瀏覽器、Web服務器和數據庫。一些文獻中提到4層數據庫系統是在Web服務器和數據庫之間增長一個應用服務器層。本章既是講述設計Web服務器應用程序的方法。

9.2.13        修改宿主目錄及創建虛擬目錄

建立一個網站,必須有以下條件:第一,有固定的IP地址。第二,安裝並運行Web服務器軟件,例如Windows操做系統下的IIS,Unix或Liunx下的Aparc。第三,在宿主目錄下有可供遊覽的網頁。Windows2000的IIS服務器的宿主目錄爲\InetPub\wwwroot。能夠修改宿主目錄爲其它任意目錄,修改Windows2000的IIS服務器的宿主目錄方法以下:

(1)    在D盤建文件夾:ASP

(2)    打開控制面板,雙擊管理工具圖標。

(3)    雙擊Internet 服務管理器圖標。

(4)    右擊第一個+號後的計算機名,出現彈出菜單,選擇菜單項新建/WEB站點,按嚮導步驟選擇D:/asp爲新站點。單擊第一個+,打開文件樹,右擊默認WEB站點,將其中止。右擊管理WEB站點,將其中止。

請讀者做以下試驗:首先用記事本建立以下網頁:

<html>

  <body>

   這是個人第一個網頁

</body>

</html>

以文件名Test.htm存到d:/asp文件夾中,查找本機IP地址,假如爲:202.204.206.98。在另外一臺計算機中打開瀏覽器,輸入地址:http://202.204.206.98/Test.htm,在瀏覽器中應能看到文字:這是個人第一個網頁。由此可知,必須把建立的網頁拷貝到宿主目錄下。從本機訪問宿主目錄下的網頁時,能夠在瀏覽器的URL(地址)處鍵入:http://localhost/網頁以宿主目錄爲根目錄的全路經。其餘人訪問時,能夠在瀏覽器的URL(地址)處鍵入:http://IP地址或域名/網頁以宿主目錄爲根目錄的全路經。

也能夠用建虛擬目錄的方法,存放網頁,具體步驟以下:

(1)    打開控制面板,雙擊管理工具圖標。

(2)    雙擊Internet 服務管理器圖標。

(3)    單擊計算機名前的+號。

(4)    右擊默認Web站點,出現彈出菜單,選擇菜單項新建/虛擬目錄,按嚮導步驟選擇D:/asp爲新虛擬目錄。此時,在默認Web站點下將會出現設定的虛擬目錄,此目錄容許其餘人訪問。

請讀者想想,如把文件Test.htm拷貝到新虛擬目錄,在另外一臺計算機中如何訪問此網頁。

9.2   HTML標記語言

網頁使用HTML標記語言寫成。HTML標記是用特殊的ASCII字符來定義網頁中的格式,字體等等特色。因爲各類系統中,都支持ASCII字符標準,不一樣系統中的瀏覽器均可以解釋這些ASCII標記,將其所表示的網頁在屏幕中顯示。這樣,不一樣的系統均可以使用統一ASCII標記,訪問其它系統中的網頁。

若是有WEB服務器時,用IE瀏覽器顯示網頁前,必須把網頁拷貝到宿主目錄下,例如Windows2000的IIS服務器爲\InetPub\wwwroot。訪問此網頁時,在瀏覽器的URL(地址)處鍵入此網頁的URL,回車便可。

爲了在沒有WEB服務器時,能用IE瀏覽器顯示靜態網頁,首先將IE的默認網頁設置爲about:blank。而後運行IE,在地址欄中輸入網頁文件的路徑,回車便可。修改IE的默認網頁爲about:blank及IE的默認編輯器爲寫字板的具體辦法是:單擊IE菜單工具/Internet選項,打開Internet選項對話框。在常規頁中的主頁選擇使用空白頁,程序頁中,HTML編輯器選擇Windows Notepad。

9.2.1   HTML標記

HTML標記是用特殊的ASCII字符來定義網頁中的格式、字體、字符對齊方式等特色。其格式爲:<標記名稱>被控制的文字</標記名稱>。其中,<標記名稱>爲開始標記,</標記名稱>爲結束標記,通常用來定義被控制的文字的格式或字體等。例如,下列標記使被控制的文字ASP.NET中間對齊:<center>ASP.NET</center>

9.2.2   HTML文件結構

一個網頁文件的最基本HTML標記結構以下:

<html>

  <head>

   <title>

顯示在瀏覽器標題欄中的文字

   </title>

  </head>

  <body>

   這裏是網頁的內容

</body>

</html>

<html>表示網頁文件的開始,</html>表示網頁文件的的結束,網頁的全部內容都應在這兩個標記之間。<head>…</head>之間能夠設定網頁的一些信息,<title>   </title>之間的文字顯示在IE瀏覽器的標題欄中。<body>…</body>之間時網頁的主題內容。由此能夠看出,在HTML語法中,HTML標記能夠嵌套,一個HTML標記能夠包含另外一個HTML標記,但標記的嵌套不能是交錯的。下邊是一個實際例子:

<html>

  <head>

    <title>

     這是個人第一個網頁

    </title>

  </head>

  <body>

     <center>

這是個人第一個網頁。<BR>

其中&ltBR&gt標記表示換行,

注意,僅鍵入回車時不能在網頁中換行的。<BR>

注意空格的用法,    鍵入四個空格,網頁中只有一個空格。<BR>

增長4個空格,&nbsp&nbsp&nbsp&nbsp是4個空格<BR>

網頁中不區分大小寫,不一樣瀏覽器顯示的效果可能不一樣<BR>

<!--這是註釋,瀏覽時不顯示-->

注意,特殊符號的顯示:&lt,&gt,&quot,&amp,&copy,&reg

     </center>

  </body>

</html>

網頁中能夠增長一些標記,例如:

<html>

  <head>

   <title>,<base>,<link>,<isindex>,<meta>

  </head>

  <body>

HTML文件的正文寫在這裏…

 </body>

</html>

這些標記的用法見如下各節。

9.2.3   語言字符集的信息

語言字符集的信息用法見下邊的網頁。主要是選用網頁使用的字符集,gb2312是中文字符集。

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=gb2312">

<title>meta的使用</title>

</head>

<body>

meta的使用。

</body>

</html>

9.2.4   背景色彩和文字色彩

設置背景和文字色的語法以下:<body bgcolor=#,text=#,link=#,alink=#,vlink=#>其中,bgcolor,text,link,alink,vlink的意義見書,#表示顏色,可用rrggbb表示,rr,gg,bb分別是表示紅色,綠色,藍色的16進制數,例如,紅色爲:ff0000。下例設置背景色爲紅色。

<html>

<head>

<title>設置背景色爲紅色</title>

</head>

<body bgcolor=ff0000>

設置背景色爲紅色。

</body>

</html>

9.2.5   頁面空白

能夠設置頁面的上下左右邊距,單位爲像素。例如設置左邊距爲20個像素格式以下:

<body leftnargin=20>

9.2.6   顯示一幅圖

下例在網頁中顯示一幅圖。注意<IMG src="file:///D:/耿肇英/ASP.NET教案/baobao048.jpg" width="320" height="240">的寫法。其中,file://是文件協議,用來選擇本地文件。通常網頁中用http://,即超文本協議,此時要求運行WEB服務器。

<html>

  <head>

   <title>

    增長一幅圖形!

   </title>

  </head>

  <body>

    <IMG src="file:///D:/耿肇英/ASP.NET教案/baobao048.jpg" width="320" height="240">

</body>

</html>

9.2.7   超級連接

瀏覽網頁時,當鼠標變爲手形時,單擊,能夠打開另外一個網頁,下邊的例子在當前窗口打開另外一個網頁。

<html>

<head>

 <title>

  連接的例子

 </title>

</head>

<body>

  這是一個

  <a href="C214.htm">連接的例子</a>

  點一下帶下劃線的文字!

</body>

</html>

9.2.8   超級連接在新窗口打開另外一網頁

以下例子:

<html>

<head>

 <title>

   開一個新窗口例子

 </title>

</head>

<body>

  <a href="window.htm"target="window_name">

   開一個新窗口!

  </a>

</body>

</html>

將光標移到」開一個新窗口」,光標變爲手型,單擊」開一個新窗口」,將打開另外一個網頁窗口,即window.htm網頁。window.htm網頁以下:

<html>

<head>

 <title>

   New Window Form HyperLink Dir

 </title>

</head>

<body>

 <H1aligh=center>這是新開的窗口!</H1>

 <center><p>返回原先窗口<a href="C226.htm#window">開新一個(瀏覽器)窗口</a>"一處

 </p></center>

</body>

</html>

9.2.9   標尺線

標尺線標記格式爲:<hr align=left color="red" noshade size=10 width=50>。其中,align爲標尺線對齊方式,能夠取left,right,center。Color爲標尺線顏色。Noshade設定標尺線爲沒有三維效果的實心黑線。Size爲標尺線的厚度。width爲標尺線的寬度,能夠是像素值,也能夠相對於窗口的百分比。實際使用見下例:

<html>

<head>

 <title>

   標尺線

 </title>

</head>

<body>

  <hr size=10>

  <hr width=#>

  <hr width=50>

  <hr width=50%>

  <hr align=left>

  <hr align=right>

  <hr width=50% align=left>

  <hr width=50% align=right>

  <hr noshade>

  <hr color="red">

</body>

</html>

9.2.10        網頁中標題的字體

網頁中一共有6種標題字體,見下例:

<html>

<head>

 <title>

  標題字體

 </title>

</head>

<body>

  <h1>這是1級標題!</h1>

  <h2>這是2級標題!</h2>

  <h3>這是3級標題!</h3>

  <h4>這是4級標題!</h4>

  <h5>這是5級標題!</h5>

  <h6>這是6級標題!</h6>

</body>

</html>

其中,標題字體是黑體,每一個標題自動插入一個空行。

9.2.11        網頁中正文字體

網頁中正文字體只有7種大小,能夠用以下方法設置正文字體:

<html>

<head>

 <title>

  正文字體

 </title>

</head>

<body>

  <font size=7>字號爲7,最大字體</font>

  <font size=6>字號爲6</font>

  <font size=5>字號爲5</font>

  <font size=4>字號爲4</font>

  <font size=3>字號爲4</font>

  <font size=2>字號爲2</font>

  <font size=1>字號爲1,最小字體</font>

</body>

</html>

注意字號只能是1到7。

9.2.12        斜體、粗體字符及爲字體增長下劃線,刪除線

能夠使字體爲斜體、粗體,爲字體增長下劃線,刪除線。見下例:

<html>

<head>

</head>

<body>

  <b>標記內的字爲黑體</b> <br>

  <i>標記內的字爲斜體</i> <br>

  <u>標記內的字有下劃線</u> <br>

  <tt>標記內的字等寬,例如w和i等寬</tt> <br>

  H<sub>2</sub> ,2爲下標<br>

  A<sup>2</sup> ,2爲上標<br>

  <s>標記內的字加刪除線</s> <br>

  <strike>標記內的字加刪除線</strike> <br>

</body>

</html>

9.2.13        字體標記的組合使用

見下例:

<html>

<head>

 <title>

  字體標記的組合使用

 </title>

</head>

<body>

  <i><font size=5>

      <b>今天</b> 天氣<font size=6>真好!</font>

  </font></i>

</body>

</html>

9.2.14        字體的顏色

見下例:

<html>

<head>

</head>

<body>

  <font size=5 color=000000>Black</font>&

  <font size=5 color=red>Red</font>

</body>

</html>

9.2.15        客戶端字體

每一個操做系統都提供若干字體,網頁能夠使用操做系統提供的字體,下邊的網頁顯示如何使用這些字體。

<html>

<head>

</head>

<body>

  <h1>客戶端字體事例</h1>

  <font face="Arial">Arial...</font><br>

  <font face="Comic Sans MS">Comic Sans MS...</font><br>

  <font face="Courier">Courier...</font><br>

  <font face="Courier New">Courier New...</font><br>

  <font face="Modern">Modern...</font><br>

  <font face="MS Serif">MS Serif...</font><br>

  <font face="MS-DOS CP 932">MS-DOS CP 932...</font><br>

  <font face="Roman">Roman...</font><br>

  <font face="Script">Script...</font><br>

  <font face="Small Fonts">Small Fonts...</font><br>

  <font face="Symbol">Symbol...</font><br>

  <font face="Times Roman">Times Roman...</font><br>

  <font face="Times New Roman">Times New Roman...</font><br>

  <font face="WingDings">WingDings...</font><br>

</body>

</html>

9.2.16        網頁中控件的概念

WEB服務器爲了和用戶進行交互,必須解決以下問題:首先,用戶應能輸入一些數據,例如,要查詢的條件,用戶登陸的信息等等。第二,這些數據用什麼方法傳到WEB服務器。第三,WEB服務器用那個程序響應用戶。爲了實現以上功能,必須使用窗體控件,也叫表單控件form,Visual Studio.net中叫WebForm。同時還須要一些其它控件,例如,編輯框控件,列表框控件,下拉列表框控件和按鈕等。能夠用HTML標記語言定義控件。IE瀏覽器看到這些標記,就把它顯示爲相應的控件。控件有許多屬性,也能夠用HTML標記語言表示,每一個屬性用空格分開,用屬性名稱=屬性值格式定義。

9.2.17        窗體控件和其它控件的使用

窗體控件是其它控件的容器,全部其它控件都要放到窗體控件中。Form控件的基本語法以下:

<form action=URL method="POST">

   <!--在此處增長交互控件,例如編輯框、列表框-->

  <input type="submit" value="提交" name="B1">

<input type="reset" value="所有重寫" name="B2">

</form>

其中,<form action=URL method="POST">…</form>定義Form控件,action是WEB服務器用響應用戶程序的URL,method="POST"是數據用POST方法傳到WEB服務器,也能夠是get方法。用戶用交互控件輸入信息。<input type="submit" value="提交" name="B1">是一個按鈕控件,其類型爲submit,按鈕標題爲:提交,表明此控件的name爲B1。當用戶單擊此按鈕,form控件將把控件內的全部交互控件中的數據用POST方法,傳遞給action指定WEB服務器的程序處理。<input type="reset" value="所有重寫" name="B2">也是一個按鈕,用戶單擊此按鈕,將清空form控件內的全部交互控件。

form控件內能夠增長交互控件,交互控件的使用<input>標記,其語法以下:<input align=top|middle|bottom [check] maxlength=? Name=? Size=? Src=? Type=? Value=?>各個屬性意義以下:

align爲對齊方式,能夠取top、middle和bottom。

Type爲控件類型,能夠是:type="submit"爲提交按鈕。type="reset"爲所有重寫按鈕。type="text"爲編輯框。type="password"爲口令編輯框。type="checkbox"爲複選框。type="radio"爲單選框。type="image"爲圖形。type="hidden"用戶不能看到,能夠用來傳遞網頁的一些默認的數據。

[check]只有在type="checkbox"或"radio"時使用,表示缺省被選中。

Maxlength屬性在type="text"編輯框時表示最大字符長度。

Name屬性表明此控件的名字。

Size屬性在type="text"編輯框時表示編輯框最大寬度。

Value如爲按鈕,則爲標題,爲編輯框,則爲缺省內容。此值將按Name/Value對的形式傳遞給WEB服務器。

9.2.18        例子:文字輸入和密碼輸入

<html>

<head>

<title>Form的例子</title>

</head>

<body>

<form method="POST" action="--WEBBOT-SELF--">

  您的姓名:<input type="text" name="T1" size="20"><br>

  您的主頁的網址:<input type="text" name="T2" size="20"><br>

  密碼:<input type="password" name="T3" size="20"><br>

  <input type="submit" value="提交"><input type="reset" value="所有重寫"><br>

</form>

</body>

</html>

9.2.19        用FontPage作網頁的例子,使用複選框和單選按鈕

用FontPage或Dreamerware要比使用記事本編輯網頁方便的多。下邊用FontPage作網頁的例子。下邊是具體步驟:

(1)    運行FontPage。

(2)    單擊菜單文件/新建/網頁。出現新建對話框,選擇常規頁的普通網頁,單擊肯定按鈕,建立一個新網頁。

(3)    單擊菜單插入/表單/表單,增長一個新表單(form)。在表單中已有一個提交按鈕和一個所有重寫按鈕。將光標移到提交按鈕先後回車,增長form的尺寸。

(4)    右擊提交按鈕,在彈出菜單中選中菜單項表單域屬性,出現按鈕屬性對話框,可修更名稱(Name屬性)屬性,值/標籤(value屬性)=提交查詢內容,按鈕類型爲提交。按肯定按鈕。用一樣方法修改另外一個按鈕的標題爲重置。

(5)    將光標移到第一行,單擊菜單插入/表單/複選框。右擊複選框,在彈出菜單中選中菜單項表單域屬性,出現複選框屬性對話框,修更名稱(Name屬性)屬性=水果1。在複選框後鍵入字符:Banana。用一樣方法增長另兩個複選框,注意初始狀態修改成選中。

(6)    用FontPage建立的網頁文件以下:

<html>

<head>

<meta http-equiv="Content-Language" content="en-us">

<meta http-equiv="Content-Type" content="text/html; charset=gb2312">

<meta name="GENERATOR" content="Microsoft FrontPage 4.0">

<meta name="ProgId" content="FrontPage.Editor.Document">

<title>New Page 2</title>

</head>

<body>

<form method="POST" action="--WEBBOT-SELF--">

  <!--webbot bot="SaveResults" U-File="fpweb:///_private/form_results.txt"

  S-Format="TEXT/CSV" S-Label-Fields="TRUE" -->

  <p><input type="checkbox" name="水果1" value="香蕉">Banana</p>

  <p><input type="checkbox" name="水果2" value="蘋果" checked>Apple</p>

  <p><input type="checkbox" name="水果3" value="桔子" checked>Orange</p>

  <p><input type="submit" value="提交查詢內容" name="B1"><input type="reset" value="所有重寫" name="B2"></p>

</form>

</body>

</html>

9.3 ASP.NET技術基礎

設計靜態網頁有兩種方法:一種是使用記事本,用HTML語言編寫,另外一種是使用可視化工具,如FrontPage,Dreamware等。顯然,使用可視化工具要方便快捷的多。以往設計服務器端動態網頁時,例如ASP,每每只能使用記事本一行一行的寫,效率很低。程序員迫切須要一種設計服務器端動態網頁的可視化工具,能象使用C#設計Window應用程序同樣設計動態網頁,使用控件類、屬性和事件等面向對象的概念。爲了實現這個目的,引入ASP.NET服務器端控件概念。靜態網頁中通常有一個表單(Form),在表單中能夠有多個控件,例如,列表框、編輯框、按鈕等等,經過這些控件,完成必定的功能。一樣,ASP.NET服務器端控件首先引入運行在服務端WebForm概念,在WebForm中能夠放入多個服務器端控件,例如,列表框、編輯框、按鈕等等,全部這些控件,都是.NET框架類庫中相應類的對象,每一個對象都有本身的屬性、方法和事件。這些概念和編制Windows應用程序相應的概念基本相同。這些ASP.NET服務器端控件,也使用HTML標記描述,但這些服務器端控件並不傳送這些HTML標記給瀏覽器解釋,而是由Web服務器負責解釋,翻譯爲全部瀏覽器都能解釋的標準HTML標記後傳送給瀏覽器解釋,這樣就極大地簡化了服務器端動態網頁的設計,也保證了生成的網頁的顯示效果和瀏覽器無關。使用ASP.Net技術建立的服務器端動態網頁的擴展名爲.aspx。

本節首先介紹ASP.NET服務器端控件基本概念,而後介紹使用記事本編寫ASP.NET動態網頁的方法,最後介紹如何使用Visual Studio.NET編寫ASP.NET動態網頁。

9.3.1   HTML服務器端控件

ASP.Net中的HTML服務器端控件和標準的HTML控件有着對應關係,但功能更強大。能夠在程序中修改HTML服務器端控件的屬性,可以在服務器端響應事件,支持數據綁定等。例如增長一個HTML服務器端控件編輯框用以下HTML語句:

<INPUT TYPE=」TEXT」 ID=」Text1」 MAXLENGTH=16 RUNAT=」SERVER」/>

這裏和標準的HTML控件的區別是增長了屬性RUNAT=」SERVER」。屬性ID是表明這個控件的惟一標誌,和Winndows應用程序中的控件屬性Name的意義是同樣的。HTML服務器端控件是爲了方便原來學習HTML或ASP編寫Web應用程序的程序員而提供的。若是,你之前是Windows應用程序員,建議使用Web服務器端控件,這些控件不但功能更強大,而使用上更象Windows應用程序中的控件,所以學習更方便。所以這裏就不介紹HTML服務器端控件了。

9.3.2   Web服務器端控件

在ASP.NET系統中,除了常規的HTML控件外,還包括Web服務器端控件。同HTML服務器端控件同樣,這些控件能夠在程序中修改服務器端控件的屬性,可以在服務器端響應事件,支持數據綁定等。例如定義一個Web服務器端控件編輯框控件,方法以下:

<asp:TextBox id="textBox1" runat="server"/>

服務器端控件不但功能更強大,並且和編制Windows應用程序中的控件使用方法基本一致,所以學習更方便。本書的全部例子都使用Web服務器端控件。

9.3.3   Web Form的事件處理

象Windows應用程序同樣,ASP.Net應用程序也採用事件驅動的概念,用戶對瀏覽器的各類操做都被看做事件,事件產生後,Web應用程序用事件處理函數響應事件。但ASP.Net的事件驅動和Windows應用程序的事件驅動有着本質上的區別。Web應用程序的事件產生後,因爲事件處理程序在Web服務器端,Web應用程序把事件經過網絡使用HTTP協議由瀏覽器傳到Web服務器,在Web服務器執行事件處理程序,把運行結果轉變爲標準HTML標誌的網頁,傳回瀏覽器。

在Web事件處理機制中,每一次Web應用程序響應事件都會使得網頁從新生成。事實上,一旦服務器完成某一個網頁的處理操做並將它傳送至瀏覽器,則會隨即移除該網頁的全部信息,也就是說,網頁中定義的對象和變量在服務器端已不存在了,網頁生命週期結束。當Web應用程序再一次響應事件時,服務器又會將上述處理過程重作一次。基於此緣由,咱們說網頁是無狀態的——即網頁變量與控件的數據值並不會保留在服務器上。

所以,咱們增長事件函數時,應考慮網絡傳播的速度的影響,不能象Windows應用程序那樣,響應太多的事件。在網頁中,每一個控件都有屬性AutoPosBack,其值爲true,事件才能自動調用事件處理函數,若是不但願響應該事件,應將該控件的屬性AutoPosBack設爲false。

9.3.4   記事本編寫ASP.NET動態網頁

ASP.NET中的服務器端控件也用HTML標記,但這些服務器端控件的HTML標記並不傳送給瀏覽器解釋,而是由Web服務器負責解釋,翻譯爲全部瀏覽器都能解釋的標準HTML標記後傳送給瀏覽器解釋。全部ASP.NET服務器端控件都要放到Web窗體(WebForm)中,Web窗體(WebForm)也由Web服務器負責解釋。下邊是一個最簡單的使用服務器端控件的例子:

<%@ Page language="c#" %>

<html>

<head>

<title>這是個人第一個ASP.NET網頁</title>

</head>

<script language="c#" runat=server>

   void Page_Load(Object src,EventArgs e)

     {Label1.Text="如今的時間是:"+DateTime.Now;}

   void EnterBtn_Click(Object src,EventArgs e)

     {Label1.Text="如今的時間是:"+DateTime.Now;}

</script>

<body>

  <form action="e1.aspx" runat=server>

  <asp:Label id="Label1" font-size="14" font-bold="true" forecolor="red" Text=""runat=server>

</asp:Label>

  <br>

  <asp:button text="查看時間" Onclick="EnterBtn_Click" runat=server/>

  </form>

</body>

</html>

網頁文件第一條語句表示網頁中使用C#語言。<html>表示網頁文件的開始,</html>表示網頁文件的的結束,網頁的全部內容都應在這兩個標記之間。定義在標記<html>和</html>之間的內容被分爲三部分,第一部分:<head>和</head>之間能夠設定網頁的一些信息,<title>和</title>之間的文字顯示在IE瀏覽器的標題欄中。第二部分:<script language="c#" runat=server>和</script>標記之間能夠定義方法,變量或對象,language="c#"表示在此標記之間定義的方法使用C#語言,runat=server表示在此標記之間定義的方法運行在Web服務器端,這裏定義了兩個方法,方法Page_Load()是Web服務器裝載本網頁時調用的方法,能夠在此方法中作一些初始化工做,方法EnterBtn_Click()是"查看時間"按鈕的事件函數。第三部分:<body>和</body>之間是網頁在瀏覽器中顯示的內容。<form action="e1.aspx" runat=server>和</form>標記定義Web窗體(WebForm),注意runat=server表示Web窗體由Web服務器解釋。在Web窗體中增長了兩個控件對象,第一個是Label控件,asp:Label表示本控件是Label控件,id至關Windows應用程序中控件的Name屬性,用來區分不一樣對象,runat=server表示次控件由Web服務器解釋,其他是設定屬性值,注意不一樣屬性用空格分隔。第二個控件是按鈕,請注意定義單擊事件函數的方法。

將其以文件名e1.aspx存入d:/asp文件夾,若是d:/asp文件夾已被設定爲Web站點,能夠在IE的地址欄輸入:http://localhost/c411.aspx後,看到這個網頁。在瀏覽器端看不到這些代碼,用IE菜單查看/源代碼,能夠看到用超文本編制的網頁。

9.3.5   用Visual Studio.NET實現ASP.NET動態網頁

用Visual Studio.NET實現上節的例子。具體步驟以下:

(1) 運Visaul C#後,則進入開始界面,選擇新建項目。打開新建項目對話框,在項目類型中選擇Visual C#項目,在模板中選擇[ASP.NET Web應用程序],指定項目項目放置的位置爲http://localhost/e1,這裏http://localhost表明當前激活的宿主目錄,即將本應用的全部文件存入宿主目錄下的文件夾e1中,點擊「肯定」,生成一個空白窗體(WebForm)。用戶可在窗體中放入控件。Visual Studio.NET爲咱們創建了一個應用項目。

(2)向項目中添加控件須要使用[Toolbox]窗口,若看不到,能夠用菜單視圖/工具箱打開這個窗口。

(3)先選中[Toolbox]窗口中[Web窗體]類型下的[Label]條目,而後在設計的窗體中按下鼠標左鍵並拖動鼠標,畫出一個Label控件。該控件用來顯示一行文本。

(4)使用[Properties]窗口修改Label控件的文本內容和文本字體屬性。在右下側屬性窗口中找到[text]屬性,把它的值由「Label1」改成」如今的時間是:」;接着在屬性窗口中找到[Font]屬性,選中Font所在的單元格,單擊Font屬性左邊的「+」號,在出現的子屬性中編輯,能夠修改Label控件中文本的字體和字號等屬性。編輯完成後,單擊變成「-」號的方框隱藏Font的子屬性;修改Label控件的ForeColor屬性,能夠修改Label中文本的顏色。

(5)從[Toolbox]窗口中選中一個Button控件到窗體,在[Properties]窗口中將按鈕的[Text]屬性分別改成」查看時間」。

(6)爲單擊查看時間按鈕事件(Click)函數增長語句(雙擊Click事件):

private void Button1_Click(object sender, System.EventArgs e)

{

Label1.Text="如今的時間是:"+DateTime.Now;

}

(7)爲Page_Load事件函數增長語句:

private void Page_Load(object sender, System.EventArgs e)

{

Label1.Text="如今的時間是:"+DateTime.Now;

}

(8)  單擊工具欄中藍色箭頭按鈕,運行,看一下效果。也可用瀏覽器看一下,地址爲:http://localhost/e1/WebForm1.aspx。請仔細觀察,每一步驟Visual Studio.NET都爲咱們增長了什麼語句。

9.3.6   Code Behind技術

Code Behind技術把界面設計代碼和程序設計代碼以不一樣的文件分開,對於代碼的重複使用,程序的調試和維護都是十分方便的。特別是在團隊開發中,能夠使不一樣人員編輯不一樣文件,極大地提升了效率。Visual Studio.NET使用了Code Behind技術,當咱們使用Visual Studio.Net建立了一個Web應用程序,將自動建立了兩個文件,其中ASP.NET Web網頁文件WebForm1.aspx以下:

<%@ Page language="c#" Codebehind="WebForm1.aspx.cs" AutoEventWireup="false" Inherits="e2.WebForm1" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<html>

<head>

<title> WebForm1</title>

<meta name="GENERATOR" Content="Microsoft Visual Studio 7.0">

<meta name="CODE_LANGUAGE" Content="C#">

<meta name="vs_defaultClientScript" content="JavaScript">

<meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">

</head>

<body MS_POSITIONING="GridLayout">

<form id="Form1" method="post" runat="server">

</form>

</body>

</html>

語句<%@ Page language="c#" Codebehind="WebForm1.aspx.cs" AutoEventWireup="false" Inherits="e2.WebForm1" %>中的Codebehind="WebForm1.aspx.cs"表示網頁的全部代碼在文件WebForm1.aspx.cs中,使設計網頁的外觀和設計代碼分離,可同時進行設計,互不影響,也是網頁和代碼的邏輯關係清楚,增長了易讀性。代碼文件WebForm1.aspx.cs以下:

using System;

using System.Collections;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Web;

using System.Web.SessionState;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Web.UI.HtmlControls;

namespace e2

{

     /// <summary>

     /// WebForm1 的摘要說明。

     /// </summary>

     public class WebForm1 : System.Web.UI.Page

     {

         private void Page_Load(object sender, System.EventArgs e)

         {

              // 在此處放置用戶代碼以初始化頁面

         }

         #region Web Form Designer generated code

         override protected void OnInit(EventArgs e)

         {

              //

              // CODEGEN:該調用是 ASP.NET Web 窗體設計器所必需的。

              //

              InitializeComponent();

              base.OnInit(e);

         }

         /// <summary>

         /// 設計器支持所需的方法 - 不要使用代碼編輯器修改

         /// 此方法的內容。

         /// </summary>

         private void InitializeComponent()

         {   

              this.Load += new System.EventHandler(this.Page_Load);

         }

         #endregion

     }

}

9.3.7   ASP.NET和HTML兼容

任何一個靜態網頁只要把其擴展名修改成aspx,在ASP.NET下仍可運行,運行效果和之前相同。見下例,它是一個普通的靜態網頁。

<html>

<head>

<title>學生選課系統</title>

</head>

<body>

 <center>

 <h1>學生選課系統</h1>

 <form method="POST" action="c411.htm">

    <p>姓名:<input type="text" name="T1" size="20"></p>

    <p>學號:<input type="password" name="T2" size="20"></p>

    <p>課程:<select size="1" name="D1">

             <option selected>微積分</option>

             <option>代數與幾何</option>

             <option>模擬電路</option>

             <option>機械原理</option>

        </select>

    <input type="submit" value="提交" name="B1"></p>

</form>

</center>

</body>

</html>

將其以文件名c411.aspx存入d:/asp文件夾,若是d:/asp文件夾已被設定爲Web站點,能夠在IE的地址欄輸入:http://localhost/c411.aspx後,看到這個網頁。

ASP.NET的設計目標之一就是儘量地保持和現有ASP頁面的語法及運行庫的兼容。但願將現有ASP頁面文件的擴展名改成.aspx,這些頁面仍能夠在ASP.NET中運行。在大多數狀況下該目標已經實現了,但通常要對某些基本代碼做出修改,由於ASP.NET已再也不支持VBScript了,並且VB語言自己也發生了變化。

9.3.8   網頁中使用C#語句

在網頁中,能夠插入一些C#語句,具體用法見下例:

<% @ Page Language="C#"%>

<html>

  <body>

     <center>

       <% for (int i=0;i<8;i++){ %>

        <font size="<%=i%>">這是個人第一個ASP.NET網頁</font><br>

        <%}%>

    </center>

 </body>

</html>

在瀏覽器端看不到這些代碼,用IE菜單查看/源代碼,能夠看到用超文本編制的網頁。這樣使用C#語句,不是一個好的習慣,不建議使用。

 

 

第十章  Web服務器端控件

本章介紹經常使用的Web服務器端控件的屬性、事件和方法,以及用Web服務器端控件編制服務器端動態網頁的方法。

10.1  經常使用的ASP.NET服務器端控件

10.1.1    Label控件

Label控件用以下方法定義:

<asp:Label id="label1" font-size="14" font-bold="true" forecolor="red" Text="標籤控件" runat=server></asp:Label>或者

<asp:Label id="Label1" font-size="14" font-bold="true" forecolor="red" runat=server>

標籤控件</asp:Label>

下邊介紹其經常使用的屬性:

l  屬性Text:顯示的文本

l  屬性ForeColor 文本的顏色,顏色能夠取:紅色=System.Drawing.Color.Red。黑色= System.Drawing.Color.Black等等。

l  字體的屬性:黑體爲Font.Bold=true,斜體爲Font.Italic=true等等。

l  屬性BackColor:背景色

l  屬性id:至關Windows應用程序中控件的Name屬性,用來區分不一樣對象。

l  屬性sp:Label:表示本控件是Label控件。

l  屬性runat=server表示次控件運行在服務器段,由Web服務器解釋。

10.1.2TextBox控件

Label控件用以下方法定義:

<asp:TextBox id="textBox1" runat=server></asp:TextBox>

經常使用的屬性以下:

l  屬性:Text 顯示的文本

l  屬性:TextMode=SingleLine 爲編輯框,TextMode=MultiLine 爲多行編輯框,能夠有滾動條。TextMode=PassWord 爲口令編輯框。

l  屬性:MaxLength 編輯框和口令編輯框時,容許輸入的最多字符數。

l  屬性:Rows 多行編輯框時表示行數

l  事件TextChanged:控件中文本發生變化。

10.1.3    Button、LinkButton和ImageButton控件

Button控件已介紹過了,Text爲按鈕的標題,單擊事件爲:Click。

LinkButton控件:爲超級連接形式的按鈕,Text爲按鈕超級連接形式的標題,單擊事件爲Click。使用方法同Button控件,可爲其增長單擊事件Click的事件函數。

ImageButton控件:有些按鈕須要在按鈕上增長圖案,例如工具條中的按鈕,能夠使用ImageButton控件。屬性ImageUrl爲圖案的路徑,通常最好和網頁文件放在同一個目錄下,此時,控件定義以下:

<asp:ImageButton id="ImageButton1" runat="server" ImageUrl="t1.bmp"></asp:ImageButton

使用方法同Button控件,可爲其增長單擊事件Click的事件函數。

10.1.4    CheckBox和CheckBoxList控件

CheckBoxList控件能夠建立一組若干CheckBox按鈕,這些按鈕有相同的性質。這些CheckBox按鈕能夠多選,不選或都選,可用來表示一些可共存的特性,例如一我的的愛好。下面例子在窗口中加一Label控件用來顯示某人的愛好,增長兩個CheckBox按鈕,一個表明是否愛好音樂,一個表明是否愛好文學,每當用鼠標單擊CheckBox按鈕選擇或不選擇愛好,Label控件顯示實際的愛好。具體步驟以下:

(1)建立一個Web應用程序框架,選擇菜單命令創建一個新空白窗體。

(2)放工具箱的Label控件到窗體,其屬性[Text]=「你的愛好是:」。

(3)放工具箱的CheckBoxList控件到窗體。

(4)單擊屬性Items後的按鈕,出現集合編輯器對話框。單擊添加按鈕,增長一個CheckBox按鈕,修改其Text屬性爲」音樂」,用一樣方法增長另外一個CheckBox按鈕,修改其Text屬性爲」文學」。注意愛好是能夠多選的,所以必須用CheckBox控件。

(5)設定屬性AutoPosBack=true。

(6)爲CheckBox1按鈕事件(SelectedIndexChanged)函數增長語句以下:

private void CheckBoxList1_SelectedIndexChanged(object sender, System.EventArgs e)

{

     String s="你的愛好是:";

     for(int i=0;i<2;i++)

         {

              if(CheckBoxList1.Items[i].Selected)

                   s=s+CheckBoxList1.Items[i].Text;

         }

     Label1.Text=s;

}

(7)編譯,運行,選中音樂顯示:你的愛好是:音樂,再選中文學顯示:你的愛好是:音樂文學,…。

10.1.5    RadioButton和RadioButtonList控件

有一類特性是互斥的,例如性別男女,選擇這類特性可用RadioButtonList控件,該控件的最大特色是它有多個按鈕,但只能選其中的一個按鈕,下面是一個例子,兩個單選按鈕分別爲男和女,用Label控件顯示選擇的的結果。具體步驟以下:

(1) 建立一個Web應用程序框架,選擇菜單命令創建一個新空白窗體。

(2) 放工具箱的Label控件到窗體,其屬性[Text]=「男」。

(3) 放工具箱的RadioButtonList控件到窗體。

(4) 單擊屬性Items後的按鈕,出現集合編輯器對話框。單擊添加按鈕,增長一個RadioButton按鈕,修改其Text屬性爲」男」, 修改其Selected屬性爲true。用一樣方法增長另外一個RadioButton按鈕,修改其Text屬性爲」女」,修改其Selected屬性爲法false。

(5) 設定屬性AutoPosBack=true。

(6) 爲SelectedIndexChanged事件增長事件函數以下:

private void RadioButtonList1_SelectedIndexChanged(object sender, System.EventArgs e)

         {

             

              if(RadioButtonList1.SelectedIndex==0)

                 Label1.Text="男";

              else

                   Label1.Text="女";

         }

(7)    編譯,運行,單擊RadioButtonList中的兩個RadioButton按鈕,顯示所做的選擇。請想想和CheckBox按鈕的區別。

10.1.6    Image控件

Image控件用來顯示圖像,其屬性AlternateText爲字符串類型,若是圖形不被正確顯示,則顯示此字符串。屬性ImageAlign爲圖形對齊方式。ImageUrl爲圖形的URL地址。下例,增長3個單選按鈕,根據單選按鈕那個被選中,顯示不一樣的圖像。具體步驟以下:

(1) 建立一個Web應用程序框架,選擇菜單命令創建一個新空白窗體。

(2) 放工具箱的RadioButtonList控件到窗體。

(3) 單擊屬性Items後的按鈕,出現集合編輯器對話框。單擊添加按鈕,增長一個RadioButton按鈕,修改Text屬性爲」圖1」,修改Value屬性爲」p1.jpg」,修改其Selected屬性爲true。用一樣方法增長另外一個RadioButton按鈕,修改其Text屬性爲」圖2」, 修改Value屬性爲」p2.jpg」,修改其Selected屬性爲法false。

(4) 設定屬性AutoPosBack=true。

(5) 爲RadioButtonList控件的SelectedIndexChanged事件增長事件函數以下:

private void RadioButtonList1_SelectedIndexChanged(object sender, System.EventArgs e)

         {

              Image1.ImageUrl=RadioButtonList1.SelectedItem.Value;

     }

(6)    爲Page_Load事件函數增長語句:

private void Page_Load(object sender, System.EventArgs e)

         {

              // 在此處放置用戶代碼以初始化頁面

              Image1.ImageUrl=RadioButtonList1.Items[0].Value;

         }

(7)    編譯,連接,運行,單擊RadioButtonList中的兩個RadioButton按鈕,顯示不一樣的圖像。

10.1.7HyperLink控件

HyperLink控件是超級連接控件,用來從一個網頁定向到另外一個網頁。屬性Text爲設置超級連接的文字。也能夠使用圖形完成超級連接,ImageUrl爲圖形的URL。屬性NavigateUrl是定向到另外一個網頁的URL。屬性Target=_blank,打開一個新窗口,不然在原窗口打開。實現超級連接的例子的具體步驟以下:

(1) 建立一個Web應用程序框架,選擇菜單命令創建一個新空白窗體。

(2)    放工具箱的HyperLink控件到窗體。

(3)    修改屬性Text=」 超級連接」。

(4)    單擊屬性NavigateUrl後的按鈕,出現選擇URL對話框,URL類型選擇爲與根相關的,URL編輯框添入/bookExample/c412.aspx。

(5)    編譯,連接,運行,單擊HyperLink控件,在原窗口代開另外一個網頁。如屬性Target=_blank,打開一個新窗口顯示新網頁。

10.1.8Table、TableCell和TableRow控件

這是一個表格控件,建立表格的具體步驟以下:

(1)    建立一個Web應用程序框架,選擇菜單命令創建一個新空白窗體。

(2)    放工具箱的Table控件到窗體。

(3)    單擊屬性Row後的按鈕,出現選擇TableRow集合編輯器對話框,單擊添加按鈕,增長兩行。

(4)    選擇第0個TableRow,單擊屬性Cell後的按鈕,出現選擇TableCell集合編輯器對話框,單擊添加按鈕,增長三列。修改每列的屬性Text,分別爲:課程總論、剛體靜力學、彈性靜力學。

(5)    選擇第1個TableRow,單擊屬性Cell後的按鈕,出現選擇TableCell集合編輯器對話框,單擊添加按鈕,增長三列。修改每列的屬性Text,分別爲:雅舍、孩子、音樂。

(6)    能夠看到兩行三列的表,運行看一下。

10.1.9DrowDownList控件

這是一個下拉列表控件,建立下拉列表的具體步驟以下:

(7)    建立一個Web應用程序框架,選擇菜單命令創建一個新空白窗體。

(8)    放工具箱的DrowDownList控件到窗體。

(9)    單擊屬性Items後的按鈕,出現選擇ListItem集合編輯器對話框,單擊添加按鈕,增長三項。修改每項的屬性Text,分別爲:課程總論、剛體靜力學、彈性靜力學。

(10)放工具箱的Label控件到窗體,id=Label1。

(11)放工具箱的Button控件到窗體,爲單擊肯定按鈕事件(Click)函數增長語句(雙擊Click事件):

private void Button1_Click(object sender, System.EventArgs e)

         {

              Label1.Text=DropDownList1.SelectedItem.Text;

         }

(12)編譯,連接,運行,從下拉列表選擇剛體靜力學,單擊Button控件,Label1標籤控件顯示剛體靜力學。

10.2  ASP.Net控件數據綁定

所謂數據綁定技術就是把數據集的某個或者某些數據綁定到控件的某些屬性上面的一種技術。說的具體些,就是把數據集中某個或者某些數據綁定到Text控件、ListBox控件、ComBox等控件上的可以顯示數據的屬性上面。當對控件完成數據綁定後,其顯示的內容將隨着數據集的變化而變化。

10.2.1   數據綁定基礎

ASP.NET引入了新的數據綁定語法。這種很是靈活的語法容許開發人員不只能夠綁定到數據源,並且能夠綁定到簡單屬性、集合、表達式甚至是從方法調用返回的結果。
DataBind是頁和全部服務器控件的方法。當須要更新被綁定的數據時,必須調用此方法。當在父控件上調用DataBind時,該控件的全部子控件也同時調用本身的DataBind方法。例如,當調用將對DataList模板中的每一控件調用DataBind方法。在調用頁的DataBind方法,既會致使調用頁上的全部控件的DataBind方法,更新頁上全部綁定數據。一般從Page_Load事件調用DataBind,以下例所示。DataList1.DataBind()後,Page.DataBind(),
protected void Page_Load(Object Src, EventArgs E) {
DataBind();}
下面的示例說明如何將一個服務器控件的屬性綁定到另外一個服務器控件的屬性。
<html>
<head>
    <script language="C#" runat="server">
        void SubmitBtn_Click(Object sender, EventArgs e) {
          Page.DataBind();//更新頁內的全部被綁定的數據
        }
    </script>
</head>
<body>
    <h3><font face="宋體">一個服務器控件的屬性綁定到另外一個服務器控件的屬性</font></h3>
    <form runat=server>
        <asp:DropDownList id="StateList" runat="server">
          <asp:ListItem>蘋果</asp:ListItem>
          <asp:ListItem>香蕉</asp:ListItem>
          <asp:ListItem>桔子</asp:ListItem>
        </asp:DropDownList>
        <asp:button Text="提交" OnClick="SubmitBtn_Click" runat=server/>
        <p>
        選定的水果:<asp:label text='<%# StateList.SelectedItem.Text %>' runat=server/>
    </form>
</body>
</html>
網頁中語句text='<%# StateList.SelectedItem.Text %>'是將Label控件的Text屬性綁定到DropDownList控件的屬性StateList.SelectedItem.Text。符號%#表示數據綁定。函數SubmitBtn_Click中的語句Page.DataBind()更新頁內的全部被綁定的數據。若是使用Visual Studio.Net實現,具體步驟以下:

(6)建立一個Web應用程序框架,選擇菜單命令創建一個新空白窗體。

(7)放工具箱的DrowDownList控件到窗體。單擊屬性Items後的按鈕,出現選擇ListItem集合編輯器對話框,單擊添加按鈕,增長三項。修改每項的屬性Text,分別爲:課程總論、剛體靜力學、彈性靜力學。

(8)  放工具箱的Button控件到窗體,爲單擊肯定按鈕事件(Click)函數增長語句(雙擊Click事件):

private void Button1_Click(object sender, System.EventArgs e)

         {

         Page.DataBind();

         }

(9)放Label控件到窗體,id爲Label1。單擊屬性DataBinding後標題爲…的按鈕,打開Label1數據綁定對話框,選擇自定義綁定表達式(c),在其下編輯框中輸入:DropDownList1.SelectedItem.Text。單擊肯定按鈕。

(10)      運行。

10.2.2        基於變量的數據綁定

ASP.NET 數據綁定語法支持綁定到公共變量、頁的屬性和頁上其餘控件的屬性。下面的示例說明如何綁定到公共變量和頁上的簡單屬性。注意這些值在調用前初始化。DataBind()
<html>
<head>
    <script language="C#" runat="server">
        void Page_Load(Object sender, EventArgs e) {
            Page.DataBind();
        }
        string custID{//屬性
            get {
                return "ALFKI";
            }
        }
        int orderCount{
            get {
                return 11;
            }
        }
    </script>
</head>
<body>
    <h3><font face="宋體">到頁屬性的數據綁定</font></h3>
    <form runat=server>
        客戶:<b><%# custID %></b><br>
        未結的訂單:<b><%# orderCount %></b>
    </form>
</body>
</html>
用Visual Studio.Net實現的方法見上例及書。

10.2.3    基於集合的綁定

像DataGrid、ListBox、DrowDownList和HTMLSelect這樣的列表服務器控件的列表均可以綁定到數據源。例如綁定到公共語言運行庫的集合類型,如ArrayList、DataView、Hashtable和DataReader等。下面的示例說明如何將DrowDownList的列表綁定到ArrayList。
<html>
<head>
    <script language="C#" runat="server">
        void Page_Load(Object Sender, EventArgs E) {
            if (!Page.IsPostBack) {
               ArrayList values = new ArrayList();
               values.Add ("IN");
               values.Add ("KS");
               values.Add ("MD");
               values.Add ("MI");
               values.Add ("OR");
               values.Add ("TN");
               DropDown1.DataSource =values;
               DropDown1.DataBind();
            }
        }
        void SubmitBtn_Click(Object sender, EventArgs e) {
           Label1.Text = "您選擇了:" + DropDown1.SelectedItem.Text;
        }
    </script>
</head>
<body>
    <h3><font face="宋體">數據綁定 DropDownList</font></h3>
    <form runat=server>
      <asp:DropDownList id="DropDown1" runat="server" />
      <asp:button Text="提交" OnClick="SubmitBtn_Click" runat=server/>
      <p>
      <asp:Label id=Label1 font-name="宋體" font-size="10.5pt" runat="server" />
    </form>
</body>
</html>
下面的示例說明如何把數據表綁定到DataGrid。注意使用DataView類要引用命名空間System.Data,即語句<%@ Import namespace="System.Data" %>。具體例子以下:
<%@ Import namespace="System.Data" %>
<html>
<head>
<script language="C#" runat="server">
  void Page_Load(Object sender, EventArgs e ) {
   if (!Page.IsPostBack) {
     DataTable dt = new DataTable();//創建一個數據表
     DataRow dr;//創建一個數據表的記錄變量
     dt.Columns.Add(new DataColumn("整數值", typeof(Int32)));//增長字段
     dt.Columns.Add(new DataColumn("字符串值", typeof(string)));//包括字段名
     dt.Columns.Add(new DataColumn("日期時間值", typeof(DateTime)));//及字段類型
     dt.Columns.Add(new DataColumn("布爾值", typeof(bool)));
     for (int i = 1; i <= 9; i++) {//增長10個記錄
        dr = dt.NewRow();//創建1個記錄對象
        dr[0] = i;//爲記錄的每一個字段賦值
        dr[1] = "項 " + i.ToString();
        dr[2] = DateTime.Now;
        dr[3] = (i % 2 != 0) ? true : false;
        dt.Rows.Add(dr);//把此記錄加到數據表中
        }
       dataGrid1.DataSource = new DataView(dt);//爲dataGrid指定數據源
       dataGrid1.DataBind();//數據更新
       }
    }
  </script>
</head>
<body>
    <h3><font face="宋體">到 DataView 的數據綁定</font></h3>
    <form runat=server>
        <asp:DataGrid id="dataGrid1" runat="server"
          BorderColor="black"
          BorderWidth="1"
          GridLines="Both"
          CellPadding="3"
          CellSpacing="0"
          HeaderStyle-BackColor="#aaaadd"
        />
    </form>
</body>
</html>
下面的示例說明如何綁定到Hashtable。
<html>
<head>
    <script language="C#" runat="server">
        void Page_Load(Object sender, EventArgs e) {
            if (!Page.IsPostBack) {
                Hashtable h = new Hashtable();//注意哈希表的使用
                h.Add ("鍵 1", "值 1");//哈希表的每個元素是一對鍵和值
                h.Add ("鍵 2", "值 2");
                h.Add ("鍵 3", "值 3");
                MyDataList.DataSource=h;//爲列表框指定數據源
                MyDataList.DataBind();//數據更新
            }
        }
    </script>
</head>
<body>
    <h3><font face="宋體">到哈希表的數據綁定</font></h3>
    <form runat=server>
        <asp:DataList id="MyDataList" runat="server"
          BorderColor="black"
          BorderWidth="1"
          GridLines="Both"
          CellPadding="4"
          CellSpacing="0"
          >
            <ItemTemplate>
                <%# ((DictionaryEntry)Container.DataItem).Key %> :
                <%# ((DictionaryEntry)Container.DataItem).Value %>
            </ItemTemplate>
        </asp:DataList>
    </form>
</body>
</html>
標記<ItemTemplate>指定顯示格式</ItemTemplate>是按指定顯示格式重複顯示數據源中的全部數據。本例中應顯示3組數據,指定顯示格式爲:鍵1:值。
下面介紹如何將ListBox、DrowDownList和HTMLSelect這樣的列表服務器控件的列表綁定到數據表的某一字段上。
<%@ Import namespace="System.Data" %>
<html>
<head>
<script language="C#" runat="server">
  void Page_Load(Object sender, EventArgs e ) {
   if (!Page.IsPostBack) {
     DataTable dt = new DataTable();//創建一個數據表
     DataRow dr;//創建一個數據表的記錄變量
     dt.Columns.Add(new DataColumn("Itemid", typeof(Int32)));//增長字段
     dt.Columns.Add(new DataColumn("ItemName", typeof(string)));//包括字段名
     dt.Columns.Add(new DataColumn("ItemDate", typeof(DateTime)));//及字段類型
     dt.Columns.Add(new DataColumn("ItemBool", typeof(bool)));
     for (int i = 1; i <= 9; i++) {//增長10個記錄
        dr = dt.NewRow();//創建1個記錄對象
        dr[0] = i;//爲記錄的每一個字段賦值
        dr[1] = "項 " + i.ToString();
        dr[2] = DateTime.Now;
        dr[3] = (i % 2 != 0) ? true : false;
        dt.Rows.Add(dr);//把此記錄加到數據表中
        }
       StateList.DataSource = new DataView(dt);//爲DropDownList指定數據源
       StateList.DataTextField="ItemName";
       StateList.DataValueField="Itemid";
       StateList.DataBind();//數據更新
       }
    }
   void SubmitBtn_Click(Object sender, EventArgs e) {
    Label1.Text="StateList的Text="+StateList.SelectedItem.Text+":StateList的Value="+StateList.SelectedItem.Value;
   }
 
  </script>
</head>
<body>
    <h3><font face="宋體">到StateList的數據綁定</font></h3>
    <form runat=server>
        <asp:DropDownList id="StateList" runat="server"/>
         <asp:button Text="提交" OnClick="SubmitBtn_Click" runat=server/>
         <br>
        <asp:Label id="Label1" runat="server"/>
    </form>
</body>
</html>

10.2.4   基於表達式綁定

一般須要在綁定到頁或控件以前操做數據。下面的示例說明如何綁定到表達式和方法的返回值。

<html>
<head>
    <script language="C#" runat="server">
        void Page_Load(Object Src, EventArgs E) {
            if (!Page.IsPostBack) {
               ArrayList values = new ArrayList();
               values.Add (0);
               values.Add (1);
               values.Add (2);
               values.Add (3);
               values.Add (4);
               values.Add (5);
               values.Add (6);
               DataList1.DataSource = values;
               DataList1.DataBind();
            }
        }
        String EvenOrOdd(int number) {
            if ((number % 2) == 0)
              return "偶數";
            else
              return "奇數";
        }
    </script>
</head>
<body>
  <h3><font face="宋體">到方法和表達式的數據綁定</font></h3>
  <form runat=server>
    <asp:DataList id="DataList1" runat="server"
      BorderColor="black"
      BorderWidth="1"
      GridLines="Both"
      CellPadding="3"
      CellSpacing="0"
      >
      <ItemTemplate>
       數字值:<%# Container.DataItem %><%--Container表示數據源--%>
       偶/奇:<%# EvenOrOdd((int) Container.DataItem) %><%--綁定到函數返回值--%>
      </ItemTemplate>
    </asp:datalist>
  </form>
</body>
</html>

10.2.5基於DataBinder.Eval方法的數據綁定

爲將綁定的數據按指定數據類型轉化爲字符串,能夠使用String.Format方法。請看下面的示例,該例要將數據表中字段名爲"IntegerValue"的數據轉換爲貨幣的數據類型的字符串輸出。
<%# String.Format("{0:c}",((DataRowView)Container.DataItem)["IntegerValue"])%>
該語法可能比較複雜,難以記憶。ASP.NET提供了一種靜態方法DataBinder.Eval,能夠將綁定的數據按指定數據類型轉化爲字符串。該方法使用很方便,由於它消除了開發人員爲強迫將數值轉換爲所需的數據類型而必須作的許多顯式轉換。這在數據綁定模板列表內的控件時尤爲有用,由於一般數據字段的類型都必須轉換。爲將整數顯示爲貨幣字符串,使用#DataBinder.Eval格式以下:
<%#DataBinder.Eval(Container.DataItem, "IntegerValue", "{0:c}") %>
DataBinder.Eval是一個具備三個參數的方法,第一個參數是數據源的當前記錄,在象DataList、DataGrid或Repeater這樣的模板列表中,該參數始終是,第二個參數是數據表字段名,表示要將此字段的數據轉換爲第三個參數指定的數據類型的字符串,第三個參數爲格式字符串,{0:c}表示貨幣類型。格式字符串參數是可選的。若是省略它,則 DataBinder.Eval將此字段的數據轉換爲字段自己的數據類型的字符串,以下例所示,輸出爲字符串"true"或"false"。Container.DataItem
<%# (bool)DataBinder.Eval(Container.DataItem, "BoolValue") %>
具體的實例以下:
<%@ Import namespace="System.Data" %>
<html>
<head>
    <script language="C#" runat="server">
        void Page_Load(Object sender, EventArgs e) {
            if (!Page.IsPostBack) {
                DataTable dt = new DataTable();
                DataRow dr;
                dt.Columns.Add(new DataColumn("IntegerValue", typeof(Int32)));
                dt.Columns.Add(new DataColumn("StringValue", typeof(string)));
                dt.Columns.Add(new DataColumn("DateTimeValue", typeof(DateTime)));
                dt.Columns.Add(new DataColumn("BoolValue", typeof(bool)));
                for (int i = 0; i < 9; i++) {
                    dr = dt.NewRow();
                    dr[0] = i;
                    dr[1] = "項 " + i.ToString();
                    dr[2] = DateTime.Now;
                    dr[3] = (i % 2 != 0) ? true : false;
                    dt.Rows.Add(dr);
                }
                dataList1.DataSource = new DataView(dt);
                dataList1.DataBind();
            }
        }
    </script>
</head>
<body>
    <h3><font face="宋體">使用 DataBinder.Eval 進行數據綁定</font></h3>
    <form runat=server>
        <asp:DataList id="dataList1" runat="server"
          RepeatColumns="3"
          Width="80%"
          BorderColor="black"
          BorderWidth="1"
          GridLines="Both"
          CellPadding="4"
          CellSpacing="0"
          >
            <ItemTemplate>
                訂購日期:<%# DataBinder.Eval(Container.DataItem, "DateTimeValue", "{0:d}") %>
 
                <p>
                數量:<%# DataBinder.Eval(Container.DataItem, "IntegerValue", "{0:N2}") %>
                <p>
                項:<%# DataBinder.Eval(Container.DataItem, "StringValue") %>
                訂購日期: <asp:CheckBox id=chk1 Checked='<%# (bool)DataBinder.Eval(Container.DataItem, "BoolValue") %>' runat=server/>
                <p>
            </ItemTemplate>
        </asp:Datalist>
    </form>
</body>
</html>

控件DataList中的ItemTemplate是模板控件,其功能是將控件DataList的數據源中的全部數據,按ItemTemplate模板控件所指定的格式顯示。

10.2.6列表綁定控件

列表綁定控件通用屬性
1. DataSource 屬性
DataList、DataGraid和Repeater都提供了DataSource屬性。使用DataSource屬性指定要綁定到上述三種數據列表控件的數據源,用數據源中的數據填充上述三種數據列表控件。數據源必須是實現System.Collections.ICollection接口的具備相同對象的集合,例如System.Data.DataView(見6.3節最後例子)、System.Collections.ArrayList(見6.3節例1)和System.Collections.Hashtable(見6.3節哈希表例子)。
2. Items 集合
Items是一個集合屬性,包含一些具備相同特徵的若干對象的集合。DataList、DataGraid和Repeater控件中包含多個Items集合屬性,使用Items集合用來以編程的方式控制DataList、DataGraid和Repeater控件中的各項。例如:
a)   AlternatingItem:DataGraid中全部奇數編號行的項的集合
b)   SelectedItem:當前選中的全部項的集合。
c)   EditItem:正在編輯的行中全部項的集合。例子見7.2.4 更新數據的語句MyDataGrid.EditItemIndex = (int)E.Item.ItemIndex;。
以上各項都和數據源有關,如下各項和數據源無關。
d)   Header:全部列表表頭項的集合
e)   Footer: 全部列表表尾項的集合
f)   Separtor:DataGraid和Repeater控件中分隔符線的集合
g)   Page:DataGraid在分頁顯示中,每頁數據項的集合。
3.數據綁定和Items集合的建立
當爲DataList、DataGraid和Repeater等列表控件的屬性DataSource指定數據源,並執行數據綁定函數DataBind方法後,列表控件將建立Items集合,並從數據源取得顯示所需的數據,能夠經過Items屬性來得到列表控件中各項的內容。注意,只有綁定到數據源的項才包含在Items集合中。頁眉、頁腳和分隔符不包含在該集合中。下面的示例展現如何使用 Items集合來顯示DataList控件中的項。
<%@ Import Namespace="System.Data" %>
<html>
   <script language = "C#" runat="server">
      ICollection CreateDataSource() 
      {
         DataTable dt = new DataTable();
         DataRow dr;
         dt.Columns.Add(new DataColumn("StringValue", typeof(string)));
         for (int i = 0; i < 10; i++) 
         {
            dr = dt.NewRow();
            dr[0] = "Item " + i.ToString();
            dt.Rows.Add(dr);
         }
         DataView dv = new DataView(dt);
         return dv;
      }
      void Page_Load(Object sender, EventArgs e) 
      {
         if (!IsPostBack) 
         {
            DataList1.DataSource = CreateDataSource();//指定數據源
            DataList1.DataBind();//數據綁定
         }
      }
      void Button_Click(Object sender, EventArgs e)
      { 
         if (DataList1.Items.Count>0)//Items項數>0
         {
            Label1.Text = "The Items collection contains: <br>";
 
            foreach(DataListItem item in DataList1.Items)
            {
        
               Label1.Text += ((DataBoundLiteralControl)item.Controls[0]).Text +
                              "<br>";
            }
         }
      } 
 
   </script>
 
<body>
 
   <form runat=server>
 
      <h3>DataList Items Example</h3>
 
      <asp:DataList id="DataList1" runat="server"
           BorderColor="black"
           CellPadding="3"
           Font-Name="Verdana"
           Font-Size="8pt">
 
         <HeaderStyle BackColor="#aaaadd">
         </HeaderStyle>
 
         <AlternatingItemStyle BackColor="Gainsboro">
         </AlternatingItemStyle>
 
         <HeaderTemplate>
 
            Items
 
         </HeaderTemplate>
               
         <ItemTemplate>
 
            <%# DataBinder.Eval(Container.DataItem, "StringValue") %>
 
         </ItemTemplate>
 
      </asp:DataList>
 
        <br><br>
 
      <asp:Button id="Button1"
           Text="顯示DataList1表第一列的全部內容"
           OnClick="Button_Click"
           runat="server"/>
 
      <br><br>
 
      <asp:Label id="Label1"
           runat="server"/>
 
   </form>
 
</body>
</html>

若是使用控件DataGrid,有時須要知道指定行的指定列的數據,表達式DataGrid1.Items[2].Cells[1].Text表示網格控件DataGrid1的第2行第1列的文本。具體例子以下:

<%@ Import namespace="System.Data" %>

<html>

<head>

<script language="C#" runat="server">

  void Page_Load(Object sender, EventArgs e ) {

   if (!Page.IsPostBack) {

     DataTable dt = new DataTable();//創建一個數據表

     DataRow dr;//創建一個數據表的記錄變量

     dt.Columns.Add(new DataColumn("整數值", typeof(Int32)));//增長字段

     dt.Columns.Add(new DataColumn("字符串值", typeof(string)));//包括字段名

     dt.Columns.Add(new DataColumn("日期時間值", typeof(DateTime)));//及字段類型

     dt.Columns.Add(new DataColumn("布爾值", typeof(bool)));

     for (int i = 1; i <= 9; i++) {//增長10個記錄

        dr = dt.NewRow();//創建1個記錄對象

        dr[0] = i;//爲記錄的每一個字段賦值

        dr[1] = "項 " + i.ToString();

        dr[2] = DateTime.Now;

        dr[3] = (i % 2 != 0) ? true : false;

        dt.Rows.Add(dr);//把此記錄加到數據表中

        }

       dataGrid1.DataSource = new DataView(dt);//爲dataGrid指定數據源

       dataGrid1.DataBind();//數據更新

       }

    }

   void Button_Click(Object sender, EventArgs e)

   {

    Label1.Text=dataGrid1.Items[2].Cells[1].Text;

   }

</script>

</head>

<body>

    <form runat=server>

        <asp:DataGrid id="dataGrid1" runat="server"

          BorderColor="black"

          BorderWidth="1"

          GridLines="Both"

          CellPadding="3"

          CellSpacing="0"

          HeaderStyle-BackColor="#aaaadd"

        />

      <br><br>

        <asp:Button id="Button1"

           Text="顯示DataGrid1表第二行第一列的內容"

           OnClick="Button_Click"

           runat="server"/>

      <br><br>

        <asp:Label id="Label1" runat="server"/>

 

    </form>

</body>

</html>

3. Style
使用DataList和DataGraid的屬性Style可定義控件的外觀。見下例:
<asp:DataGrid id="grid" runat="server" visible="false"
         CssClass="Shadow" BackColor="white"
         CellPadding="2" CellSpacing="2" GridLines="none" 
         BorderStyle="solid" BorderColor="black" BorderWidth="1"
         font-size="x-small" font-names="verdana">
 
         <AlternatingItemStyle BackColor="palegoldenrod" />
         <ItemStyle BackColor="beige" />
         <HeaderStyle ForeColor="white" BackColor="brown" Font-Bold="true" />
</asp:DataGrid>
其中定義了控件DataGraid的背景爲白色,邊界爲黑實線,寬度爲1個象素,字體爲"x-small",字體名字爲"verdana"。奇數行的背景顏色,標題的字的顏色,背景色。數據項的背景色等等。顯示效果見7.1.2的例子。
4. ItemTemplate 屬性

控件DataList中的ItemTemplate是模板控件,其功能是將控件DataList的數據源中的全部數據,按ItemTemplate模板控件所指定的格式顯示。DataList 控件中項的外觀由ItemStyle屬性控制。還能夠使用 AlternatingItemTemplate 屬性來控制 DataList 控件中交替項的內容。具體例子見6.6節中3.數據綁定和Items集合的建立的例子。

DataGraid控件沒有ItemTemplate模板,可以使用模板列控件TemplateColumn,在模板列控件中增長ItemTemplate模板本身定義該列的顯示控件或顯示格式,具體例子見7.1.6列類型的第3和第4個例子。還能夠在其中增長EditItemTemplate模板本身定義該列在編輯時使用的控件,具體例子見7.2.5節例子。
Repeater控件的ItemTemplate模板見8.4節例子。
5. 模板中的數據綁定
模板中的數據綁定的例子見上一節中的例子。
6.6.2 使用列表綁定控件
<%@ Import Namespace="System.Data" %>
 
<html>
   <script language = "C#" runat="server">
 
      ICollection CreateDataSource() 
      {
         DataTable dt = new DataTable();
         DataRow dr;
 
         dt.Columns.Add(new DataColumn("StringValue", typeof(string)));
  
         for (int i = 0; i < 10; i++) 
         {
            dr = dt.NewRow();
            dr[0] = "Item " + i.ToString();
            dt.Rows.Add(dr);
         }
 
         DataView dv = new DataView(dt);
         return dv;
      }
 
      void Page_Load(Object sender, EventArgs e) 
      {
         if (!IsPostBack) 
         {
            DataList1.DataSource = CreateDataSource();
            DataList1.DataBind();
         }
      }
 
      void Button1_Click(Object sender, EventArgs e) 
      {
 
         if (DropDown1.SelectedIndex == 0)
            DataList1.RepeatDirection = RepeatDirection.Horizontal;
         else
            DataList1.RepeatDirection = RepeatDirection.Vertical;
 
         if (DropDown2.SelectedIndex == 0)
            DataList1.RepeatLayout = RepeatLayout.Table;
         else
            DataList1.RepeatLayout = RepeatLayout.Flow;
 
         DataList1.RepeatColumns=DropDown3.SelectedIndex+1;
 
         if ((Check1.Checked ==true) && (DataList1.RepeatLayout == RepeatLayout.Table)) 
         {
            DataList1.BorderWidth = Unit.Pixel(1);
            DataList1.GridLines = GridLines.Both;
         }    
         else  
         {
            DataList1.BorderWidth = Unit.Pixel(0);
            DataList1.GridLines = GridLines.None;
         }    
      }    
 
   </script>
 
<body>
 
   <form runat=server>
 
      <h3>DataList Example</h3>
 
      <asp:DataList id="DataList1" runat="server"
           BorderColor="black"
           CellPadding="3"
           Font-Name="Verdana"
           Font-Size="8pt">
 
         <HeaderStyle BackColor="#aaaadd">
         </HeaderStyle>
 
         <AlternatingItemStyle BackColor="Gainsboro">
         </AlternatingItemStyle>
 
         <HeaderTemplate>
 
            Items
 
         </HeaderTemplate>
               
         <ItemTemplate>
 
            <%# DataBinder.Eval(Container.DataItem, "StringValue") %>
 
         </ItemTemplate>
 
         <AlternatingItemTemplate>
 
            *
            <%# DataBinder.Eval(Container.DataItem, "StringValue") %>
 
         </AlternatingItemTemplate>
 
      </asp:DataList>
 
      <p>
      <hr noshade align="left" width="300px">
 
      RepeatDirection:
 
      <asp:DropDownList id=DropDown1 runat="server">
 
         <asp:ListItem>Horizontal</asp:ListItem>
         <asp:ListItem>Vertical</asp:ListItem>
 
      </asp:DropDownList><br>
 
      RepeatLayout:
 
      <asp:DropDownList id=DropDown2 runat="server">
 
         <asp:ListItem>Table</asp:ListItem>
         <asp:ListItem>Flow</asp:ListItem>
 
      </asp:DropDownList><br>
 
      RepeatColumns:
 
      <asp:DropDownList id=DropDown3 runat="server">
 
         <asp:ListItem>1</asp:ListItem>
         <asp:ListItem>2</asp:ListItem>
         <asp:ListItem>3</asp:ListItem>
         <asp:ListItem>4</asp:ListItem>
         <asp:ListItem>5</asp:ListItem>
 
      </asp:DropDownList><br>
         
      Show Borders: 
 
      <asp:CheckBox id=Check1 runat="server" /><p>
         
      <asp:LinkButton id=Button1 
           Text="Refresh DataList" 
           OnClick="Button1_Click" 
           runat="server"/>
 
   </form>
 
</body>
</html>
若是使用Visual Studio.Net實現模板,具體步驟以下:

本節小結

  1. ASP.NET 聲明性數據綁定語法使用 <%# %> 表示法。
  2. 能夠綁定到數據源、頁或其餘控件的屬性、集合、表達式以及從方法調用返回的結果。
  3. 列表控件能夠綁定到支持 ICollectionIEnumerableIListSource 接口的集合,如 ArrayListHashtableDataViewDataReader
  4. DataBinder.Eval 是用於晚期綁定的靜態方法。它的語法可能比標準數據綁定語法簡單,但性能較低。

 

10.3  數據驗證控件

用戶輸入了數據,在提交前,首先要對輸入的數據進行驗證。固然,能夠本身編程序進行驗證。ASP.NET提供了一些驗證控件,能夠不用編程完成對輸入的數據進行驗證。本節介紹如何使用這些數據驗證控件。

10.3.1    數據驗證概述

對用戶輸入的數據進行驗證,能夠在客戶端進行。實現原理是當用戶輸入了信息並單擊提交按鈕後,用在客戶端運行的JavaScript腳本或VBScript腳本對數據驗證,只有全部數據正確,才能發送到服務器端處理。此種方法的優勢是運行在客戶端,所以反應速度快,減輕了服務器和網絡的負載。缺點是因爲JavaScript腳本或VBScript腳本是以明文的方式嵌入在HTML文檔中,客戶端能夠看到這些腳本程序,若是用戶把這段腳本刪除,網頁也就失去了驗證功能,所以這種方法是不安全的。

另外一種數據驗證方法是在服務器端進行,當用戶輸入了信息並單擊提交按鈕後,把數據馬上發送到服務器端,在服務器端驗證,若是驗證不經過,返回錯誤信息。這種方法雖然在響應速度比較慢,增長了服務器的負擔,但可靠性上要強的不少。

ASP.NET提供了一些驗證控件,能夠不用編程完成對輸入的數據進行驗證。下邊是一個使用驗證控件簡單的例子,該例以數據驗證控件RequiredFieldValidator爲例,介紹數據驗證控件屬性的使用方法。有些數據用戶是必須輸入的,這些數據能夠用編輯控件,單選或多選按鈕等控件輸入。能夠用控件RequiredFieldValidator對這些控件輸入的數據進行驗證,檢查用戶是否輸入了數據。控件RequiredFieldValidator的屬性ControlToValidate的值選擇要驗證的控件的id值,能夠是編輯控件,單選或多選按鈕等。屬性ErrorMessage是發生錯誤時,提示的錯誤信息。用戶用編輯控件textBox1輸入姓名,要求必須輸入。用控件RequiredFieldValidator1對其輸入進行驗證,所以屬性ControlToValidate= textBox1。屬性ErrorMessage=」必須輸入姓名」。當單擊提交按鈕後,若是用戶沒有輸入姓名,則用」必須輸入姓名」提示用戶。

<html>

<body>

<form id="Form1" method="post" runat="server">

<p>姓名:<asp:TextBox id=" TextBox1" runat="server"/></p>

<p><asp:Button Text="提交" runat=server/></p>

<asp:RequiredFieldValidator id="RequiredFieldValidator1" runat="server"

ErrorMessage="RequiredFieldValidator" ControlToValidate="RadioButtonList1">

</asp:RequiredFieldValidator>

</form>

</body>

</html>

10.3.2    經常使用的驗證控件

.Net框架類庫中提供如下幾種驗證控件:

l  RequiredFieldValidator控件

l  自定義數據驗證控件CustomValidator控件

l  ValidationSummary控件

l  CompareValidator控件

RegularExpressionValidator 控件

10.3.3    驗證控件經常使用的屬性

l  屬性ControlToValidate:要驗證的控件的id值。

l  屬性ErrorMessage:發生錯誤時,提示的錯誤信息。

l  屬性Display:

l  屬性IsValid:

l  屬性Text:

10.3.4    RequiredFieldValidator

上邊已介紹用記事本編輯網頁如何使用此控件,下邊的例子用Visual Studio.Net 編輯。該例子增長一個RadioList控件,輸入卡的類型,增長一個編輯控件,輸入編號,二者都要求必須輸入,用兩個RequiredFieldValidator控件驗證。步驟以下:

(1)建立一個Web應用程序框架,選擇菜單命令創建一個新空白窗體。

(2)放工具箱的Label控件到窗體,其屬性[Text]=「RequiredFieldValidator控件的使用」。Id=Label1。

(3)放工具箱的Label控件到窗體,其屬性[Text]=「輸入卡號」。

(4)放工具箱的RadioButtonList控件到窗體,id=RadioButtonList1。

(5)單擊屬性Items後的按鈕,出現集合編輯器對話框。單擊添加按鈕,增長一個RadioButton按鈕,修改其Text屬性爲」蘋果卡」,修改其Selected屬性爲法false。用一樣方法增長另外一個RadioButton按鈕,修改其Text屬性爲」橡膠卡」,修改其Selected屬性爲法false。

(6)放工具箱的Label控件到窗體,其屬性[Text]=「輸入編號」。

(7)放工具箱的TextBox控件到窗體,id=TextBox1。

(8)放工具箱的RequiredFieldValidator控件到窗體, 屬性ControlToValidate= RadioButtonList1, 屬性ErrorMessage=」必須輸入卡類型」。

(9)放工具箱的RequiredFieldValidator控件到窗體, 屬性ControlToValidate=TextBox1, 屬性ErrorMessage=」必須輸入編號」。

(10)      放工具箱的Button控件到窗體,爲其增長單擊事件函數以下:

private void Button1_Click(object sender, System.EventArgs e)

         {

              if(Page.IsValid==true)

                   Label1.Text="已輸入了數據";

              else

                   Label1.Text="至少有一項未輸入了數據";

         }

(11)  如運行出錯,把C:\inetpub\wwwroot\aspnet_client文件夾拷貝到D:\Asp文件夾下。運行

10.3.5    自定義數據驗證控件CustomValidator控件

CustomValidator控件容許編程者本身定義一個函數對數據進行驗證。通常數據驗證分爲客戶端驗證和服務器端驗證,能夠修改驗證控件的屬性ClientTarget改變在那端驗證,例如:Page.ClientTarget=ClientTarget.Downlevel語句表示要在服務器端驗證,而語句Page.ClientTarget=ClientTarget.Uplevel表示在客戶端驗證,在客戶端驗證必須在發佈目錄下包含C:\inetpub\wwwroot\aspnet_client文件夾。所以,編程者要根據在那一端驗證,編寫不一樣的函數,在服務器端驗證函數定義以下:

void ServerValidate(object source, ServerValidateEventArgs args){//驗證語句}

在客戶端驗證函數定義以下:?

void ClientValidate(source,value){//驗證語句}

書中的例子以下:

<%@ Page Language="C#" %>

 

<html>

<head>

  

 

   <script runat=server>

 

      void ValidateBtn_OnClick(object sender, EventArgs e)

      {

         if (Page.IsValid)

         {

            lblOutput.Text = "Page is valid.";

         }

         else

         {

            lblOutput.Text = "Page is not valid!";

         }

      }

 

      void ServerValidate(object source, ServerValidateEventArgs args)

      {

         try

         {

            int i = int.Parse(args.Value);

            args.IsValid = ((i%2) == 0);

         }

 

         catch

         {

            args.IsValid = false;

         }

      }

 

   </script>   

 

</head>

<body>

 

   <form runat="server">

 

      <h3>CustomValidator Example</h3>

 

      <asp:Label id=lblOutput runat="server"

           Text="Enter an even number:"

           Font-Name="Verdana"

           Font-Size="10pt" /><br>

 

      <p>

 

      <asp:TextBox id="Text1"

           runat="server" />

   

      &nbsp;&nbsp;

 

      <asp:CustomValidator id="CustomValidator1"

        ControlToValidate="Text1" ErrorMessage="Not an even number!"

        OnServerValidate="ServerValidate" runat="server"/>

 

      <p>

 

      <asp:Button id="Button1"

           Text="Validate"

           OnClick="ValidateBtn_OnClick"

           runat="server"/>

 

   </form>

 

</body>

</html>

</html>

用Visual Studio.NET實現此例,具體步驟以下:

(1)建立一個Web應用程序框架,選擇菜單命令創建一個新空白窗體。

(2)放工具箱的Label控件到窗體,其屬性[Text]=「CustomValidator 控件的使用」。Id=Label1。

(3)放工具箱的Label控件到窗體,其屬性[Text]=「鍵入一個偶數」。

(4)放工具箱的TextBox控件到窗體,id=TextBox1。

(5)放工具箱的CustomValidator控件到窗體,id=CustomValidator1,屬性ControlToValidate=TextBox1, 屬性ErrorMessage=Not an even number!。

(6)放工具箱的Button控件到窗體,爲其增長單擊事件函數以下:

void ValidateBtn_OnClick(Object sender,EventArgs e)

       {   If (Page.IsValid)

              lblOutput.Text = "Page is Valid!";

           else

              lblOutput.Text = "Page is InValid!";

        }

 

(7)爲CustomValidator控件ServerValidate事件增長事件函數以下

private void CustomValidator1_ServerValidate(object source, System.Web.UI.WebControls.ServerValidateEventArgs args)

         {

              try

              {

                   int i = int.Parse(args.Value);

                   args.IsValid = ((i%2) == 0);

              }

 

              catch

              {

                   args.IsValid = false;

              }

}

(8) 

10.3.6    ValidationSummary控件

當用戶提交了數據後,全部驗證控件對數據進行驗證,若是沒有錯誤,設置Page.IsValid=true,不然=false。若是在頁面中放置了控件ValidationSummary,它將自動顯示發現錯誤的數據驗證控件的屬性ErrorMessage的內容。能夠在5.2.1的例子中,增長一個ValidationSummary控件,運行後看一下效果。

10.3.7    CompareValidator控件

CompareValidator控件能夠對兩個控件輸入的值進行比較。屬性ControlToValidate=控制對象的id,屬性ValueToCompare=要比較得值,屬性Type=比較的數據類型,屬性Operator=如何比較,能夠是:Equal、NotEqual、GreatrThan、GreatrThanEqual、LessThan、LessThanEqual。用Visual Studio.NET實現此例,具體步驟以下:

(1)建立一個Web應用程序框架,選擇菜單命令創建一個新空白窗體。

(2)放三個Label控件到窗體,其屬性[Text]分別爲」First string」、」Second string」和」lblOutput」。id分別爲Label一、Label2和lblOutput。

(3)在Label1和Label2控件後,分別放置TextBox控件,id分別爲TextBox1和TextBox2。

(4)放工具箱的CompareValidator控件到窗體,屬性ControlToValidate=TextBox1,屬性ControlToCompare=TextBox2,屬性ErrorMessage=Not an even number!,id=Compare1。

(5)放兩個ListBox控件到窗體,id分別爲ListOperator和ListType。

(6)單擊ListOperator屬性Items旁的三個小點,在ListItem編輯器對話框中單擊添加按鈕,增長6個選項,屬性Text分別爲:Equal、NotEqual、GreatrThan、GreatrThanEqual、LessThan、LessThanEqual,同時,屬性Value也變爲相應的值。

(7)單擊ListType屬性Items旁的三個小點,在ListItem編輯器對話框中單擊添加按鈕,增長5個選項,屬性Text分別爲:String、Integer、Double、Date、Currency,同時,屬性Value也變爲相應的值。

(8)設置兩個ListBox控件屬性SelectionMode爲Single,不容許多選。(爲何?)

(9)設置兩個ListBox控件屬性AutoPostBack=true。

(10)      爲ListOperator事件(SelectedIndexChenged)增長事件函數以下:

private void ListOperator_SelectedIndexChanged(object sender, System.EventArgs e)

         {

              Compare1.Operator=(ValidationCompareOperator)ListOperator.SelectedIndex;

              Compare1.Validate();

         }

(11)      爲ListType事件(SelectedIndexChenged)增長事件函數以下:

private void ListType_SelectedIndexChanged(object sender, System.EventArgs e)

         {

              Compare1.Type=(ValidationDataType)ListType.SelectedIndex;

              Compare1.Validate();

         }

(12)      放工具箱的Button控件到窗體,爲其增長單擊事件函數以下:

private void Button1_Click(object sender, System.EventArgs e)

         {

              //Label1.Text=DropDownList1.SelectedItem.Text;

              if(Page.IsValid==true)

                   lblOutput.Text="數據有效";

              else

                   lblOutput.Text="數據無效";

         }

(13)      運行,看一下效果。增長列表內容用以下語句

listBox1.Items.Add("Item9");//在列表最後增長一項
listBox1.SetSelected(1, true);//第一項被選中

       listBox1.EndUpdate();//更新

5.2.5 RangeValidator 控件

RangeValidator 控件測試輸入控件的值是否在指定範圍內。RangeValidator 控件使用四個關鍵屬性執行驗證。ControlToValidate 屬性包含要驗證的輸入控件。MinimumValue 和 MaximumValue 屬性指定有效範圍的最大值和最小值。BaseCompareValidator.Type 屬性用於指定要比較的值的數據類型。在執行驗證操做以前,要比較的值被轉換爲此數據類型。能夠進行比較的不一樣數據類型: 字符串數據類型String、32 位有符號整數數據類型Integer、雙精度浮點數數據類型Double、日期數據類型Date、一種能夠包含貨幣符號的十進制數據類型Currency。

下面的示例說明如何在 Web 頁上建立 RangeValidator 控件,以檢查輸入到輸入控件的值是否在比較範圍內。

<%@ Page Language="C#" %>
<html>
<head>
   <script runat="server">
      void ButtonClick(Object sender, EventArgs e)
      {
         if (Page.IsValid)
         {
            Label1.Text="Page is valid.";
         }
         else
         {
            Label1.Text="Page is not valid!!";
         }
      }
   </script>
</head>
 
<body>
   <form runat="server">
      <h3>RangeValidator Example</h3>
      Enter a number from 1 to 10:
      <br>
      <asp:TextBox id="TextBox1"
           runat="server"/>
      <br>
      <asp:RangeValidator id="Range1"
           ControlToValidate="TextBox1"
           MinimumValue="1"
           MaximumValue="10"
           Type="Integer"
           EnableClientScript="false"
           Text="The value must be from 1 to 10!"
           runat="server"/>
      <br><br>
      <asp:Label id="Label1"
           runat="server"/>
      <br><br>
      <asp:Button id="Button1"
           Text="Submit"
           OnClick="ButtonClick"
           runat="server"/>
   </form>
</body>
</html>

 

10.3.8    RegularExpressionValidator 控件

RegularExpressionValidator 控件也叫正則表達式控件,該控件用來檢查輸入控件的值是否匹配正則表達式定義的模式。這類驗證容許您檢查可預知的字符序列,好比身份證號碼、電子郵件地址、電話號碼和郵編中的字符序列。本節首先講解一些正則表達式的基本知識,而後將這些基本知識用於數據驗證控件。
1.基本模式
模式,是正規表達式最基本的元素,它們是一組描述字符串特徵的字符。模式能夠很簡單,由普通的字符串組成;也能夠很是複雜,能夠用特殊的字符表示一個範圍內的宇符、重複出現等。最簡單的匹配就是一個字符串,這種狀況下,若是一個字符串含有這個字符串,那麼那個字符串就認爲是符合匹配要求的。
l  「^」頭匹配
這個模式包含一個特殊的字符^,表示該模式只匹配那些以緊接其後的以字符串。例如:^front,表示以」front」開頭的字符串是匹配的,而不以」front」開頭的字狩串是不匹配的。
l  「$」尾匹配
    尾匹配「$」的意義是,只有那些以「$」號前面的字符串結尾的字符串才符合匹配的要求,例如:tail$,表示那些以」tail」結尾的字符串是匹配的。結合使用「^」和「S」,能夠提供一種整個字符串匹配的模式:^whole$,就表示僅有「whole」字符串符合匹配要求。
2.轉義序列
所謂轉義序列其實就是一些沒法直接在正則表達式中使用的字符,例如標點符號、空格、
回車、換行、製表符等。全部的轉義序列都用反斜槓(\)打頭。和「C」語言中相似,轉義序列也是以「\」開頭的,如:
換行:\n
回車:\r
製表符:\t
因爲在正則表達式中「^」、「S」和「+」等都有特殊的意義,因此在正則表達式中也須要使用轉義序列來表示「\^」「\$」和「\+」。
3.字符簇
在Internet中,正規表達式一般用來艦用戶的輸人,當用戶提交一個Form之後,要判斷輸入的電話號碼、地址、Enail地址、信用卡號碼、郵政編碼等是否有效,用普通的基於字面的字符是不夠的,須要一種能夠設定一個字符集合的方法,在正則表達式中,這種方法稱爲字符簇,一個字符簇是使用方掛號括起來的。下面舉一個例子:[ABCabc],上面的字符簇例子表示若是一個字符是「A」或「B」或「C「或「a」或「b」或「C「,那麼就符合匹配要求。
當須要一個有順序的返回的時候,能夠使用連字號來表示二個字符的範圍,如:[a-z]匹配全部的小寫字母。[A-Z]匹配全部的大寫字母。[az-AZ]匹配全部字母。[0-9]匹配全部的數字。[0-9\.\-] 匹配全部的數字,句號和減號。[\f\r\t\n]匹配全部的白字符。
前面曾經提到^表示字符串的開頭,但它還有另一個含義。當在一組方括號裏使用^時,它表示「非」或「排除」的意思,經常用來剔除某個字符。例如,若是要求第一個字符不能是小寫字母:^[^a-z],這個模式與「A4」、「7b」及「+a」是匹配的,但與」a2’、「c6」是不匹配的。下面是幾個排除特定字符字符的例子:[「a-z」],除了小寫字母之外的全部字符。[^「0-9」],除了數字以外的全部字符。[^\」\’],除了雙引號(」)和單引號(’)以外的全部字符。特殊字符」.」(點號)在正規表達式中用來表示除了「新行」以外的全部字符。因此模式」^.5$」與任何兩個字符的、以數字5結尾和以其餘非「新行」字符開頭的字符串匹配。模式」.」能夠匹配任何字符串,除了空串和只包括一個「新行」的字符串。
4.重複
到如今爲止,已經討論瞭如何去匹配一個字母或數字,但更多的狀況下,可能要匹配一個單詞或一組數字。一個單詞由若干個字母組成,一組數字由若干個單數組成。
正則表達式提供了「{}」來執行重複,跟在字符或字符簇後面的花括號({})用來肯定前面的內容重複出現的次數。其中{n,m}表示可能重複n到m次而且包括n和m次,{n,}表示可能重複n次或大於n次。例如:^a{4}$表示aaaa。^a(2,4)$表示aa,aaa,或aaaa。^a{2,}$表示包含多於兩個a的字符串。.{2}表示全部的兩個字符。
下面是經常使用的一些模式:
^[a-zA-Z0-9_]{1,}$表示全部包含一個以上的字母、數字或下劃線的字符串。
^[0-9]{1,}$ 表示全部的整數。
^\-{0,1}[0-9]{0,}\.{0,1}[0-9]{0,}$ 表示全部小數。
正則表達式提供了一些簡寫的特殊字符,可讓表達式容易理解:
?      {0,1}
*       {0,}
+       {1,}
例如:^[0-9]+$ 表示全部的整數。^[0-9]+$ 表示全部的整數。^\-?[0-9]*\.?[0-9]+$表示全部小數。

下例說明如何使用 RegularExpressionValidator 驗證一個 5 位數的郵編。

<%@ Page Language="C#" %>
 <html>
 <head>
    <script runat="server">
        void ValidateBtn_Click(Object sender, EventArgs e) 
       {
          if (Page.IsValid) 
          {
             lblOutput.Text = "Page is Valid!";
          }
          else 
          {
             lblOutput.Text = "Page is InValid! :";
          }
       }
     </script>
  </head>
 
 <body>
     <h3>RegularExpressionValidator Example</h3>
    <p>
     <form runat="server">
        <table bgcolor="#eeeeee" cellpadding="10">
          <tr valign="top">
             <td colspan="3">
                <asp:Label ID="lblOutput" 
                     Text="Enter a 5 digit zip code" 
                     runat="server"/>
             </td>
          </tr>
          <tr>
             <td colspan="3">
                <b>Personal Information</b>
             </td>
          </tr>
          <tr>
             <td align="right">
                Zip Code:
             </td>
             <td>
                <asp:TextBox id="TextBox1" 
                     runat="server"/>
             </td>
             <td>
                <asp:RegularExpressionValidator id="RegularExpressionValidator1" 
                     ControlToValidate="TextBox1"
                     ValidationExpression="\d{5}"
                     Display="Static"
                     ErrorMessage="Zip code must be 5 numeric digits"
                     EnableClientScript="False" 
                     runat="server"/>
             </td>
          </tr>
          <tr>
             <td></td>
             <td>
                <asp:Button text="Validate" 
                     OnClick="ValidateBtn_Click" 
                     runat=server />
             </td>
             <td></td>
          </tr>
       </table>
     </form>
 </body>
 </html>
如用Visual Studio.NET實現,只需修改屬性ValidationExpressio便可。

 

10.4  DataGraid控件

10.4.1  DataGrid控件概述

 

10.4.2  DataGrid控件綁定數據庫表

例子e10_4_1聯接一個數據庫,用DataGrid控件顯示的例子以下:
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<html>
<title>DataGrid顯示數據庫表</title>
<script runat=server>
public void Page_Load(Object sender, EventArgs e)
{
         string txtConn="DATABASE=Northwind;SERVER=localhost;UID=sa;PWD=;";
         string txtCommand="SELECT employeeid, firstname, lastname FROM Employees";
         SqlConnection conn = new SqlConnection(txtConn);
         SqlDataAdapter da = new SqlDataAdapter(txtCommand, conn);
         DataSet ds = new DataSet();
         da.Fill(ds, "MyTable");
         grid.DataSource =ds.Tables["MyTable"];//爲網格控件指定數據源
         grid.DataBind();//數據綁定
//       grid.Visible =true;
}
</script>
<body bgcolor="ivory" style="font-family:arial;font-size:9pt">
<form runat=server>
    <asp:DataGrid id="grid" runat="server" visible="false"
         AutoGenerateColumns="true"
         CssClass="Shadow" BackColor="white"
         CellPadding="2" CellSpacing="2" GridLines="none" 
         BorderStyle="solid" BorderColor="black" BorderWidth="1"
         font-size="x-small" font-names="verdana">
         <AlternatingItemStyle BackColor="palegoldenrod" />
         <ItemStyle BackColor="beige" />
         <HeaderStyle ForeColor="white" BackColor="brown" Font-Bold="true" />
     </asp:DataGrid>
</form>
</body>
</html>
其中字符串txtConn="DATABASE=Northwind;SERVER=localhost;UID=sa;PWD=;"叫聯接字符串,DATABASE時數據源,SERVER是數據庫服務器,UID是用戶名,PWD爲密碼。語句SqlConnection conn=new SqlConnection(txtConn)用來創建一個鏈接。字符串txtCommand ="SELECT employeeid, firstname, lastname FROM Employees"是一個SQL語句,用來從表Employees中取出字段employeeid、firstname、lastname的全部記錄。語句SqlDataAdapter da=new SqlDataAdapter(txtCommand,conn)用來創建一個SqlDataAdapter對象,它負責讀取數據庫數據。用DataGrid控件顯示錶Employees中字段employeeid、firstname、lastname的數據。Page_Load()函數說明了顯示數據的必要步驟。特別要注意DataGrid控件數據綁定的方法。

10.4.3  DataGrid控件對數據庫記錄分頁顯示

<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<%@ Import Namespace="System.Data" %>
 
<html>
<title>分頁</title>
 
<script runat="server">
public void Page_Load(Object sender, EventArgs e)
{
         DataGrid1.DataSource = CreateDataSource();
         DataGrid1.DataBind();
}
 
private DataTable CreateDataSource()
{
         String strConn = "DATABASE=Northwind;SERVER=localhost;UID=sa;PWD=;";
         String strCmd ="SELECT firstname, lastname FROM employees";
         SqlDataAdapter cmd = new SqlDataAdapter(strCmd, strConn);
 
         DataSet oDS = new DataSet();
         cmd.Fill(oDS, "EmployeesList");
         
         return oDS.Tables["EmployeesList"];
}
 
public void PageIndexChanged(Object sender, DataGridPageChangedEventArgs e)
{
         DataGrid1.CurrentPageIndex = e.NewPageIndex;
         DataGrid1.DataSource = CreateDataSource();
         DataGrid1.DataBind();
}
 
</script>
 
 
<body bgcolor="ivory" style="font-family:arial;font-size:xsmall">
 
<!-- ASP.NET topbar -->
<h2>分頁</h2>
<form runat="server">
 
<asp:datagrid runat="server" id="DataGrid1"
         Font-Size="Smaller" Font-Names="Verdana" 
         CellPadding="2" CellSpacing="2" 
         CssClass="Shadow" BackColor="White"
         BorderStyle="solid" BorderColor="black" BorderWidth="1"
         AllowPaging="True"
         PageSize="3" 
         OnPageIndexChanged="PageIndexChanged">
 
         <PagerStyle PageButtonCount="3" Font-Bold="true" Mode="NumericPages" BackColor="palegreen" />
         <AlternatingItemStyle BackColor="Gainsboro" />
         <ItemStyle BackColor="White" />
         <HeaderStyle Font-Bold="True" ForeColor="White" BackColor="Navy" />
</asp:datagrid>
 
</form>
</body></html>
AllowPaging="True"表示容許分頁,PageSize="3"表示每頁3個記錄,<PagerStyle PageButtonCount="3" Font-Bold="true" Mode="NumericPages" BackColor="palegreen" />中PageButtonCount="3"表示有3個按鈕,Mode="NumericPages"表示按鈕形式爲數字,也能夠修改成Mode="NextPrev",則在網格下部出現<和>,單擊<,轉向前頁,單擊>,轉向後頁。也能夠改成字符,例如修改成「前頁」和「後頁」,能夠修改屬性PrevPageText=」前頁」,NextPageText=」後頁」。OnPageIndexChanged="PageIndexChanged"表示單擊按鈕事件函數是PageIndexChanged。

10.4.4    DataGrid控件對記錄排序

<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<html>
<title>按列排序</title>
<script runat="server">
    SqlConnection conn;
    protected void Page_Load(Object Src, EventArgs E) 
    {
        conn = new SqlConnection("server=localhost;uid=sa;pwd=;database=pubs");
        if (!IsPostBack)
            BindGrid("au_id");
    }
    protected void MyDataGrid_Sort(Object sender, DataGridSortCommandEventArgs e) 
    {
        BindGrid(e.SortExpression);
    }
    public void BindGrid(String sortfield) 
    {
      SqlDataAdapter myCommand = new SqlDataAdapter("select * from Authors",conn);
      DataSet ds = new DataSet();
      myCommand.Fill(ds, "Authors");
      DataView Source = ds.Tables["Authors"].DefaultView;
      Source.Sort = sortfield;
      MyDataGrid.DataSource=Source;
      MyDataGrid.DataBind();
    }
</script>
<body>
  <h3><font face="Verdana">按列排序</font></h3>
  <form runat="server">
    <ASP:DataGrid id="MyDataGrid" runat="server" OnSortCommand="MyDataGrid_Sort"
      Width="700"
      BackColor="#ccccff" 
      BorderColor="black"
      ShowFooter="false" 
      CellPadding=3 
      CellSpacing="0"
      Font-Name="Verdana"
      Font-Size="8pt"
      HeaderStyle-BackColor="#aaaadd"
      AllowSorting="true" 
    />
  </form>
</body>
</html>
AllowSorting="true"表示容許排序,容許排序的列標題有一下劃線,單擊標題將產生事件,事件函數由OnSortCommand="MyDataGrid_Sort"定義。現若是用手工產生每一列,排序的例子以下:
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
 
<html>
<title>按列排序</title>
<script runat="server">
 
    SqlConnection conn;
 
    protected void Page_Load(Object Src, EventArgs E) 
    {
        conn = new SqlConnection("DATABASE=Northwind;SERVER=localhost;UID=sa;PWD=;");
 
        if (!IsPostBack)
            BindGrid("lastname");
    }
 
    protected void MyDataGrid_Sort(Object sender, DataGridSortCommandEventArgs e) 
    {
        BindGrid(e.SortExpression);
    }
 
    public void BindGrid(String sortfield) 
    {
        SqlDataAdapter myCommand = new SqlDataAdapter("SELECT employeeid, firstname, lastname, title, country FROM Employees", conn);
 
        DataSet ds = new DataSet();
        myCommand.Fill(ds, "MyList");
 
        DataView Source = ds.Tables["MyList"].DefaultView;
        Source.Sort = sortfield;
 
        MyDataGrid.DataSource=Source;
        MyDataGrid.DataBind();
    }
 
</script>
 
<body>
 
  <h3><font face="Verdana">按列排序</font></h3>
 
  <form runat="server">
 
    <asp:DataGrid id="MyDataGrid" runat="server"  
         AutoGenerateColumns="false"
         CssClass="Shadow" BackColor="white"
         CellPadding="2" CellSpacing="2" GridLines="none" 
         BorderStyle="solid" BorderColor="black" BorderWidth="1"
         font-size="x-small" font-names="verdana"
         AllowSorting="true"
         OnSortCommand="MyDataGrid_Sort">
 
         <AlternatingItemStyle BackColor="palegoldenrod" />
         <ItemStyle BackColor="beige" />
         <HeaderStyle ForeColor="white" BackColor="brown" Font-Bold="true" />
 
        <columns>
            <asp:BoundColumn runat="server" DataField="employeeid" HeaderText="編號" >
                 <itemstyle backcolor="lightblue" font-bold="true" />
           </asp:BoundColumn>
            <asp:BoundColumn runat="server" DataField="firstname" 
                 HeaderText="名字" />
            <asp:BoundColumn runat="server" DataField="lastname" 
                 HeaderText="姓" SortExpression="lastname" />
            <asp:BoundColumn runat="server" DataField="title" 
                 HeaderText="Position" />
            <asp:BoundColumn runat="server" DataField="country" 
                 HeaderText="國家" SortExpression="country" />
         </columns>
     </asp:DataGrid>
 
  </form>
 
</body>
</html>
在DataGrid的5列中,只有DataField="lastname"和DataField="country"有SortExpression屬性定義,分別爲:"lastname"和"country",所以,只有此兩列能夠排序,表達式SortExpression= "lastname"表示此列能夠排序,按字段"lastname"排序。若是增長語句Source.Sort += " DESC",則降序排序,如無字符" DESC"爲生序排序。

10.4.5  用BoundColumn列將標題改成中文

DataGrid控件的屬性AutoGenerateColumns=true,將根據數據源的內容自動填充表格,標題默認爲是字段名,因爲避免不兼容,字段名通常用英文,如但願如將標題改成中文,能夠置AutoGenerateColumns=false,使用列控件BoundColumn手工填充,其中屬性HeaderText是標題字符串,能夠改爲中文,屬性DataField是該列顯示的字段名。見下例:
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<html>
<title>DataGrid標題改成中文</title>
<script runat=server>
public void Page_Load(Object sender, EventArgs e)
{
         string txtConn="DATABASE=Northwind;SERVER=localhost;UID=sa;PWD=;";
         string txtCommand="SELECT employeeid, titleofcourtesy, firstname, lastname, title, country FROM Employees";
         SqlConnection conn = new SqlConnection(txtConn);
         SqlDataAdapter da = new SqlDataAdapter(txtCommand, conn);
         DataSet ds = new DataSet();
         da.Fill(ds, "MyTable");
         grid.DataSource = ds.Tables["MyTable"];
//       grid.DataBind();
}
</script>
<body bgcolor="ivory" style="font-family:arial;font-size:9pt">
<form runat=server>
   <asp:DataGrid id="grid" runat="server"  
         AutoGenerateColumns="false"
         CssClass="Shadow" BackColor="white"
         CellPadding="2" CellSpacing="2" GridLines="none" 
         BorderStyle="solid" BorderColor="black" BorderWidth="1"
         font-size="x-small" font-names="verdana">
         <AlternatingItemStyle BackColor="palegoldenrod" />
         <ItemStyle BackColor="beige" />
         <HeaderStyle ForeColor="white" BackColor="brown" Font-Bold="true" />
     <columns>
       <asp:BoundColumn runat="server" DataField="employeeid" HeaderText="編號">
           <itemstyle backcolor="lightblue" font-bold="true" />
       </asp:BoundColumn>
<asp:BoundColumn runat="server" DataField="titleofcourtesy" HeaderText="稱呼" />
       <asp:BoundColumn runat="server" DataField="firstname" HeaderText="姓" />
       <asp:BoundColumn runat="server" DataField="lastname" HeaderText="名" />
     </columns>
   </asp:DataGrid>
</form>
</body>
</html>

10.4.6  增長按鈕列

若是用手工建立DataGrid表格,除了以上介紹的列控件BoundColumn外,還包括控件ButtonColumn,用來建立一列按鈕,能夠爲按鈕增長一個事件函數,控件HyperLinkColumn用來建立一列超級連接字符,控件EditCommandColumn,將自動和編輯命令相關聯。控件TemplateColumn,將按指定模板建立所顯示的列。
例子e10_4_4是控件ButtonColumn的用法:
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<html>
<title>DataGrid增長按鈕列</title>
<script runat=server>
string txtConn="DATABASE=Northwind;SERVER=localhost;UID=sa;PWD=;";
public void Page_Load(Object sender, EventArgs e)
{
       string txtCommand="SELECT employeeid, firstname, lastname FROM Employees";
       SqlConnection conn = new SqlConnection(txtConn);
       SqlDataAdapter da = new SqlDataAdapter(txtCommand, conn);
       DataSet ds = new DataSet();
       da.Fill(ds, "MyTable");
       grid.DataSource = ds.Tables["MyTable"];
       grid.DataBind();
}
public void HandleCommands(Object sender, DataGridCommandEventArgs e)
{
         if(e.CommandName=="moreinfo")
         {
           int nEmpID=(int)grid.DataKeys[e.Item.ItemIndex];
           SqlConnection conn=new SqlConnection(txtConn);
           String strCmd="SELECT * FROM Employees "+
                         "WHERE employeeid="+nEmpID.ToString();
           SqlCommand cmd=new SqlCommand(strCmd,conn);
           conn.Open();
           SqlDataReader dr=cmd.ExecuteReader();
           dr.Read();
           MoreInfo.Text=BuildMoreInfoText(dr);
 
                 dr.Close();
                 conn.Close();
         }
}
private String BuildMoreInfoText(SqlDataReader dr)
{
       StringBuilder sb=new StringBuilder();
       sb.Append("<b>");
       sb.Append(dr["lastname"]+"," + dr["firstname"]);
       sb.Append("</b><br>");
       sb.Append(dr["title"] + "<hr>");
       sb.Append("<i>");
       sb.Append(dr["notes"]);
       sb.Append("</i>");
       return sb.ToString();
}
</script>
<body bgcolor="ivory" style="font-family:arial;font-size:9pt">
<form runat=server>
  <asp:DataGrid id="grid" runat="server"  
     AutoGenerateColumns="false"
     CssClass="shadow" BackColor="white"
     CellPadding="2" CellSpacing="2" GridLines="none" 
     BorderStyle="solid" BorderColor="black" BorderWidth="1"
     font-size="x-small" font-names="verdana"
     DataKeyField="employeeid"
     OnItemCommand="HandleCommands">
     <AlternatingItemStyle BackColor="palegoldenrod" />
     <ItemStyle BackColor="beige" />
     <HeaderStyle ForeColor="white" BackColor="brown" Font-Bold="true"/>
   <columns>
     <asp:BoundColumn runat="server" DataField="employeeid" HeaderText="編號"/>
     <asp:BoundColumn runat="server" DataField="firstname" HeaderText="名" />
     <asp:BoundColumn runat="server" DataField="lastname" HeaderText="姓" />
     <asp:ButtonColumn runat="server" Text="更多信息" CommandName="moreinfo">
         <itemstyle backcolor="lightblue" font-bold="true" />
     </asp:ButtonColumn>
   </columns>
  </asp:DataGrid>
<asp:Label runat="server" id="MoreInfo" />
</form>
</body>
</html>
網頁中OnItemCommand="HandleCommands"的HandleCommands是按鈕列按鈕的事件函數,若是有多個按鈕列,都用此函數響應。按鈕列按鈕的事件函數HandleCommands中的語句if(e.CommandName=="moreinfo")是判斷是哪個按鈕發的事件。

10.4.7  增長HyperLinkColumn列

例子e10_4_5下例是控件HyperLinkColumn的用法:
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<html>
<title>DataGrid增長HyperLinkColumn列</title>
<script runat=server>
string txtConn="DATABASE=Northwind;SERVER=localhost;UID=sa;PWD=;";
public void Page_Load(Object sender, EventArgs e)
{
     string txtCommand="SELECT employeeid, firstname, lastname FROM Employees";
     SqlConnection conn = new SqlConnection(txtConn);
     SqlDataAdapter da = new SqlDataAdapter(txtCommand, conn);
     DataSet ds = new DataSet();
     da.Fill(ds, "MyTable");
     grid.DataSource = ds.Tables["MyTable"];
     grid.DataBind();
}
</script>
<body bgcolor="ivory" style="font-family:arial;font-size:9pt">
<form runat=server>
  <asp:DataGrid id="grid" runat="server"  
     AutoGenerateColumns="false"
     CssClass="shadow" BackColor="white"
     CellPadding="2" CellSpacing="2" GridLines="none" 
     BorderStyle="solid" BorderColor="black" BorderWidth="1"
     font-size="x-small" font-names="verdana"
     DataKeyField="employeeid">
     <AlternatingItemStyle BackColor="palegoldenrod" />
     <ItemStyle BackColor="beige" />
     <HeaderStyle ForeColor="white" BackColor="brown" Font-Bold="true" />
<columns>
     <asp:BoundColumn runat="server" DataField="employeeid" HeaderText="編號" />
     <asp:BoundColumn runat="server" DataField="firstname" HeaderText="名" />
     <asp:BoundColumn runat="server" DataField="lastname" HeaderText="姓" />
     <asp:HyperLinkColumn runat="server"
         HeaderText="連接另外一網頁" 
         DataNavigateUrlField="employeeid"
         DataNavigateUrlFormatString="e10_4_5A.aspx?id={0}"
         DataTextField="lastname"
         DataTextFormatString="關於{0}更多信息"
         Target="frInfo">
         <ItemStyle BackColor="lightblue" font-bold="true" />
     </asp:HyperLinkColumn>
   </columns>
 </asp:DataGrid>
<asp:Label runat="server" id="MoreInfo" />
</form>
</body>
</html>
控件HyperLinkColumn中,DataNavigateUrlFormatString="例子e10_4_5A.aspx? id ={0}"是超級連接的網頁,本例是c716-1A.aspx,?id={0}是傳遞的參數,{0}是一個變量,對應DataNavigateUrlField指定的數據庫表字段,本例爲employeeid,DataTextFormatString爲超級連接字符,本例爲"關於{0}更多信息"。
例子e10_4_5A.aspx以下:
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<html>
<title>More Info</title>
<script runat=server>
public void Page_Load(Object sender, EventArgs e)
{
   int nEmpID = Convert.ToInt16(Request["id"]);
   if (nEmpID<1)
   {
     Response.Write("No valid ID specified.");
     Response.End();
   }
   else
     GetMoreInfo(nEmpID);
}
public void GetMoreInfo(int nEmpID)
{
   String strConn = "DATABASE=Northwind;SERVER=localhost;UID=sa;PWD=;";
   SqlConnection conn = new SqlConnection(strConn);
   String strCmd = "SELECT * FROM Employees " + 
                 "WHERE employeeid = " + nEmpID.ToString();
   SqlCommand cmd = new SqlCommand(strCmd, conn);
   conn.Open();
   SqlDataReader dr = cmd.ExecuteReader();
   dr.Read();
   MoreInfo.Text = BuildMoreInfoText(dr);
   dr.Close();
   conn.Close();
}
private String BuildMoreInfoText(SqlDataReader dr)
{
   StringBuilder sb = new StringBuilder();
   sb.Append("<b>");
   sb.Append(dr["employeeid"] + " - ");
   sb.Append(dr["lastname"] + ", " + dr["firstname"]);
   sb.Append("</b><br>");
   sb.Append(dr["title"] + "<hr>");
   sb.Append("<i>");
   sb.Append(dr["notes"]);
   sb.Append("</i>");
   return sb.ToString();
}
</script>
<body>
<asp:Label runat="server" id="MoreInfo" />
</body>
</html>

10.4.8  增長EditCommandColumn列

 

10.4.9        控件TemplateColumn的用法

例子e10_4_5A是控件TemplateColumn的用法,本例用單選按鈕顯示bool字段。
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<html>
<title>顯示布爾變量</title>
<script runat="server">
public void Page_Load(Object sender, EventArgs e)
{
   if(!Page.IsPostBack)
   {
     SqlConnection conn=new SqlConnection("DATABASE=Northwind;SERVER=localhost;UID=sa;PWD=;");
     SqlDataAdapter da=new SqlDataAdapter("SELECT employeeid, titleofcourtesy, firstname, lastname, title, ISNULL(reportsto,0) AS boss FROM Employees", conn);
     DataSet ds = new DataSet();
     da.Fill(ds, "MyTable");
     grid.DataSource = ds.Tables["MyTable"];
 
     grid.DataBind();
   }
}
bool HasBoss(int bossID)
{
   if (bossID != 0)
       return true;
   return false;
}
</script>
<body bgcolor="ivory" style="font-family:arial;font-size:9pt">
<form runat="server">
   <asp:DataGrid id="grid" runat="server"  
       AutoGenerateColumns="false"
       CssClass="Shadow" BackColor="white"
       CellPadding="2" CellSpacing="0" 
       BorderStyle="solid" BorderColor="black" BorderWidth="1"
       font-size="x-small" font-names="verdana">
       <AlternatingItemStyle BackColor="palegoldenrod" />
       <ItemStyle BackColor="beige" />
       <HeaderStyle ForeColor="white" BackColor="brown" Font-Bold="true" />
     <columns>
       <asp:BoundColumn runat="server" HeaderText="ID" DataField="編號">
       <itemstyle backcolor="lightblue" font-bold="true" />
       </asp:BoundColumn>
       <asp:TemplateColumn runat="server" HeaderText="Employee Name">
         <itemtemplate>
         <asp:label runat="server" 
         style="margin-left:5;margin-right:5"
         Text='<%# DataBinder.Eval(Container.DataItem,"TitleOfCourtesy")+"<b>"+
               DataBinder.Eval(Container.DataItem,"LastName")+"</b>"+","+
               DataBinder.Eval(Container.DataItem,"FirstName") %>' />
         </itemtemplate>
       </asp:TemplateColumn>
       <asp:TemplateColumn HeaderText="Reports"
             headerstyle-horizontalalign="Center" 
             itemstyle-horizontalalign="Center">
       <itemtemplate>
       <asp:checkbox runat="server" enabled="false" checked=
           '<%# HasBoss((int)DataBinder.Eval(Container.DataItem,"boss")) %>'/>
       </itemtemplate>
       </asp:TemplateColumn>
       <asp:BoundColumn runat="server" DataField="title" HeaderText="Position" />
     </columns>
</asp:DataGrid>
</form>
</body>
</html>
例子e10_4_5B用圖形按鈕顯示bool字段。
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<html>
<title>用圖像顯示布爾變量</title>
<script runat="server">
public void Page_Load(Object sender, EventArgs e)
{
     if (!Page.IsPostBack)
     {
       SqlConnection conn = new SqlConnection("DATABASE=Northwind;SERVER=localhost;UID=sa;PWD=;");
       SqlDataAdapter da = new SqlDataAdapter("SELECT employeeid, titleofcourtesy, firstname,lastname,title,ISNULL(reportsto,0)AS boss FROM Employees",conn);
       DataSet ds=new DataSet();
       da.Fill(ds,"MyTable");
       grid.DataSource = ds.Tables["MyTable"];
       grid.DataBind();
     }
}
String GetProperGifFile(int bossID)
{
   if (bossID != 0)
       return "checked.gif";//checked.gif應和e10_4_5B.aspx在同一文件夾中
   return "unchecked.gif";
}
</script>
<body bgcolor="ivory" style="font-family:arial;font-size:9pt">
<asp:DataGrid id="grid" runat="server"  
     AutoGenerateColumns="false"
     CssClass="Shadow" BackColor="white"
     CellPadding="2" CellSpacing="0" 
     BorderStyle="solid" BorderColor="black" BorderWidth="1"
     font-size="x-small" font-names="verdana">
     <AlternatingItemStyle BackColor="palegoldenrod" />
     <ItemStyle BackColor="beige" />
     <HeaderStyle ForeColor="white" BackColor="brown" Font-Bold="true" />
  <columns>
     <asp:BoundColumn runat="server" HeaderText="ID" DataField="employeeid">
       <itemstyle backcolor="lightblue" font-bold="true" />
     </asp:BoundColumn>
     <asp:TemplateColumn runat="server" HeaderText="Employee Name">            
         <itemtemplate>
           <asp:label runat="server" 
             style="margin-left:5;margin-right:5"
           Text='<%#DataBinder.Eval(Container.DataItem,"TitleOfCourtesy")+"<b>" 
           +DataBinder.Eval(Container.DataItem,"LastName")+"</b>"+","+
                 DataBinder.Eval(Container.DataItem, "FirstName") %>' />
         </itemtemplate>
     </asp:TemplateColumn>
     <asp:TemplateColumn HeaderText="Reports" 
         headerstyle-horizontalalign="Center" 
         itemstyle-horizontalalign="Center">
         <itemtemplate>
           <asp:image runat="server" imageurl='<%# 
         GetProperGifFile((int)DataBinder.Eval(Container.DataItem,"boss"))%>'/>
         </itemtemplate>
     </asp:TemplateColumn>
     <asp:BoundColumn runat="server" DataField="title" HeaderText="Position" />
         </columns>
     </asp:DataGrid>
 
</form>
 
</body>
</html>
7.1.9 使用本身的數據庫

l  用Access創建數據庫

用Access創建數據庫: db1.mdb。創建Student表,記錄全部學生信息。包括字段StudentNum(學生編號),字節類型,必填字段,默認值爲空,StudentNum爲主關鍵字。字段StudentName(學生姓名),文本,字段大小8,必填字段,默認值爲空。字段StudentSex(性別),文本,字段大小2。增長若干數據。存數據庫的路徑爲:D:\asp\StudentDb.mdb

l  例子以下:

<%@ Page Language="C#" %>

<%@ Import Namespace="System.Data.OleDb" %>

<%@ Import Namespace="System.Data" %>

 

<html>

<title>DataGrid</title>

 

<script runat=server>

public void OnLoadData(Object sender, EventArgs e)

{

    string txtConn="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:\\ASP\\bookExample\\db1.mdb";

    string txtCommand="SELECT * FROM student";

    OleDbConnection conn = new OleDbConnection(txtConn);

    OleDbDataAdapter da = new OleDbDataAdapter(txtCommand, conn);

   

    DataSet ds = new DataSet();

    da.Fill(ds, "MyTable");

 

    // Display the data

    grid.DataSource = ds.Tables["MyTable"];

    grid.DataBind();

    grid.Visible = true;

}

</script>

 

 

<body bgcolor="ivory" style="font-family:arial;font-size:9pt">

 

<!-- ASP.NET topbar -->

<h2>數據庫的聯接</h2>

 

<form runat=server>

    <asp:linkbutton runat="server" id="btnLoad" text="Go get data..." onclick="OnLoadData" />

 

    <asp:DataGrid id="grid" runat="server" visible="false"

    AutoGenerateColumns="true"

    CssClass="Shadow" BackColor="white"

    CellPadding="2" CellSpacing="2" GridLines="none"

    BorderStyle="solid" BorderColor="black" BorderWidth="1"

    font-size="x-small" font-names="verdana">

 

    <AlternatingItemStyle BackColor="palegoldenrod" />

    <ItemStyle BackColor="beige" />

    <HeaderStyle ForeColor="white" BackColor="brown" Font-Bold="true" />

     </asp:DataGrid>

 

</form>

 

</body>

</html>

 

 

10.5  AdRotator控件

Web 頁上的廣告一般採用廣告條(小圖片)的形式,單擊時使用戶重定向到廣告商的 Web 頁。使用 AdRotator Web 服務器控件可以顯示廣告條並在一系列廣告條間循環。AdRotator 自動進行循環處理,在每次刷新頁面時更改顯示的廣告。使用 AdRotator 控件顯示廣告步驟:

(1) 建立一個Web應用程序框架,項目名爲UseAdRotator。

(2) 新建一個XML文件。單擊菜單項」項目/添加新項」,彈出標題爲添加新項的窗口,在窗口中選中XML文件,文件名爲ads.xml,單擊打開按鈕,增長一個XML文件。文件以下:

<Advertisements>

 <Ad>

 <ImageUrl>d:\\asp\\bookExample\\p2.JPG</ImageUrl>

 <NavigateUrl>http://www.sohu.com</NavigateUrl>

 <AlternateText>search anything</AlternateText>

 <Impressions>10</Impressions>

 <Keyword>Topic1</Keyword>

 <Caption>This is the caption for Ad#1</Caption>

 </Ad>

 

 <Ad>

 <ImageUrl>d:\\asp\\bookExample\\baobao048.jpg</ImageUrl>

 <NavigateUrl>http://www.sina.com</NavigateUrl>

 <AlternateText>sina main site</AlternateText>

 <Impressions>10</Impressions>

 <Keyword>Topic2</Keyword>

 <Caption>This is the caption for Ad#2</Caption>

 </Ad>

 

</Advertisements>

(3) 在窗體中放置控件AdRotator,其屬性Name=AdRotator1。

(4) 修改控件AdRotator的屬性AdvertisementFile,單擊其後的按鈕,出現選擇XML文件對話框,在對話框中URL(U)處填入ads.xml。

(5) 運行,能夠看到一幅圖,鼠標移到圖中,變爲手形,單擊能夠轉到搜狐網站。刷新,能夠看到另外一幅圖。

XML 文件包含如下預約義的屬性。只有 ImageUrl 屬性是必需的:

l  ImageURL 要顯示的圖像的 URL

l  NavigateURL 單擊 AdRotator 控件時定位到的頁面的 URL。

l  AlternateText 圖像不可用時顯示的文本(常爲圖片瀏覽工具提示)。

l  Keyword 可用於篩選特定廣告的廣告類別。經過設置AdRotator的KeywordFilter屬性以篩選出 XML 文件中特定類別的廣告。 

l  Impression 指示廣告的可能顯示頻率的數值。在 XML 文件中,全部 impression 值的總和不能超過 2,048,000,000 - 1

10.6  Calender控件

Calendar Web 服務器控件在 Web 窗體頁上顯示一個傳統的單月份日曆(包含該月在內的6周)。用戶可以使用該日曆查看和選擇日期。Calendar Web 服務器控件最簡單的用法以下:(C7-2A.aspx)

<html>

<head>

    <script language="C#" runat="server">

        void Date_Selected(object s, EventArgs e) {

            Label1.Text = "Selected date is: " + Calendar1.SelectedDate.ToShortDateString();

        }

    </script>

</head>

<body>

    <h3><font face="Verdana">Calendar Example</font></h3>

    <form runat=server>

        <asp:Calendar id=Calendar1 onselectionchanged="Date_Selected" runat="server" />

        <p>

        <asp:Label id=Label1 runat="server" />

    </form>

</body>

</html>

其中事件onselectionchanged="Date_Selected"是用戶改變選擇日期時產生的事件。SelectionMode屬性設定Calendar控件中可選擇的時間段,Day:可選擇任一天;DayWeek:可選擇任一天或一週;DayWeekMonth:可選擇任一天、一週或一月;None:不能選擇日期。C7-2A.aspx網頁顯示了SelectionMode屬性選擇不一樣質的效果。

<html>

<head>

    <script language="C#" runat="server">

        void Page_Load(Object Sender, EventArgs e) {

            Calendar1.SelectionMode = (CalendarSelectionMode)lstSelMode.SelectedIndex;

            if (Calendar1.SelectionMode == CalendarSelectionMode.None)

                Calendar1.SelectedDates.Clear();

        }

        void Date_Selected(object s, EventArgs e) {

            switch (Calendar1.SelectedDates.Count) {

                case (0):   //None

                    Label1.Text = "No dates are currently selected";

                    break;

                case (1):   //Day

                    Label1.Text = "The selected date is " + Calendar1.SelectedDate.ToShortDateString();

                    break;

                case (7):   //Week

                    Label1.Text = "The selection is a week beginning " + Calendar1.SelectedDate.ToShortDateString();

                    break;

                default:    //Month

                    Label1.Text = "The selection is a month beginning " + Calendar1.SelectedDate.ToShortDateString();

                  break;    

            }

        }

    </script>

</head>

<body>

    <h3><font face="Verdana">Date Selection Modes</font></h3>

    <p>

    <form runat=server>

        Choose a Selection Mode:

        <asp:DropDownList id="lstSelMode" runat=server

            AutoPostBack=true>

            <asp:ListItem Value="None" >None</asp:ListItem>

            <asp:ListItem Selected Value="Day" >Day</asp:ListItem>

            <asp:ListItem Value="DayWeek" >DayWeek</asp:ListItem>

            <asp:ListItem Value="DayWeekMonth" >DayWeekMonth</asp:ListItem>

        </asp:DropDownList>

 

        <p>

        <asp:Calendar id=Calendar1 runat="server"

            onselectionchanged="Date_Selected"

            DayNameFormat="FirstLetter"

            Font-Name="Arial" Font-Size="12px"

            Height="180px" Width="200px"

            SelectorStyle-BackColor="gainsboro"

            TodayDayStyle-BackColor="gainsboro"

            DayHeaderStyle-BackColor="gainsboro"

            OtherMonthDayStyle-ForeColor="gray"

            TitleStyle-BackColor="gray"

            TitleStyle-Font-Bold="True"

            TitleStyle-Font-Size="12px"

            SelectedDayStyle-BackColor="Navy"

            SelectedDayStyle-Font-Bold="True"

            />

        <p>

        <asp:Label id=Label1 runat="server" />

    </form>

</body>

</html>

一、顯示和選擇日期

可視日期:該日期肯定日曆中顯示哪一個月份。在日曆中,用戶可在不一樣的月份之間移動,從而在不影響當前日期的狀況下更改可視日期。

選定的一個或多個日期:在該控件中用戶可經過設置SelectionMode屬性選擇單個日、單個周或單個月份,但只能選擇連續的日期。

可設置日曆的屬性以更改日曆的顏色、尺寸、文本以及其餘可視特性。默認狀況下,該控件顯示月中各天、週中各天的標頭、帶有月份名和年份的標題、用於選擇月份中各天的連接及用於移動到下個月和上個月的連接。能夠經過設置控制控件中不一樣部分的樣式的屬性,來自定義 Calendar 控件的外觀。

SelectionMode屬性: 設定Calendar控件中可選擇的時間段

Day:可選擇任一天;     DayWeek:可選擇任一天或一週;

DayWeekMonth:可選擇任一天、一週或一月

None:不能選擇日期

SelectDate屬性實現選擇日期:按所定義的外觀樣式顯示運行時所選定的一天、一週或一月 

控件的 DayRender 事件:當在 Calendar 控件中建立(顯示)每一個日期單元格時,均會引起 DayRender 事件。經過在 DayRender 事件的事件處理程序中提供代碼,能夠在建立日期單元格時控制其內容和格式設置。事件處理程序接收一個 DayRenderEventArgs 類型的參數,它包含與此事件相關的數據。DayRenderEventArgs 屬性:

Cell:獲取表示Calendar 控件單元格的 TableCell 對象。

Day:獲取表示Calendar 控件中日期的 CalendarDay。

例 dayreader.aspx  爲 DayRender 事件編寫處理程序,使所顯示月份中日期的背景色爲黃色。它還說明如何經過向單元格添加 System.Web.UI.LiteralControl 來自定義單元格的內容。

 

10.7  Visual Studio.Net實現留言板

本例有兩個窗口,主窗口負責輸入留言,包括輸入用戶名,留言主題,留言內容,用三個編輯框,輸入完畢後,單擊提交按鈕,將留言存入數據庫。單擊另外一個查看留言按鈕,可連接到另外一個顯示留言窗口。顯示留言窗口包括一個DataGraid控件,用來顯示全部的留言的用戶名,主提,留言序號,及按鈕列,單擊相應按鈕,顯示當前記錄的留言內容。單擊返回主窗口按鈕,返回主窗口。下邊是具體步驟:

(1)    用Access2000創建數據庫: LiuYanBan.mdb。創建LiuYanTable表,記錄全部留言信息。包括字段LiuYanID(留言編號),自動編號類型,爲主關鍵字。字段LiuYanName(留言者姓名),文本,字段大小10,必填字段,默認值爲空。字段LiuYanTitle(留言標題),文本,字段大小30,必填字段,默認值爲空。字段LiuYanTime(留言時間),時間類型。字段LiuYanContent(留言內容),備註字段,必填字段,默認值爲空。增長若干數據。存數據庫的路徑爲:D:\asp\ LiuYanBan.mdb,假設文件夾asp已設爲Web網站目錄。

(2)    建立一個Web應用程序框架,選擇菜單命令創建一個新空白窗體。項目名爲LiuYanBan。

(3)    修改WebForm屬性,單擊屬性Style後標題爲…的按鈕,打開樣式生成器對話框,能夠修改WebForm的各類風格。單擊對話框左側的各個選項:字體、背景、文本、位置、佈局、邊緣、列表、其餘,能夠按本身的愛好修改相應的內容,這裏不做修改,所有采用默認值。

(4)    放工具箱的4個Label控件到窗體。修改屬性Text分別爲:留言板主窗體、用戶名、留言主題、留言內容。

(5)    放工具箱的3個TexbBox控件到窗體。修改屬性Text都爲空,ID=TexbBox1編輯框用來輸入用戶名,ID=TexbBox2編輯框用來輸入留言主題,ID=TexbBox3編輯框用來輸入留言內容,其屬性TextMode=MultiLine。因爲此三項要求必須輸入數據,所以應增長3個驗證控件。

(6)    放工具箱的Button控件到窗體,Text=」提交留言」。

(7)    在窗體中放置控件oleDbConnection,其屬性Name=oleDbConnection1。單擊控件oleDbConnection屬性ConnectionString的下拉列表的箭頭,在列表中選擇新建鏈接,打開數據鏈接屬性對話框,選擇提供程序頁,選擇OLE DB提供程序爲Microsoft Jet 4.0 OLE DB Provider後,單擊下一步按鈕,選擇數據庫名稱爲D:\asp\ LiuYanBan.mdb,用戶名稱爲Admin,空白密碼,單擊測試鏈接按鈕,應出現測試鏈接成功對話框。按肯定按鈕退出。

(8)    在窗體中放置控件oleDbCommand,其屬性Name= oleDbCommand1。單擊控件oleDbCommand屬性Connection的下拉列表的箭頭,在列表中單擊現有前的+後,選擇已有的鏈接oleDbConnection1。

(9)    爲單擊提交留言按鈕事件(Click)函數增長語句(雙擊Click事件):

         private void Button1_Click(object sender, System.EventArgs e)

         {

              oleDbConnection1.Open();

//自動增長字段沒必要寫入

              oleDbCommand1.CommandText="Insert Into LiuYanTable(LiuYanName,LiuYanTitle,LiuYanTime,LiuYanContent) Values('" + TextBox1.Text + "', '" + TextBox2.Text + "','" + DateTime.Now + "','" + TextBox3.Text + "')";

             

              oleDbCommand1.ExecuteNonQuery();

              oleDbConnection1.Close();

              TextBox1.Text="";

              TextBox2.Text="";

              TextBox3.Text="";

         }

(10)單擊文件/添加新項(w)…菜單項,出現添加新項對話框,選擇Web窗體,窗體名爲:WebForm2.aspx,單擊打開按鈕,建立新窗體。

(11)在WebForm1放工具箱的HyperLink控件到窗體,Text=」查看留言」,單擊屬性NavigateUrl後的按鈕,出現選擇URL對話框,選擇URL類型爲與根相關的,URL編輯框添入/LiuYanBan/WebForm2.aspx。

(12)在WebForm2窗體中放置控件oleDbConnection,其屬性Name=oleDbConnection1。單擊控件oleDbConnection屬性ConnectionString的下拉列表的箭頭,在列表中選擇前邊創建的數據庫鏈接。

(13)在WebForm2窗體中放置控件oleDbDataAdapter,出現添加數據適配器嚮導對話框,單擊下一步按鈕,單擊下拉列表的箭頭,在列表中選擇前邊創建的數據庫鏈接。單擊下一步按鈕。

(14)選擇使用SQL語句單選按鈕。單擊下一步按鈕。

(15)單擊高級選項按鈕,在高級SQL選項對話框中,全部多選按鈕都不選。單擊肯定按鈕。

(16)單擊查詢生成器按鈕,在添加表對話框中,選中LiuYanBan數據庫,單擊添加按鈕。再按關閉按鈕,關閉添加表對話框。

(17)選中全部字段,按LiuYanID降序排列,單擊肯定按鈕。

(18)單擊肯定按鈕。單擊完成按鈕。

(19)單擊sqlDataAdapter1選中它,單擊菜單項數據/生成數據集…,打開生成數據集對話框,他選擇默認值。按肯定按鈕退出。增長控件dataSet,其屬性Name=dataSet1。

(20)在WebForm2窗體中放置控件dataView,其屬性Name=dataView1。單擊控件dataView1屬性Table的下拉列表的箭頭,在列表中單擊現有前的+後,選擇dataSet1中的LiuYanTable。

(21)在窗體中放置控件Label,其屬性Name=Label1。

(22)在窗體中放置控件DataGrid,其屬性Name=DataGrid1。右擊DataGrid1,在彈出菜單中選擇菜單項自動套用格式,在對話框中選用本身喜歡的格式。

(23)右擊DataGrid1,在彈出菜單中選擇菜單項屬性生成器,在DataGrid屬性對話框中,選中左側的選項:常規。設置數據源爲:dataView1。選中顯示頁眉,顯示頁腳,容許排序。選中左側的選項:列。不選中在運行時自動建立列。將字段:LiuYanName、LiuYanTitle、LiuYanTime從左側的列表框移到右側的列表框,表示顯示此三個字段。見頁眉文本改爲中文:留言者姓名、留言標題、留言時間。增長一個Select按鈕,增長一個按鈕列,頁眉爲:單擊按鈕查看留言。命令名爲:ReadContent。選中左側的選項:分頁。選中容許分頁。

(24)爲按鈕列增長事件函數,DataGraid全部按鈕都產生事件:ItemCommand,根據命令名加以區分是哪個按鈕發的命令。事件函數以下:

private void DataGrid1_ItemCommand(object source,System.Web.UI.WebControls. DataGridCommandEventArgs e)

{

     if (e.CommandName == "ReadContent")

     {

Label1.Text=dataSet11.Tables["LiuYanTable"].Rows[e.Item.ItemIndex]["LiuYanContent"].ToString();

     }

}

(25)爲Page_Load事件函數增長語句:

         private void Page_Load(object sender, System.EventArgs e)

         {

              oleDbDataAdapter1.Fill(dataSet11);

              if(!Page.IsPostBack)

              {

                   DataGrid1.CurrentPageIndex=0;

                   DataGrid1.DataBind();

              }

              // 在此處放置用戶代碼以初始化頁面

         }

(26)爲DataGraid1的DataGrid1_PageIndexChanged事件函數增長語句:

private void DataGrid1_PageIndexChanged(object source,System.Web.UI.WebControls.DataGridPageChangedEventArgs e)

         {

              DataGrid1.CurrentPageIndex=e.NewPageIndex;

              DataGrid1.DataBind();

         }

(27)在WebForm2放工具箱的HyperLink控件到窗體,Text=」輸入留言」,單擊屬性NavigateUrl後的按鈕,出現選擇URL對話框,選擇URL類型爲與根相關的,URL編輯框添入/LiuYanBan/WebForm1.aspx。

(28)運行,出現WebForm1,能夠輸入一條留言,單擊提交按鈕,再單擊超級連接查看留言,轉到WebForm2,單擊查看留言按鈕,能夠在Label1處看到留言,單擊超級連接輸入留言,轉到WebForm1。

 

 

第十一章              ASP.NET內建對象

ASP.NET爲保持瀏覽用戶的數據和信息,內建了許多對象,包括Application、Response、Request、cookie、Sessions、Cache和Server等對象,以及它們的大量的方法。經過這些對象,能夠提供網絡開發必不可少的功能,例如當前目錄的得到、在線人數、訪問網站總人數、網上商店中的購物筐等等。

11.1Request對象

Request對象主要有如下用途:第一用來來在不一樣網頁之間傳遞數據,第二是Web服務器能夠使用Request對象獲取用戶所使用的瀏覽器的信息,第三是Web服務器能夠使用Request對象顯示Web服務器的一些信息,最後,能夠用Request對象得到Cookie信息。本節主要介紹前三種用途,後邊有一節專門介紹Cookie。

11.1.1    用Request對象獲取另外一個網頁傳遞的數據

從一個網頁連接到另外一個網頁時,可能須要傳遞一些數據到另外一個網頁。兩個Web網頁之間通常經過表單(From)傳遞,具體傳遞方法有兩個:Post和Get。當數據傳遞到另外一個網頁時,另外一個網頁用Request對象的方法取出這些數據。見下例:(e11_1A.aspx)

<html>

<body>

<form action=e11_1B.aspx  method=POST  runat=server>

<asp:Label id=label1"  runat=server>用戶名:</asp:Label>

<asp:TextBox id="textBox1" Text="" runat=server></asp:TextBox>

<asp:button text="提交"  runat=server/>

</form>

</body>

</html>

其中action是用戶單擊此按鈕後,響應用戶程序網頁的URL,這裏是e11_1B.aspx。語句method=POST是數據用POST方法傳到e11_1B.aspx,也能夠是get方法。在e11_1B.aspx網頁中,是不能用string s= textBox1.Text語句獲得輸入的內容的,由於textBox1是另外一個網頁的對象。必須用語句string s=Request.Form("textBox1")獲得輸入的內容。若是將屬性method="POST"改成method="GET",用語句string s=Request.QueryString("textBox1")獲得輸入的內容。下邊是e11_1B.aspx網頁完整文件:

<html>

<script language="c#" runat=server>

void Page_Load(Object src,EventArgs e)

{//如用GET方法,修改成:"用戶名:"+Request.QueryString("textBox1");

Label1.Text="用戶名:"+Request.Form("textBox1");//用POST方法使用的語句

}

</script>

<body>

<form runat=server>

<asp:Label id="Label1" runat=server></asp:Label>

</form>

</body>

</html>

如Button按鈕改成HyperLink控件如何使用

11.1.2    用Request對象獲取客戶端瀏覽器的信息

不一樣瀏覽器或相同瀏覽器的不一樣版本支持不一樣的功能,Web應用程序可能要根據不一樣的瀏覽器採起不一樣的措施,可用HttpRequest.Browser屬性的HttpBrowserCapabilities對象得到用戶使用的瀏覽器信息。見下例:

<html>

<script language="c#" runat=server>

void Page_Load(Object src,EventArgs e)

{

string s="瀏覽器的特性以下:"+"<br>";

HttpBrowserCapabilities bc=HttpRequest.Browser;

S+="Type="+bc.Type+"<br>";

S+="Name="+bc.Browser+"<br>";

S+="Version="+bc.Version+"<br>";

S+="Major Version="+bc.MajorVersion+"<br>";

S+="Minor Version="+bc.MinorVersion+"<br>";

S+="Platform="+bc.Platform+"<br>";

S+="Is Beta="+bc.Beta+"<br>";

S+="Is Crawler="+bc.Crawler +"<br>";

S+="Is AOL="+bc.AOL +"<br>";

S+="Is Win16="+bc.Win16+"<br>";

S+="Is Win32="+bc.Win32+"<br>";

S+="Supports Frames="+bc.Frames+"<br>";

S+="Supports Tables="+bc.Tables+"<br>";

S+="Supports Cookies="+bc.Cookies+"<br>";

S+="Supports VB Script="+bc.VBScript+"<br>";

S+="Supports Java Script="+bc.JavaScript+"<br>";

S+="Supports Java Applets="+bc.JavaApplets +"<br>";

S+="Supports ActiveX Controls="+bc.ActiveXControls+"<br>";

S+="CDF="+bc.CDF+"<br>";

Label1.Text=s;

}

</script>

<body>

<form runat=server>

<asp:Label id="Label1" runat=server></asp:Label>

</form>

</body>

</html>

11.1.3    用Request對象獲取服務器信息

<html>

<script language="c#" runat=server>

void Page_Load(Object src,EventArgs e)

{

string s="服務器的特性以下:"+"<br>";

foreach(string Name in Request.ServerVariables)

{

s+=Name+":"+Request.ServerVariables(Name)+"<br>"

}

Label1.Text=s

}

</script>

<body>

<form runat=server>

<asp:Label id="Label1" runat=server></asp:Label>

</form>

</body>

</html>

11.2Response對象

與Request是獲取客戶端HTTP信息相反,Response對象是用來控制發送給用戶的信息,包括直接發送信息在瀏覽器中顯示、重定向瀏覽器到另外一個URL以及設置cookie的值。在ASP.NET中通常不用Response對象發送信息給瀏覽器,能夠用其它方法重定向瀏覽器到另外一個URL,所以在ASP.Net中使用Response對象的機會愈來愈少了,這裏只對Response對象作簡單介紹,設置cookie方法在另外一節介紹。

11.2.1         用Response對象發送信息在瀏覽器中顯示

(1)    在瀏覽器中顯示數據,例如:(在ASP.Net不建議這樣使用。)

<%@ Page language="c#" %>

<html>

<body>

<%

Response.Write("<font Size=7>");

Response.Write("Response對象使用");

Response.Write("</font");

Response.Write("<br>");

%>

</body>

</html>

(2)    顯示一個文件

<%@ Page language="c#" %>

<html>

<body>

<%

System.IO.FileStream fs=new System.IO.FileStream("d:\\asp\\g1.txt",FileMode.Open);

IntPtr FileHandle=fs.Handle;

Response.WriteFile(FileHand,0,fs.Length);

Fs.Close();

%>

</body>

</html>

11.2.2         用Response對象重定向瀏覽器

用Response對象重定向瀏覽器到新浪網主頁的例子以下:

<html>

<script language="c#" runat=server>

void EnterBtn_Click(Object src,EventArgs e)

{

Response.Redirect("http://www.sina.com.cn");

}

</script>

<body>

  <form runat=server>

  <asp:Label runat=server>單擊按鈕打開新浪網主頁</asp:Label>

  <br>

  <asp:button text="打開新浪網" Onclick="EnterBtn_Click" runat=server/>

  </form>

</body>

</html>

這裏實現的功能徹底能夠用HyperLink控件實現,請讀者試一試。可是若是根據條件用語句實現轉向其它網頁,使用此語句仍是必要的,例如,有些用戶企圖不通過登陸直接訪問其它網頁,在其它網頁的Page_Load方法中要進行判斷,若是未登陸,可用上述方法直接轉向登陸界面。

11.3Cookie對象

用戶用瀏覽器訪問一個網站,因爲採用的http的特性,Web服務器並不能知道是哪個用戶正在訪問,但一些網站,但願可以知道訪問者的一些信息,例如是否是第一次訪問,訪問者上次訪問時是否有未作完的工做,此次是否爲其繼續工做提供方便等等。用瀏覽器訪問一個網站,能夠在此網站的網頁之間跳轉,當從第一個網頁轉到第二個網頁時,第一個網頁中創建的全部變量和對象都將不存在。有時但願在這些被訪問的網頁中創建聯繫,例如一個網上商店,訪問者可能從不一樣的網頁中選取不一樣的商品,那麼用什麼辦法記錄該訪問者選取的商品,也就是通常所說的購物筐如何實現。用Cookie對象能夠解決以上問題。

11.3.1         用Cookie對象記錄訪問的次數

<html>

<script language="c#" runat=server>

void Page_Load(Object src,EventArgs e)

{

if(!Page.IsPostBack)//若是用戶單擊刷新按鈕,訪問次數不加1

{

int Num=1;

HttpCookie myCookie=Request.Cookies["VistNum"];

if(myCookie!=null)

{

myCookie.Value=myCookie.Values+1;

Num=myCookie.Values;

}

else

{

myCookie=new HttpCookie("VistNum");

myCookie.Values=1;

Response.Cookie.Add(myCookie);

}

Label1.Text="您是第"+Convert.ToString(Num)+"次訪問本站";

}

}

</script>

<body>

<form runat=server>

<asp:Label id="label1" runat=server></asp:Label>

</form>

</body>

</html>

固然,瀏覽器的Cookies必須設置爲容許使用。

11.3.2         網上商店購物筐實現

網上商店網站通常有多個網頁,用戶能夠瀏覽這些網頁,從每一個網頁中選擇商品,網上商店網站要記錄這些要購買的商品,通常把這個功能叫作購物筐,下邊的例子介紹購物筐的實現方法。例子中有兩個網頁,每一個網頁有一個CheckBoxList控件,能夠選不一樣商品,每一個網頁都有兩個按鈕,一個按鈕的標題是:把選中商品放入購物筐,另外一個按鈕的標題是:結算。

(1)    第一個網頁文件e11_3_2A.aspx以下:

<html>

<script language="c#" runat=server>

void button1_Click(Object src,EventArgs e)

{

string s;

HttpCookie myCookie;

for(int i=0;i<2;i++)

{

if(checkBoxList1.Items[i].Selected)

{

s=checkBoxList1.Items[i].Text;

checkBoxList1.Checked=false;//已記錄,清除所作選擇

myCookie=Request.Cookies[s];

if(myCookie!=null)

{

myCookie.Value=myCookie.Values+1;

}

else

{

myCookie=new HttpCookie(s);

myCookie.Values=1;

Response.Cookie.Add(myCookie);

}

}

}

}

void button2_Click(Object src,EventArgs e)

{

string s="您定購了以下商品:<br>";

HttpCookieCollextion myCookie myCookieS=Request.Cookies;

for(i=0;i<myCookieS.Length;i++)

{

s+=myCookieS[i].Name+":"+myCookieS[i].Value.ToString+"<br>"

}

label1.Text=s;

}

</script>

<body>

<form runat=server>

<asp:CheckBoxList id=checkBoxList1 runat=server>

<asp:ListItem Text="香蕉"/>

<asp:ListItem Text="蘋果"/>

</asp:CheckBoxList>

<br>

<asp:button text="把選中商品放入購物筐" Onclick="button1_Click" runat=server/>

<br>

<asp:button text="結算" Onclick="button2_Click" runat=server/>

<br>

<asp:HyperLink NaviGateUrl="e11_3_2B.aspx" runat=server/>選擇花卉</asp:HyperLink>

<br>

<asp:Label id="label1" Text="" runat=server></asp:Label>

</form>

</body>

</html>

(2)    第二個網頁文件e11_3_2B.aspx以下:

<html>

<script language="c#" runat=server>

void button1_Click(Object src,EventArgs e)

{

string s;

HttpCookie myCookie;

for(int i=0;i<2;i++)

{

if(checkBoxList1.Items[i].Selected)

{

s=checkBoxList1.Items[i].Text;

checkBoxList1.Checked=false;//已記錄,清除所作選擇

myCookie=Request.Cookies[s];

if(myCookie!=null)

{

myCookie.Value=myCookie.Values+1;

}

else

{

myCookie=new HttpCookie(s);

myCookie.Values=1;

Response.Cookie.Add(myCookie);

}

}

}

}

void button2_Click(Object src,EventArgs e)

{

string s="您定購了以下商品:<br>";

HttpCookieCollextion myCookie myCookieS=Request.Cookies;

for(i=0;i<myCookieS.Length;i++)

{

s+=myCookieS[i].Name+":"+myCookieS[i].Value.ToString+"<br>"

}

label1.Text=s;

}

</script>

<body>

<form runat=server>

<asp:CheckBoxList id=checkBoxList1 runat=server>

<asp:ListItem Text="菊花"/>

<asp:ListItem Text="茉莉"/>

</asp:CheckBoxList>

<br>

<asp:button text="把選中商品放入購物筐" Onclick="button1_Click" runat=server/>

<br>

<asp:button text="結算" Onclick="button2_Click" runat=server/>

<br>

<asp:HyperLink NaviGateUrl="e11_3_2A.aspx" runat=server/>選擇水果</asp:HyperLink>

<br>

<asp:Label id="label1" Text="" runat=server></asp:Label>

</form>

</body>

</html>

(3)    兩個個文件都存到宿主目錄中,在瀏覽器中輸入地址:http://Localhost/e11_3_2A.aspx,選中某種水果,轉到第二個網頁e11_3_2B.aspx,選中某種花卉,單擊結算按鈕,應顯示所選的全部商品。固然,本例只是說明問題,由許多不盡合理之處。讀者能夠採用數據庫,用DataGraid控件商品,增長一列,由兩個按鈕,標題分別是:放到購物筐和從購物筐取出。還應時刻顯示購物筐的內容。

Cookies 集合設置 cookie 的值。若指定的 cookie 不存在,則建立它。若存在,則設置新的值而且將舊值刪去。

語法 Response.Cookies(cookie)[(key)|.attribute]=value

這裏的 cookie 是指定 cookie 的名稱。而若是指定了 key,則該 cookie 就是一個字典。Attribute 指定 cookie 自身的有關信息。Attribute 參數能夠是下列之一 :

Domain 若被指定,則 cookie 將被髮送到對該域的請求中去。

Expires 指定 cookie 的過時日期。爲了在會話結束後將 cookie 存儲在客戶端磁盤上,必須設置該日期。若此項屬性的設置未超過當前日期,則在任務結束後 cookie 將到期。

HasKeys 指定 cookie 是否包含關鍵字。

Path 若被指定,則 cookie 將只發送到對該路徑的請求中。若是未設置該屬性,則使用應用程序的路徑。

11.4Application對象

Application對象生存期和Web應用程序生存期同樣長,生存期從Web應用程序網頁被訪問開始,HttpApplication類對象Application被自動建立,直到沒有一個網頁被訪問時結束,Application對象被自動撤銷。所以Application對象中的變量也有相同生存期,而且變量能夠被Web應用程序中的全部網頁訪問。所以,能夠在Application對象中創建一些全局的公用變量,因爲存儲在Application對象中的數值能夠被應用程序的全部網頁讀取,因此Application對象的屬性也適合在應用程序的網頁之間傳遞信息。Application對象主要有如下用途:

l   存儲記錄在線人數或訪問網站總人數的變量。

l   存儲網站共用最新消息,供全部網頁更新。

l   記錄網站中個網頁同一條廣告被點擊的次數或時間。

l   存儲供全部網頁使用的數據庫數據。

l   不一樣用之間通信,例如多用戶聊天室,多用戶遊戲等

本節首先介紹Application對象的用法,而後介紹記錄訪問網站總人數的實現方法。

11.4.1    Application對象屬性

雖然Application對象沒有內置的屬性,但咱們能夠使用如下句法設置用戶定義的屬性也可稱爲集合:Application("屬性/集合名稱")=值,例如,Application("MyVar")="Hello"。用如下語句取出數據:string s= Application("MyVar")。

11.4.2    方法

Application 對象有兩個方法,它們都是用於處理多個用戶對存儲在Application中的數據進行寫入的的同步問題。因爲存儲在Application對象中的數值能夠被應用程序的全部網頁讀取,所以一個用戶在修改這個變量時,不容許其它用戶修改,這兩個方法就是解決這個問題的。

l  L ock 方 法

Lock 方法阻止其餘客戶修改存儲在 Application 對象中的變量,以確保在同一時刻僅有一個客戶可修改和存取 Application 變量。若是用戶沒有明確調用 Unlock 方法,則服務器將在 .asp 文件結束或超時後即解除對 Application 對象的鎖定。

l  Unlock 方法

和Lock方法相反,Unlock方法容許其餘客戶修改Application對象的屬性。下例介紹一個計數器變量的使用方法。

Application.Lock;

Application["counter"]=(Int32)Application["counter"]+1;

Application.UnLock;

11.4.3    事件

l  Application_OnStart事件

第一個瀏覽器訪問Web應用程序網頁時,產生的事件。

l  Application_OnEnd事件

沒有瀏覽器訪問時Web應用程序網頁時,產生的事件。

Application_OnStart和Application_OnEnd事件的處理過程必須寫在global.asax文件之中。

11.4.4    例子:顯示訪問網站總人數

(1)  創建一個主頁文件Default.aspx以下:

<html>

<script language="c#" runat=server>

void Page_Load(Object src,EventArgs e)

{

if(!Page.IsPostBack)//若是用戶單擊刷新按鈕,計數器不加1

{

int num;

Application.Lock;

Application["counter"]=(Int32)Application["counter"]+1;

num=(Int)Application["counter"];

Application.UnLock;

label1.Text=Convert.ToString(num);

}

}

</script>

<body>

<form runat=server>

<asp:Label id="label1" Text="" runat=server></asp:Label>

<br>

<asp:HyperLink id="hLink1" NavigaterUrl="other.aspx" Target="_blank" runat=server>

單擊此處轉到e1.aspx,計數器不加1。

</asp:HyperLink >

</form>

</body>

</html>

(2)  創建other.aspx網頁文件以下:

<html>

<script language="c#" runat=server>

void Page_Load(Object src,EventArgs e)

{

Int num=(Int)Application["counter"];

label1.Text=Convert.ToString(num);

}

}

</script>

<body>

<form runat=server>

<asp:Label id="label1" Text="" runat=server></asp:Label>

<br>

<asp:HyperLink id="hLink1" NavigaterUrl="default.aspx" runat=server>

單擊此處轉到dault.aspx,計數器不加1。

</asp:HyperLink >

</form>

</body>

</html>

(3)  創建global.asax文件以下:

<script language="c#" runat=server>

void Application_OnStart(Object src,EventArgs e)

{

Application.Add("counter",0);

}

</script>

(4)  三個文件都存到宿主目錄中,在瀏覽器重輸入URL地址:http://Localhost/,查看顯示的計數器數值,單擊刷新按鈕,查看顯示的計數器數值是否改變,轉到Other.aspx網頁,在轉回dault.aspx網頁,查看顯示的計數器數值是否改變。關閉全部網頁,在打開default.aspx網頁,顯示的計數器值從0開始,這是由於沒有網頁訪問網站時,Application對象被自動撤銷。在打開新網頁,產生Application_OnStart事件,將counter值爲0。爲了解決此問題,能夠創建一個文件,記錄訪問網站總人數,初值爲0,Application_OnStart事件函數中,從文件取出已訪問網站總人數,賦值給counter,Application_OnEnd事件函數中,將counter存到文件中。 (下載源碼就到源碼網:www.codepub.com

(5)  用記事本建立文件counter_File.txt,其中內容爲字符0。存文件到宿主目錄中。

(6)  修改global.asax文件以下:

<script language="c#" runat=server>

void Application_OnStart(Object src,EventArgs e)

{//用Server對象對象獲得counter_File文件絕對路徑

string s=Serve.MapPath(\counter_File.txt);

Application.Add("counterFile",s);//保存供Application_OnEnd事件函數使用

System.IO.FileStream fs=new System.IO.FileStream("s",FileMode.OpenOrCreate);

System.IO.StreamReader r=new System.IO.StreamReader(fs);

s=r.ReadLine();

r.Close();

Application.Add("counter",Convert.ToInt(s));

}

void Application_OnEnd(Object src,EventArgs e)

{//此時Server對象已不存在,沒法用Server對象獲得counter_File文件絕對路徑

string s= (string)Application("counterFile");//取出保存的計數文件的全路徑地址

System.IO.FileStream fs=new System.IO.FileStream("s",FileMode.OpenOrCreate);

System.IO.StreamWrite w=new System.IO.StreamWrite(fs);

int num=(int)Application("counterFile");

w.Write(num.ToString());

w.Close();

}

</script>

(7)  再一次訪問dault.aspx網頁,看是否已解決以上提出的問題。這裏還有一個問題,若是用用以下URL訪問網頁:http://Localhost/Other.aspx,這樣計數器就不能計數,解決的方法見Session 對象一節。

11.5  Session對象

前邊提到,用瀏覽器訪問一個網站,當在網站的網頁之間跳轉時,但願在這些被訪問的網頁中創建聯繫,例如一個網上商店的購物筐的實現,這些能夠用Cookie實現。用Session對象也能夠解決以上問題。

當瀏覽器開始訪問網站的某網頁時,Web服務器將自動建立一個Session對象,在Session對象中能夠創建一些變量,這個Session對象和Session對象中的變量只能被這個訪問者使用,其它訪問者不能使用。當用戶在網站的網頁之間跳轉時,Session對象和存儲在Session對象中的變量不會被清除,這些變量始終存在。當瀏覽器離開本網站或超過必定時間和網站沒有聯繫,Session對象被撤銷,同時存儲在Session中的變量也不存在了。

在ASP中,Session對象的功能本質上是用Cookie實現的,若是用戶將瀏覽器上面的Cookies設置爲禁用,那麼Session就不能工做。但在ASP.NET中咱們有解決方法,在config.web文件中,咱們將<sessionstate cookieless="false" />設置爲true就能夠了,也就說,不使用Cookies也能夠使用Session。

 

11.5.1         屬性

l  SessionIDSessionID 屬性返回用戶的會話標識。在建立會話時,服務器會爲每個會話生成一個單獨的標識。會話標識以長整形數據類型返回。在不少狀況下 SessionID 能夠用於 WEB 頁面註冊統計。

l  TimeOut Timeout 屬性以分鐘爲單位爲該應用程序的 Session 對象指定超時時限。若是用戶在該超時時限以內不刷新或請求網頁,則該會話將終止。

11.5.2         方法

Session 對象僅有一個方法,就是 Abandon,Abandon 方法刪除全部存儲在 Session 對象中的對象並釋放這些對象的源。若是您未明確地調用 Abandon 方法,一旦會話超時,服務器將刪除這些對象。當服務器處理完當前頁時,下面示例將釋放會話狀態。 < % Session.Abandon %>

11.5.3         事件

Session 對象有兩個事件可用於在 Session 對象啓動和釋放是運行過程。

l  Session_OnStart 事件在服務器建立新會話時發生,當用戶第一次瀏覽網頁時,發生Session_OnStart事件。服務器在執行請求的頁以前先處理該腳本。Session_OnStart 事件是設置會話期變量的最佳時機,由於在訪問任何頁以前都會先設置它們。儘管在 Session_OnStart 事件包含 Redirect 或 End 方法調用的狀況下 Session 對象仍會保持,然而服務器將中止處理 Global.asa 文件並觸發 Session_OnStart 事件的文件中的腳本。爲了確保用戶在打開某個特定的 W eb 頁 時始終啓動一個會話,就能夠在 S ession_OnStart 事 件中調用 R edirect 方 法。當用戶進入應用程序時,服務器將爲用戶建立一個會話並處理 S ession_OnStart 事 件腳本。您能夠將腳本包含在該事件中以便檢查用戶打開的頁是否是啓動頁,若是不是,就指示用戶調用 R esponse.Redirect 方 法啓動網頁。程序以下 : < SCRIPT RUNAT=Server Language=VBScript> Sub Session_OnStart startPage = "/MyApp/StartHere.asp" currentPage = Request.ServerVariables("SCRIPT_NAME") if strcomp(currentPage,startPage,1) then Response.Redirect(startPage) end if End Sub < /SCRIPT> 上述程序只能在支持 cookie 的瀏覽器中運行。由於不支持 cookie 的瀏覽器不能返回 SessionID cookie,因此,每當用戶請求 Web 頁時,服務器都會建立一個新會話。這樣,對於每一個請求服務器都將處理 Session_OnStart 腳本並將用戶重定向到啓動頁中。

l  Session_OnEnd 事件在會話被放棄或超時發生。若是用戶在指定時間內沒有請求或刷新應用程序中的任何頁,會話將自動結束。這段時間的默認值是 2 0 分 鍾。能夠經過在 I nternet 服 務管理器中設置「應用程序選項」屬性頁中的「會話超時」屬性改變應用程序的默認超時限制設置。應依據您的 W eb 應 用程序的要求和服務器的內存空間來設置此值。例如,若是您但願瀏覽您的 W eb 應 用程序的用戶在每一頁僅停留幾分鐘,就應該縮短會話的默認超時值。過長的會話超時值將致使打開的會話過多而耗盡您的服務器的內存資源。對於一個特定的會話,若是您想設置一個小於默認超時值的超時值,能夠設置 S ession 對 象的 T imeout 屬 性。例如,下面這段腳本將超時值設置爲 5 分 鍾。 < % Session.Timeout = 5 %> 固然你也能夠設置一個大於默認設置的超時值,Session.Timeout 屬性決定超時值。你還能夠經過 Session 對象的 Abandon 方法顯式結束一個會話。例如,在表格中提供一個「退出」按鈕,將按鈕的 ACTION 參數設置爲包含下列命令的 .asp 文件的 URL。 < % Session.Abandon %>

l   

11.5.4         用Session對象實現網上商店購物筐

本例要求和用Cookie實現網上商店購物筐徹底同樣,只是用Session對象實現,具體代碼以下:

(1)    第一個網頁文件e11_5_4A.aspx以下:

<html>

<script language="c#" runat=server>

void button1_Click(Object src,EventArgs e)

{

string s;

for(int i=0;i<2;i++)

{

if(checkBoxList1.Items[i].Selected)

{

s=checkBoxList1.Items[i].Text;

checkBoxList1.Checked=false;//已記錄,清除所作選擇

if(Session[s]!=null)

{

Session[s]=Session[s]+1;

}

else

{

Session[s]=1;

}

}

}

}

void button2_Click(Object src,EventArgs e)

{

string s="您定購了以下商品:<br>";

string keyName;

for(i=0;i<Session.Count;i++)

{

keyName=Session.Keys[i];

s+=keyName+":"+Session[keyName].ToString+"<br>"

}

label1.Text=s;

}

</script>

<body>

<form runat=server>

<asp:CheckBoxList id=checkBoxList1 runat=server>

<asp:ListItem Text="香蕉"/>

<asp:ListItem Text="蘋果"/>

</asp:CheckBoxList>

<br>

<asp:button text="把選中商品放入購物筐" Onclick="button1_Click" runat=server/>

<br>

<asp:button text="結算" Onclick="button2_Click" runat=server/>

<br>

<asp:HyperLink NaviGateUrl="e11_5_4B.aspx" runat=server/>選擇花卉</asp:HyperLink>

<br>

<asp:Label id="label1" Text="" runat=server></asp:Label>

</form>

</body>

</html>

(2)    第二個網頁文件e11_5_4B.aspx以下:

<html>

<script language="c#" runat=server>

void button1_Click(Object src,EventArgs e)

{

string s;

for(int i=0;i<2;i++)

{

if(checkBoxList1.Items[i].Selected)

{

s=checkBoxList1.Items[i].Text;

checkBoxList1.Checked=false;//已記錄,清除所作選擇

if(Session[s]!=null)

{

Session[s]=Session[s]+1;

}

else

{

Session[s]=1;

}

}

}

}

void button2_Click(Object src,EventArgs e)

{

string s="您定購了以下商品:<br>";

string keyName;

for(i=0;i<Session.Count;i++)

{

keyName=Session.Keys[i];

s+=keyName+":"+Session[keyName].ToString+"<br>"

}

label1.Text=s;

}

</script>

<body>

<form runat=server>

<asp:CheckBoxList id=checkBoxList1 runat=server>

<asp:ListItem Text="菊花"/>

<asp:ListItem Text="茉莉"/>

</asp:CheckBoxList>

<br>

<asp:button text="把選中商品放入購物筐" Onclick="button1_Click" runat=server/>

<br>

<asp:button text="結算" Onclick="button2_Click" runat=server/>

<br>

<asp:HyperLink NaviGateUrl="e11_5_4A.aspx" runat=server/>選擇水果</asp:HyperLink>

<br>

<asp:Label id="label1" Text="" runat=server></asp:Label>

</form>

</body>

</html>

(3)    兩個個文件都存到宿主目錄中,在瀏覽器中輸入地址:http://Localhost/e11_3_2A.aspx,選中某種水果,轉到第二個網頁e11_3_2B.aspx,選中某種花卉,單擊結算按鈕,應顯示所選的全部商品。象前邊所說,本例不盡合理,讀者能夠採用數據庫,用DataGraid控件商品,增長一列,由兩個按鈕,標題分別是:放到購物筐和從購物筐取出。還應時刻顯示購物筐的內容。

 

11.6Server 對象

Server對象提供對服務器上的資源進行訪問的方法和屬性,主要包括:獲得服務器的計算機名稱,設置腳本程序的失效時間,將HTML的特殊標記轉變爲ASCII字符,獲得文件的真實路徑等等,本節將逐一介紹這些方法。

11.6.1    屬性MachineName和ScriptTimeout

(1)  屬性MachineName

該屬性用來獲取當前運行Web應用程序的Web服務器的計算機名稱,使用方法以下:string s=Server.MachineName;這個計算機名稱能夠用以下辦法查到:打開」控制面板」,選中」系統」中的」計算機名」,應和用Server對象的屬性MachineName得到計算機名稱一致。

(2)  屬性ScriptTimeout

Web應用程序因爲運行在計算機網絡中,因爲網絡的緣由,一些程序可能沒法完成,一直在等待,這將極大消耗Web服務器的資源,爲了不這種狀況,能夠設置程序運行的最長時間,即設置屬性ScriptTimeout,在腳本程序運行超過屬性ScriptTimeout指定時間以後即做超時處理,也就中止程序運行。如如下代碼指定服務器處理腳本程序在100秒後超時:Server.ScriptTimeout=100,其默認值爲90秒。

11.6.2    HtmlEncode方法

HTML標記語言中,有些ASCII字符被做爲標記,例如字符串:<br>中的<和>都是標記,如須要顯示這些字符,必須做特殊處理,例如爲了在瀏覽器中正確顯示以下字符串:」<br>是換行標記」,字符串必須寫爲以下形式:

<asp:Label id="label1" Text="%3cbr%3c是換行標記" runat=server></asp:Label>;

也能夠用Server對象的屬性HtmlEncode方法,用法以下:

<asp:Label id="label1" runat=server>Server.HtmlEncode(」<br>是換行標記」)</asp:Label>;

11.6.3    URLEncode方法

URL是Uniform Resource Location(統一資源定位器)的簡稱,URL用來定位一個網頁的。在URL中,有些ASCII字符具備特殊含義,必須作特殊處理。例如http://www.sina.com/中的字符/,用Server對象URLEncode方法處理,

string s=」http://www.sina.com/」;

 

11.6.4    MapPath方法

網頁中網頁文件的路徑通常是以宿主目錄爲根目錄,不一樣的系統中,宿主目錄所在的實際目錄並不相同,並且網頁也可能在虛擬目錄中。所以網頁文件的路徑並非網頁文件的實際路徑。而在用File類處理文件時,則要求文件的地址必須是實際的全路徑,Server對象的MapPath方法提供這兩種路徑的轉換方法,例如,f1.aspx文件存在宿主目錄下的Test目錄下,用Server對象獲得f1.aspx文件絕對路徑方法以下:

string s=Serve.MapPath(\Test\f1.aspx);//這裏\表示以宿主目錄

也能夠用以下語句:

string s=Serve.MapPath(Test\f1.aspx);//表示單前網頁所在的目錄的子目錄Test

習題

(1)  如何實現記錄訪問網站的在線人數。(提示:增長一個Application對象變量做爲計數器,Application_Start事件函數中計數器爲0,Session_Start事件函數中計數器加1,Session_End事件函數中計數器減1,每一個網頁的Page_Load事件函數中用Label控件顯示計數器值。)

(2)  用Application對象創建一個2人聊天室。若是是多人聊天室,又如何實現。

(3)  用戶不通過主頁,直接訪問網站的某網頁,將不能時訪問者總數加1,如何防止。

(4)  將書中的例子用Visual Studio.Net實現。

 

 

第十二章              可擴展標記語言

12.1  HTML及其缺點

Internet提供了全球範圍的網絡互連與通訊功能,Web技術的發展更是一日千里,其豐富的信息資源給人們的學習和生活帶來了極大的便利。特別是應運而生的HTML(超文本置標語言),以簡單易學、靈活通用的特性,令人們發佈、檢索、交流信息都變得很是簡單,從而使Web成了最大的環球信息資源庫。然而,電子商務、電子出版、遠程教育等基於Web的新興領域的全面興起使得傳統的Web資源更加複雜化、多樣化,數據量的日趨龐大對網絡的傳輸能力也提出更高的要求,人們對Web服務功能的需求也達到更高的標準。而傳統的HTML因爲自身特色的限制,不能知足這些要求。HTML主要有以下不足:

l  HTML的標記都是預先定義的,用戶不能自定義有意義的標記,可擴展性差。

l  HTML的顯示方式內嵌在數據中,這樣在建立文本時,要同時考慮輸出格式,若是由於需求不一樣而須要對一樣的內容進行不一樣風格的顯示時,要從頭建立一個全新的文檔,重複工做量很大。不能對數據按照不一樣的需求進行多樣化顯示等個性化服務。

l  HTML缺少對數據結構的描述,對於應用程序理解文檔內容、抽取語義信息都有諸多不便。不能進行智能化的語義搜索。不能對不一樣平臺、不一樣格式的數據源進行數據集成和數據轉化等。

l  HTML語言不能描述矢量圖形、數學公式、化學符號等特殊對象。

12.2  SGML(標準通用置標語言)

SGML(Standard Generalized Markup Language)是一種通用的文檔結構描述置標語言,爲語法置標提供了異常強大的工具,同時具備極好的擴展性,所以在數據分類和索引中很是有用。但SGML複雜度過高,不適合網絡的平常應用,加上開發成本高、不被主流瀏覽器所支持等緣由,使得SGML在Web上的推廣受到阻礙。

12.3  XML(可擴展置標語言)

XML(eXtensible Markup Language)是由W3C於1998年2月發佈的一種標準。它一樣是SGML的一個簡化子集,它將SGML的豐富功能與HTML的易用性結合到Web的應用中,以一種開放的自我描述方式定義了數據結構,在描述數據內容的同時能突出對結構的描述,從而體現出數據之間的關係。XML的優勢以下:

l  XML簡單易用,功能強大。

l  XML容許各個組織、我的創建適合本身須要的標記集合,而且這些標記能夠用通用的工具顯示。例如定義數學、化學、音樂等專用標記。

l  XML的最大優勢在於它的數據存儲格式不受顯示格式的制約。通常來講,一篇文檔包括三個要素:數據、結構以及顯示方式。XML把文檔的三要素獨立開來,分別處理。首先把顯示格式從數據內容中獨立出來,保存在樣式表文件(Style Sheet)中,這樣若是須要改變文檔的顯示方式,只要修改樣式表文件就好了。XML的自我描述性質可以很好地表現許多複雜的數據關係,使得基於XML的應用程序能夠在XML文件中準確高效地搜索相關的數據內容,忽略其餘不相關部分。

l  XML還有其餘許多優勢,好比它有利於不一樣系統之間的信息交流,徹底能夠充當網際語言,並有但願成爲數據和文檔交換的標準機制。

因爲以上優勢,XML必將在商務的自動化處理,信息發佈,智能化的Web應用程序和數據集成等領域被普遍被使用。

12.4  XML的文檔格式

首先介紹XML文檔內容的基本單元——元素,它的語法格式以下:

〈標籤〉文本內容〈/標籤〉

元素是由起始標籤、元素內容和結束標籤組成。用戶把要描述的數據對象放在起始標籤和結束標籤之間。例如:

<姓名>王平</姓名>

不管文本內容有多長或者多麼複雜,XML元素中還能夠再嵌套別的元素,這樣使相關信息構成等級結構。下面的例子中,在<學生>的元素中包括了全部學生的信息,每一個學生都由<學生>元素來描述,而<學生>元素中又嵌套了<編號>、<姓名>、<性別>和<年齡>元素。完整XML文件student.xml內容以下,例1:

<?xml version="1.0" encoding="GB2312"?>

<?xml-stylesheet type="text/xsl" href="student1.xsl"?>

<學生>

       <編號>001</編號>

       <姓名>張三</姓名>

       <性別>男</性別>

       <年齡>20</年齡>

</學生>

除了元素,XML文檔中能出現的有效對象是:聲明指令、註釋、根元素、子元素和屬性。

l  聲明指令

聲明指令給XML解析器提供信息,使其可以正確解釋文檔內容,它的起始標識是「<?」,結束標識是「?>」。常見的XML聲明就是一個處理指令:

<?xml version="1.0" encoding="GB2312"?>

該處理指令指明XML使用的版本號和文檔的編碼方式是"GB2312"。又如:

<?xml-stylesheet type="text/xsl" href="student1.xsl"?>

使用student1.xsl樣式表文件顯示本XML文檔。

l  註釋

註釋是XML文件中用做解釋的字符數據,XML處理器不對它們進行任何處理。註釋是用「<!--」和「 --> 」引發來的,能夠出如今XML元素間的任何地方,可是不能夠嵌套:

<!--這是一個註釋-->

l  根元素和子元素

若是一個元素從文件頭的序言部分以後開始一直到文件尾,包含了文件中全部的數據信息,咱們稱之爲根元素。XML元素是能夠嵌套的,那麼被嵌套在內的元素稱爲子元素。在前面的例子中,<編號>就是<學生>的子元素。

l  屬性

屬性給元素提供進一步的說明信息,它必須出如今起始標籤中。屬性以名稱/取值對出現,屬性名不能重複,名稱與取值之間用等號「=」分隔,並用引號把取值引發來。例如:

<工資 currency=「US$」> 25000 </工資>

上例中的屬性說明了薪水的貨幣單位是美圓。

l  XML文檔的基本結構

XML文檔的基本結構由序言部分和一個根元素組成。序言包括了XML聲明和DTD(或者是XML Schema),DTD(Document Type Define,文檔定義類型)和XML Schema都是用來描述XML文檔結構的,也就是描述元素和屬性是如何聯繫在一塊兒的。例如,在例1的文檔前面加上以下的序言部分,就構成了一個完整的XML文檔:

<?xml version="1.0" encoding="GB2312"?>

<?xml-stylesheet type="text/xsl" href="student1.xsl"?>

<!DOCTYPE employees SYSTEM「employees.dtd」>

一個XML文檔中有且僅有一個根元素,其餘全部的元素都是它的子元素,在例1中,<學生>就是根元素。

l  格式良好的」(Well-Formed)XML文檔

一個XML文檔首先應當是「格式良好的」(Well-Formed),該規定的正式定義位於:http://www.w3.org/TR/REC-xml。「格式良好的」XML文檔除了要知足根元素惟一的特性以外,還包括:

(1)    起始標籤和結束標籤應當匹配:結束標籤是必不可少的;

(2)    大小寫應一致:XML對字母的大小寫是敏感的,<employee>和<Employee>是徹底不一樣的兩個標籤,因此結束標籤在匹配時必定要注意大小寫一致;

(3)    元素應當正確嵌套:子元素應當徹底包括在父輩元素中,下面的例子就是嵌套錯誤:

<A>
<B>
</A>
</B>
正確的嵌套方式以下:
<A>
<B>
</B>
</A>
(4) 屬性必須包括在引號中;元素中的屬性是不容許重複的。

12.5  用XSL文件顯示XML文檔

因爲XML文檔只是定義數據的結構,並不包含顯示的格式。如要按指定格式顯示這些數據,還要使用CSS文件或XSL文件定義顯示格式。這裏使用三個XSL文件按不一樣顯示格式顯示同一個XML文件。首先定義一個student1.xsl文件顯示上邊XML文檔,文件以下:

<?xml version="1.0" encoding="GB2312"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/TR/WD-xsl">

       <xsl:template match="/">

              <xsl:for-each select="學生">

                     <xsl:value-of select="編號"/>,

                     <xsl:value-of select="姓名"/>,

                     <xsl:value-of select="性別"/>,

                     <xsl:value-of select="年齡"/>

              </xsl:for-each>

       </xsl:template>

</xsl:stylesheet>

將student1.xsl文件和文件student1.xml存到同一文件夾,雙擊student1.xml文件,打開IE5.0,顯示效果以下:

001, 張三, 男, 20

能夠定義不一樣的xsl文件,以不一樣的顯示方式顯示student1.xml文件。例如student2.xsl文件以下:

<?xml version="1.0" encoding="GB2312"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/TR/WD-xsl">

       <xsl:template match="/">

              <html>

                     <head>

                            <meta http-equiv="Content-Type" content="text/html; charset=gb2312"/>

                            <title>演示2</title>

                     </head>

                     <body>

                            <xsl:for-each select="學生">

                                   <table border="1" cellpadding="0" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" width="100%" id="AutoNumber1">

                                          <tr>

                                                 <td width="50%">編號</td>

                                                 <td width="50%">

                                                        <xsl:value-of select="編號"/>

                                                 </td>

                                          </tr>

                                          <tr>

                                                 <td width="50%">姓名</td>

                                                 <td width="50%">

                                                        <xsl:value-of select="姓名"/>

                                                 </td>

                                          </tr>

                                          <tr>

                                                 <td width="50%">性別</td>

                                                 <td width="50%">

                                                        <xsl:value-of select="性別"/>

                                                 </td>

                                          </tr>

                                          <tr>

                                                 <td width="50%">年齡</td>

                                                 <td width="50%">

                                                        <xsl:value-of select="年齡"/>

                                                 </td>

                                          </tr>

                                   </table>

                            </xsl:for-each>

                     </body>

              </html>

       </xsl:template>

</xsl:stylesheet>

例如用student3.xsl以不一樣的顯示方式顯示student1.xml文件。文件以下:

<?xml version="1.0" encoding="GB2312"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/TR/WD-xsl">

       <xsl:template match="/">

              <html>

                     <head>

                            <meta http-equiv="Content-Type" content="text/html; charset=gb2312"/>

                            <title>演示3</title>

                     </head>

                     <body>

                            <p align="center">學生信息</p>

                            <xsl:for-each select="學生">

                                   <form method="POST" action="--WEBBOT-SELF--">

                                          <table border="0" cellpadding="0" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" width="100%" id="AutoNumber1">

                                                 <tr>

                                                        <td width="45%" align="right">編號:</td>

                                                        <td width="5%" align="center"> </td>

                                                        <td width="50%">

                                                               <input type="text" name="編號" size="20">

                                                                      <xsl:attribute name="value">

                                                                             <xsl:value-of select="編號"/>

                                                                      </xsl:attribute>

                                                               </input>

                                                        </td>

                                                 </tr>

                                                 <tr>

                                                        <td width="45%" align="right">姓名:</td>

                                                        <td width="5%" align="center"> </td>

                                                        <td width="50%">

                                                               <input type="text" name="姓名" size="20">

                                                                      <xsl:attribute name="value">

                                                                             <xsl:value-of select="姓名"/>

                                                                      </xsl:attribute>

                                                               </input>

                                                        </td>

                                                 </tr>

                                                 <tr>

                                                        <td width="45%" align="right">性別:</td>

                                                        <td width="5%" align="center"> </td>

                                                        <td width="50%">

                                                               <input type="text" name="性別" size="20">

                                                                      <xsl:attribute name="value">

                                                                             <xsl:value-of select="性別"/>

                                                                      </xsl:attribute>

                                                               </input>

                                                        </td>

                                                 </tr>

                                                 <tr>

                                                        <td width="45%" align="right">年齡:</td>

                                                        <td width="5%" align="center"> </td>

                                                        <td width="50%">

                                                               <input type="text" name="年齡" size="20">

                                                                      <xsl:attribute name="value">

                                                                             <xsl:value-of select="年齡"/>

                                                                      </xsl:attribute>

                                                               </input>

                                                        </td>

                                                 </tr>

                                          </table>

                                          <p align="center">

                                                 <input type="submit" value="Submit" name="B1"/>

                                                 <input type="reset" value="Reset" name="B2"/>

                                          </p>

                                   </form>

                            </xsl:for-each>

                            <p align="center"> </p>

                     </body>

              </html>

       </xsl:template>

</xsl:stylesheet>

讀者能夠試一下。

12.6  .NET對XML的支持

首先,建立一個XML文檔,文件名爲MyXMLFile.xml,內容以下:

<?xml version="1.0" encoding="GB2312" ?>

<!--這是一個註釋-->

<bookstore>

       <book 出版社="電子工業出版社">

              <書名>SQL實用全書</書名>

              <做者>Rafe Colburn</做者>

              <出版日期>2001年6月</出版日期>

              <價格>34.00</價格>

       </book>

       <book 出版社="清華大學出版社">

              <書名>C#高級編程</書名>

              <做者>Simon Robinson</做者>

              <出版日期>2002年6月</出版日期>

              <價格>128.00</價格>

       </book>

       <book 出版社="人民郵電出版社">

              <書名>ASP.NET從入門到精通</書名>

              <做者>Chris Payne</做者>

              <出版日期>2002年1月</出版日期>

              <價格>41.00</價格>

       </book>

       <book 出版社="中國青年出版社">

              <書名>精通C#與ASP.NET程序設計</書名>

              <做者>孫三才</做者>

              <出版日期>2003年6月</出版日期>

              <價格>39.00</價格>

       </book>

       <book 出版社="電子工業出版社">

              <書名>ASP.NET實用全書</書名>

              <做者>張三</做者>

              <出版日期>2004年6月</出版日期>

              <價格>55.00</價格>

       </book>

</bookstore>

請讀者用IE瀏覽器(5.0以上版本)瀏覽MyXMLFile.xml文件,單擊標記前的減號(或加號),看一下效果。

網頁文件c8-1-1A.aspx用來讀出每本書的書名、做者、出版日期、價格等數據。

<%@ Page Language="C#" %>

<%@ Import Namespace="System.Xml" %>

<html>

<title>讀XML文件</title>

<script runat=server>

public void Page_Load(Object sender, EventArgs e)

{

       string FileNameString="d:\\asp\\bookExample\\MyXMLFile.xml";

       XmlTextReader dr= new XmlTextReader(FileNameString);

       while(dr.Read())

         if(dr.NodeType==XmlNodeType.Text)

            ListBox1.Items.Add(dr.Value);

}

</script>

<body>

<h2>讀XML文件</h2>

<form runat=server>

    <asp:ListBox id="ListBox1" runat="server"/>

</form>

</body>

</html>

當用XmlTextReader讀(dr.Read())Xml文檔時,每次讀出一個節點的數據。

一個Xml文檔的元素,能夠分爲兩大類,第一類是文本,第二類是標記。文本是Xml文檔的數據,在兩個標記之間的文本被稱爲一個文本節點,例如,<書名>SQL實用全書</書名>中的」SQL實用全書」是一個文本節點。這個節點的類型是:Xml.XmlNodeType.Text。

第二類Xml文檔的元素是標記,它能夠分爲如下幾大類:註釋標記、聲明標記、開始標記,結束標記,每類都被稱爲一個Xml文檔的標記節點,例如,<!--這是一個註釋-->是註釋標記,註釋標記的節點類型爲:Xml.XmlNodeType.Comment,註釋的內容爲dr.Value。<?xml version="1.0" encoding="GB2312" ?>是聲明標記,其中包括兩個聲明:xml version="1.0"和encoding="GB2312",等號前內容的被稱爲聲明的名稱(dr.Name),等號後內容的被稱爲聲明的值(dr.Value)。聲明標記的節點類型爲:Xml.XmlNodeType.XmlDeclartion。<book 出版社="電子工業出版社">是開始標記,book被稱爲標記名稱(dr.Name),出版社被稱爲屬性(dr.AttributeName),"電子工業出版社"被稱爲屬性的值(Value)。開始標記的節點類型爲:Xml.XmlNodeType.Element。</book>是結束標記,book被稱爲標記名稱(dr.Name)。結束標記的節點類型爲:Xml.XmlNodeType.EndElement。

本網頁的Page_Load方法中,用dr.Read()讀Xml文檔,每次讀出一個節點的數據,用語句if(dr.NodeType==XmlNodeType.Text)判斷是不是文本節點,若是是文本節點,則把文本內容加到ListBox1。若是但願只顯示書名,則判斷語句能夠改成:if(dr.NodeType==XmlNodeType.Text && dr.Name==」書名」)。

網頁文件c8-1-1B.aspx用來讀出標記book的屬性,具體內容以下:

<%@ Page Language="C#" %>

<%@ Import Namespace="System.Xml" %>

<html>

<title>讀XML文件</title>

<script runat=server>

public void Page_Load(Object sender, EventArgs e)

{

       string FileNameString="d:\\asp\\bookExample\\MyXMLFile.xml";

       XmlTextReader dr= new XmlTextReader(FileNameString);

       while(dr.Read())

         if(dr.NodeType==XmlNodeType.Element)

            for(int i=0;i<dr.AttributeCount;i++)

              ListBox1.Items.Add(dr.GetAttribute(i));

}

</script>

<body>

<h2>讀XML文件</h2>

<form runat=server>

    <asp:ListBox id="ListBox1" runat="server"/>

</form>

</body>

</html>

若是,顯示註釋,改成下列語句:

public void Page_Load(Object sender, EventArgs e)

{

       string FileNameString="d:\\asp\\bookExample\\MyXMLFile.xml";

       XmlTextReader dr= new XmlTextReader(FileNameString);

       while(dr.Read())

         if(dr.NodeType==XmlNodeType.Comment)

            ListBox1.Items.Add(dr.Value);

}

若是,顯示聲明,改成下列語句:(見c8-1-1c.aspx)

<%@ Page Language="C#" %>

<%@ Import Namespace="System.Xml" %>

<html>

<title>讀XML文件</title>

<script runat=server>

public void Page_Load(Object sender, EventArgs e)

{

       string FileNameString="d:\\asp\\bookExample\\MyXMLFile.xml";

       XmlTextReader dr= new XmlTextReader(FileNameString);

       while(dr.Read())

         if(dr.NodeType==XmlNodeType.XmlDeclaration)

            ListBox1.Items.Add(dr.Name+" "+dr.Value);

}

</script>

<body>

<h2>讀XML文件</h2>

<form runat=server>

    <asp:ListBox id="ListBox1" runat="server"/>

</form>

</body>

</html>

下例用DataGrid控件顯示MyXMLFile.xml,(見c8-1-1D.aspx)

<%@ Page Language="C#" %>

<%@ Import Namespace="System.Xml" %>

<%@ Import Namespace="System.Data" %>

<html>

<title>讀XML文件</title>

 

<script runat=server>

public void Page_Load(Object sender, EventArgs e)

{

       string FileNameString="d:\\asp\\bookExample\\MyXMLFile.xml";

       DataSet ds = new DataSet();

       ds.ReadXml(FileNameString);

       DataGrid1.DataSource=ds;

       DataGrid1.DataMember="book";

       DataGrid1.DataBind();

}

</script>

 

 

<body>

<h2>讀XML文件</h2>

 

<form runat=server>

    <asp:DataGrid id="DataGrid1" runat="server"/>

</form>

 

</body>

</html>

12.7  ADO.NET和XML

仔細察看MyXMLFile.xml文件,它和數據庫的表有對應關係,標記<bookstore>之間的內容能夠看做一個數據庫的表,標記<book>之間的內容能夠看做一個數據庫的表的一個記錄,標記<書名>、<做者>、<出版日期>、<價格>能夠看做一個數據庫的表的字段,這些標記之間的文本能夠看做這些字段的數據。咱們知道,一個字段還有一些其餘屬性,例如,字段的數據類型,爲了表示這些屬性,能夠使用DTD(Document Type Define,文檔定義類型)和XML Schema來描述XML文檔的數據結構,也就是描述元素和屬性是如何聯繫在一塊兒的。微軟的.NET系統支持用XML Schema來描述XML文檔的數據結構,下例介紹如何使用XML Schema,見文件C8-1-1F.aspx。

<%@ Page Language="C#" %>

<%@ Import Namespace="System.Data" %>

<%@ Import Namespace="System.Data.SqlClient" %>

<%@ Import Namespace="System.IO" %>

 

<html>

<title>DataGrid</title>

 

<script runat=server>

DataSet ds;

public void Page_Load(Object sender, EventArgs e)

{

       string txtConn="DATABASE=Northwind;SERVER=localhost;UID=sa;PWD=;";

       string txtCommand="SELECT employeeid, firstname, lastname FROM Employees";

       SqlConnection conn = new SqlConnection(txtConn);

       SqlDataAdapter da = new SqlDataAdapter(txtCommand, conn);

      

       ds = new DataSet();

       da.Fill(ds, "MyTable");

 

       // Display the data

       grid.DataSource = ds.Tables["MyTable"];

       grid.DataBind();

       grid.Visible = true;

}

 

public void SvaeXmlWithSchema(Object sender, EventArgs e)

{

       ds.WriteXml(Server.MapPath("XmlFile1.xml"), XmlWriteMode.WriteSchema);

}

 

public void SvaeXmlNoSchema(Object sender, EventArgs e)

{

       StreamWriter sw = new StreamWriter(Server.MapPath("XmlFile2.xml"));

       sw.Write(ds.GetXml());

       sw.Close();

}

</script>

 

 

<body bgcolor="ivory" style="font-family:arial;font-size:9pt">

 

<!-- ASP.NET topbar -->

<h2>將數據庫表存爲帶XML架構和不帶XML架構XML文件</h2>

 

<form runat=server>

    <asp:linkbutton runat="server" id="SvaeXml1" text="將數據庫表存爲帶XML架構XML文件" onclick="SvaeXmlWithSchema" />

    <br>

    <asp:linkbutton runat="server" id="SvaeXml2" text="將數據庫表存爲不帶XML架構XML文件" onclick="SvaeXmlNoSchema" />

 

    <asp:DataGrid id="grid" runat="server" visible="false"

       AutoGenerateColumns="true"

       CssClass="Shadow" BackColor="white"

       CellPadding="2" CellSpacing="2" GridLines="none"

       BorderStyle="solid" BorderColor="black" BorderWidth="1"

       font-size="x-small" font-names="verdana">

 

       <AlternatingItemStyle BackColor="palegoldenrod" />

       <ItemStyle BackColor="beige" />

       <HeaderStyle ForeColor="white" BackColor="brown" Font-Bold="true" />

     </asp:DataGrid>

 

</form>

 

</body>

</html>

單擊兩個按鈕,能夠建立帶XML架構和不帶XML架構XML文件,文件名爲"XmlFile1.xml"和"XmlFile1.xml"。用瀏覽器察看這兩個XML文件,能夠看到它們的區別。如建立了有架構的XML文件,能夠修改該文件,例如,修改字段類型。用網頁文件C8-1-1G能夠從新打開帶XML架構或不帶XML架構XML文件。

<%@ Page Language="C#" %>

<%@ Import Namespace="System.Xml" %>

<%@ Import Namespace="System.Data" %>

<html>

<title>讀XML文件</title>

 

<script runat=server>

public void Page_Load(Object sender, EventArgs e)

{

       string FileNameString="d:\\asp\\bookExample\\XmlFile.xml";

       DataSet ds = new DataSet();

       ds.ReadXml(FileNameString);

       DataGrid1.DataSource=ds;

       DataGrid1.DataMember="MyTable";

       DataGrid1.DataBind();

}

</script>

 

<body>

<h2>讀帶XML架構和不帶XML架構XML文件</h2>

 

<form runat=server>

    <asp:DataGrid id="DataGrid1" runat="server"/>

</form>

 

</body>

</html>

12.8  使用Visual Studio.Net創建和顯示XML文檔

(1) 建立一個Web應用程序框架,項目名爲UseXml。

(2)    在窗體中放置控件DataGrid,其屬性Name=DataGrid1。

(3)    放工具箱的2個Button控件到窗體,修改屬性Text分別爲:存爲帶XML架構的XML文件,讀帶XML架構的XML文件。

(4)    新建一個XML文件。單擊菜單項」項目/添加新項」,彈出標題爲添加新項的窗口,在窗口中選中XML文件,文件名爲MyXMLFile.xml,單擊打開按鈕,增長一個XML文件

(5)    在文件添加以下內容:

<?xml version="1.0" encoding="GB2312" ?>

<!--這是一個註釋-->

<bookstore>

       <book 出版社="電子工業出版社">

              <書名>SQL實用全書</書名>

              <做者>Rafe Colburn</做者>

              <出版日期>2001年6月</出版日期>

              <價格>34.00</價格>

       </book>

       <book 出版社="清華大學出版社">

              <書名>C#高級編程</書名>

              <做者>Simon Robinson</做者>

              <出版日期>2002年6月</出版日期>

              <價格>128.00</價格>

       </book>

       <book 出版社="人民郵電出版社">

              <書名>ASP.NET從入門到精通</書名>

              <做者>Chris Payne</做者>

              <出版日期>2002年1月</出版日期>

              <價格>41.00</價格>

       </book>

       <book 出版社="中國青年出版社">

              <書名>精通C#與ASP.NET程序設計</書名>

              <做者>孫三才</做者>

              <出版日期>2003年6月</出版日期>

              <價格>39.00</價格>

       </book>

       <book 出版社="電子工業出版社">

              <書名>ASP.NET實用全書</書名>

              <做者>張三</做者>

              <出版日期>2004年6月</出版日期>

              <價格>55.00</價格>

       </book>

</bookstore>

(6)    單擊MyXMLFile.xml窗口下的數據,能夠看到用表格顯示的XML文件。

(7)    爲Page_Load事件函數增長語句:

         private void Page_Load(object sender, System.EventArgs e)

         {

              string FileNameString="MyXMLFile.xml";

              DataSet ds = new DataSet();

              ds.ReadXml(Server.MapPath(FileNameString));

              DataGrid1.DataSource=ds;

              DataGrid1.DataMember="book";

              DataGrid1.DataBind();

              // 在此處放置用戶代碼以初始化頁面

         }

(8)    運行,能夠看到用表格顯示的XML文件。

(9)    打開MyXMLFile.xml文件,單擊菜單項」XML/建立架構」,將建立MyXMLFile.xsd文件,打開此文件,能夠修改每一個字段的屬性。

(10)爲單擊存爲帶XML架構的XML文件按鈕事件(Click)函數增長語句(雙擊Click事件):

 

(11)爲單擊讀帶XML架構的XML文件按鈕事件(Click)函數增長語句(雙擊Click事件):

 

 

第十三章              Web服務

Micosoft.Net平臺架構中的分佈式系統主要包括兩部分:用ASP.Net技術構建服務器端動態網頁,以及Web服務(Web Service或XML Web Service)。前邊章節已詳細介紹了構建服務器端動態網頁的方法,本節將介紹Web服務的基本概念和構建方法。

13.1  Web服務的概念和用途

Web中不管是靜態網頁仍是動態網頁,數據都被嵌入到網頁中,網頁的服務對象都是人,用戶能夠很容易閱讀這些網頁。但若是一個程序使用這種方式得到數據,會是十分困難的,程序必須從網頁中把數據分離,才能加以利用。而用一個程序在Web中得到數據有時又是十分必要的,例如:一個氣象臺總站但願經過Internet網得到各個基層氣象臺的各類資料,在網上以統一的網頁對外發布。氣象臺總站但願各個基層氣象臺提供一個Internet網的服務,能根據總站的要求,自動提供相應的資料。相似的例子不少,例如一個很大的單位的總部和下屬單位之間信息系統的整合,一個綜合網站但願自動得到其它網站提供的信息等等。這種需求實際上就是Web服務。

爲實現這種功能有不少困難,各個基層氣象臺使用的系統可能徹底不一樣,即便使用相同的操做系統,也可能使用不一樣數據庫系統,數據庫中定義的字段可能不一樣,數據庫應用程序可能使用不一樣的語言編制,即便這些徹底相同,還可能數據的表示方式不相同,數據格式,數據的位數等等。爲解決這些問題,已提出了許多方案,例如:微軟的分佈式控件對象模型(DCOM)、對象管理組織(OMG)的公用對象請求代理程序體系結構(CORBA)、SUN公司的遠程方法調用(RMI)等等,但這些方法都不能很好的解決以上問題。

Micosoft.Net的Web服務爲實現這種功能提供了完整的解決方案。Web服務使用Http協議在Internet網上傳輸數據和消息,用XML擴展標記語言描述數據,用SOAP表示消息,SOAP是一個簡單的、重量輕的基於XML的協議,用於交換Web上的結構化的和模式化的信息。用Micosoft.Net的Web服務實現氣象臺總站所需功能的大概思路是這樣的,每一個基層氣象臺在本身的系統中提供一個Internet網遠程調用函數,該函數用Http協議接受用SOAP表示的調用,並把函數的返回值用XML擴展標記語言描述,用SOAP表示後,用Http協議返回給調用者。氣象臺總站只要使用Http和SOAP協議逐一調用這些Web遠程函數,就能夠得到各個基層氣象臺的資料了。因爲這些協議都是被普遍接受的協議,能被不一樣的系統所接受,也就解決了以上所提出的問題。

有以上敘述可知,Web服務不追求代碼的可移植性,而是提供一個可行的解決方案來加強數據和系統的互操做性。有許多Web服務的定義,比較簡單又比較容易理解的描述是:Web服務是一個可經過Http、SOAP和XML協議進行訪問的Web遠程函數庫。

剛纔討論的問題只是Web服務的幾個應用,還有許多其它用途,例如:。

l   應用程序集成

你能夠使用Web服務以一種集成的方式整合表面上看上去徹底不一樣的現有應用程序。例如許多公司的每一個部門都有定製的軟件,產生一系列有用可是孤立的數據和業務邏輯。爲了管理上的方便,很是有必要把這些應用程序功能集合到一塊兒。利用Web服務,就有可能把現有的應用程序中的數據和功能以Web服務方式提供給其它部門。而後能夠建立一個集成的應用程序,加強各部門之間的互操做性。

l   代碼複用

在軟件開發行業,大部分開發者都依賴代碼複用。過去開發者們爲了利用他人已經實現了的代碼,或者將代碼段複製到本身的代碼中,作一些改動以適應本身得須要,或者在服務器或我的計算機上安裝一個控件庫,讓應用程序來訪問這個庫。這將使得代碼有不少個版本,而這些版本間可能只有細微差異,卻分散在各個地方。當代碼最初的開發者決定對代碼更新一下或者改正一下錯誤,要把這些改變告訴全部使用這些代碼的開發者的時候,將是很是困難的。若是咱們把代碼放在一箇中心位置存儲,讓全部人都訪問這兒,這不是很好嗎?這樣原創者能夠在作了一些增補或者修正以後,可以當即提供給全部使用它的人。用Web服務能夠實現以上設想,遠程調用Web服務中的方法,就象調用本地函數同樣方便。

l   工做流程解決方案

有些工做是很是複雜的,例如,貨物的運輸,可能要使用多種交通工具,火車、汽車、輪船等,商業上的一筆交易,都是一個很是複雜的流程,流程的每個環節都由不一樣部門的不一樣的程序進行控制,如何創建這些控制程序之間的聯繫,是十分重要的。使用Web服務是一個很好的解決方案。經過Web服務,使各個流程控制程序創建聯繫,徹底實現自動控制和管理。

l   新的銷售方式

如今軟件的銷售方式通常是用戶把軟件買回去,安裝在本身的計算機中。有了Web服務,就能夠提供軟件的服務,按次收費。

l   由Web服務組成的自動化系統

不遠的未來,信息家電將要聯接到Internet網上,PDA、手機,甚至各類嵌入式設備也要上網,這些設備和其它設備之間經過Web服務創建聯繫也是一種可行的方案。

13.2創建Web服務

Web服務仍採用客戶/服務器模式(Cient/Server)。本節介紹在服務器端應作的工做,包括創建供客戶端調用的Web服務方法,以及爲了客戶端使用Web服務方法,提供給客戶端描述該Web服務的WSDL文檔。

13.2.1        用記事本創建Web服務

創建一個Web服務文件和創建一個普通網頁文件的步驟基本同樣,下邊是一個最簡單的Web服務文件,其它程序訪問其中的Web服務方法時,將返回參數a和b的和,具體程序代碼以下:

<%@ WebService Language="C#" class="MyClass"%>

using System;

using System.Web.Services;

public class MyClass:WebService

{     [WebMethod]

public int MyWebMethod (int a,int b)

{     return a+b;

}

//其它WebMethod 

}

在文件中,第一行的語句表示這是一個Web服務文件,使用C#語言,Web服務的類名是MyClass。因爲創建的Web服務類必須以WebService類爲基類,因此必須引入命名空間System.Web.Services,這個Web服務類必須是一個公有類。可供其它程序訪問的方法叫Web服務方法,在其頭部必須增長關鍵字[WebMethod],表示這個方法是一個Web服務方法,這個方法必須是一個公有方法。

創建文件後,以asmx爲擴展名存盤,存到網站的宿主目錄中或其任意子目錄中。使用URL定位這個Web服務文件。如今使用瀏覽器檢驗這個Web服務,若是把Web服務文件以MyAdd.asmx存到網站的宿主目錄中,在瀏覽器中URL地址欄中輸入以下地址:http://localhost/MyAdd.asmx,瀏覽器中顯示以下:

 

點擊MyWebMethod,瀏覽器中顯示以下:

 

在編輯框中輸入兩個加數分別爲10和20,而後點擊invote按鈕,在瀏覽器上顯示以下內容,這是用XML標記表示的調用Web服務方法MyWebMethod返回的結果。

<?xml  version="1.0"  encoding="utf-8" ?>

<string  xmlns="http://tempuri.org/">30</string>

13.2.2        用Visual Studio.Net創建Web服務

若是使用Visual Studio.Net創建這個Web服務文件,具體步驟以下:

(1)  打開vs.net,新建項目(asp.net web服務),在位置中鍵入http://localhost/webserver,其中webserver就是項目的名字。單擊肯定按鈕,建立項目。

(2)  打開Service1.asmx.cx文件以下:

using  System;

using  System.Collections;

using  System.ComponentModel;

using  System.Data;

using  System.Diagnostics;

using  System.Web;

using  System.Web.Services;

namespace  webserver

{

///<summary>

///Service1的摘要說明。

///</summary>

//(1)

public  class  Service1:System.Web.Services.WebService

{

public  Service1()

{

//CODEGEN:該調用是ASP.NET  Web服務設計器所必需的

InitializeComponent();
}

#region  Component  Designer  generated  code

//Web服務設計器所必需的
private  IContainer  components  =  null;

///  <summary>

///  設計器支持所需的方法  -  不要使用代碼編輯器修改

///  此方法的內容。

///  </summary>
private  void  InitializeComponent()

{

}

///<summary>

///清理全部正在使用的資源。

///</summary>

protected  override  void  Dispose(bool  disposing)

{

if(disposing&&components!=null)

{

components.Dispose();

}

base.Dispose(disposing);

}

#endregion

//WEB服務示例

//HelloWorld()示例服務返回字符串Hello  World

//若要生成,請取消註釋下列行,而後保存並生成項目

//若要測試此Web服務,請按F5鍵

//[WebMethod]

//public  string  HelloWorld()

//{

//     return  "Hello  World";

//}

}

}

(3)  下面在//(1)處加入[WebService(Namespace="http://localhost/webserver/")],這是由於SOAP是基於http協議上的,客戶端沒法知道webservice位於那個服務器上。在實際應用中,好比http://www.ourfly.com上放置這個webservice,則Namespace改成http://www.ourfly.com/webserver。

(4)  下面給這個webservice添加一個方法。微軟幫咱們寫好了一個以下,以被註解掉。

//[WebMethod]

//public  string  HelloWorld()

//{

//return  "Hello  World";

//}

添加一個本身的方法。方法名稱叫show

[WebMethod]

public  string  show(string  yourname)

{

return  「http://www.ourfly.com」+」歡迎」+yourname;

}

(5)  如今能夠測試這個Web服務,按F5運行,點擊show,輸入你的名字,而後點擊invote按鈕,在瀏覽器上顯示以下內容,這是用XML標記表示的調用Web服務方法Show返回的結果。

<?xml  version="1.0"  encoding="utf-8"  ?>

<string  xmlns="http://tempuri.org/">http://www.ourfly.com歡迎yyg</string>

(6)  打開bin目錄,Vs.net已經將proxy作好了.webserver.dll。

(7)  請注意,這裏運行只是一種測試,實際上應在其它計算機上生成一個調用此Web服務的程序,能夠是Windows應用程序,也能夠是控制檯程序,或者是ASP.Net程序,便可以是Micosoft.Net系統程序,也能夠是其它系統程序,例如Java程序,Linux程序等等,下節將介紹這方面的知識。

13.2.3        服務描述語言(WSDL)

WSDL(Web Services Description Language)中文名稱爲Web服務描述語言。

Web服務提供了一種服務,容許Internet上的計算機使用http和SOAP協議遠程調用Web服務方法。你們都知道,爲了使用一個函數,首先要看一下函數的使用說明。Web服務方法也存在一樣的問題,特別是SOAP協議,它採用XML標記語言描述Web服務中傳遞的消息,而XML標記語言是能夠定義本身的標記的,但SOAP並無提供一種通用的XML標記供Web服務使用,不一樣的Web服務中SOAP的XML標記定義可能不一樣。所以,爲了使不一樣系統調用其它系統中的Web服務,必須對調用Web服務的方法及Web服務返回的數據的格式作詳細說明即服務描述,並且這種描述也應採用被普遍接受的協議。

WSDL就是Web服務描述語言。WSDL是基於XML的,用WSDL生成一個XML文檔,能夠提供關於Web服務的操做信息,例如,抽象形式的服務接口信息、數據傳輸的具體訪問協議和格式、供客戶端使用該Web服務的細節等等。服務描述是一個使用WSDL語言的XML語法編寫的XML文檔,定義了Web服務能理解的Web服務消息格式。服務描述起一個協定的做用,用來定義一個Web服務的行爲而且指示潛在的客戶如何與之交互。因爲在micosoft.Net中提供了一些工具,能夠自動生成WSDL文檔,這裏就不介紹WSDL了,能夠經過下邊方法看到micosoft.Net自動生成的WSDL文檔,例如查看上節生成的Web服務,在瀏覽器中URL地址中輸入http://localhost/MyAdd.asmx?WSDL,瀏覽器中顯示該Web服務WSDL文檔。

13.3基於.Net的Web服務客戶端程序

Web服務客戶端程序是用來調用服務器端的Web服務方法,前邊使用瀏覽器調用Web服務方法,只能算作一種測試,經過這種測試,能夠驗證Web服務方法的正確性,發現錯誤。做爲客戶端程序,不管在何處,採用那種操做系統,但願只要知道Web服務的所在網址,就能夠調用其相關Web服務方法。Web服務客戶端程序通常應在Web網上的另外一臺計算機中,單作實驗或學習,也能夠和Web服務在同一臺計算機中。本節介紹如何實現基於.Net的Web服務客戶端程序。

13.3.1    Web服務客戶端程序代理類

Web服務客戶端程序是用http和SOAP協議來調用遠程的Web服務方法,所以,Web服務客戶端程序必須把程序的調用及其參數轉化爲SOAP協議,傳送到Web服務。但這個工做比較繁瑣,程序員但願採用象普通編程語言調用一個方法那樣調用Web方法。.NET Framework的SDK提供了一個程序WSDL.EXE,能夠自動爲Web服務客戶端程序生成一個代理程序,該代理程序的功能是,Web服務客戶端程序用通常程序語言那樣調用Web服務方法,代理程序負責轉換爲SOAP協議,發送到Web服務方法,由代理程序負責得到Web服務方法返回的數據,因爲這些數據也用SOPA協議表示,也要由代理程序轉換爲轉換爲通常程序語言可以理解的形式,傳送給Web服務客戶端程序。下邊介紹生成代理程序的具體方法。WSDL.EXE必須在控制檯界面下使用,使用的格式以下:

WSDL /l:C# /OUT:Hello.cs /protocol:soap http://LocalHost/Hello.asmx?WSDL

其中,/l參數指定編制Web服務客戶端程序使用的語言,能夠是vb、C#和Jscript,默認值爲C#;/OUT參數指定生成的代理類文件的路徑和文件名,默認值和Web服務ASMX文件同名,擴展名爲參數/l指定的語言的擴展名;參數/protocol指定調用Web服務方法使用的協議,能夠是HTTP-GET、HTTP-POST和SOAP協議;http://後邊是Web服務ASMX文件的URL。WSDL運行的結果是生成一個Web服務客戶端程序代理類的源程序。有了源程序,還要編譯源程序生成dll文件,格式以下:csc /t:librrary hello.cs。把生成的hello.dll文件存到Web服務客戶端程序項目所在目錄的子目錄bin下,這個代理類就能夠被項目的其它成代碼使用了。

13.3.2         HTTP-GET、HTTP-POST和SOAP協議

當構造一個XML Web服務時,它自動支持客戶端使用SOAP、HTTP-GET和HTTP-POST協議通信。HTTP-GET和HTTP-POST支持使用URL編碼的變量名/變量值對來傳送消息,支持這兩個協議的數據類型沒有支持SOAP協議的數據類型豐富。SOAP是一個簡單的、重量輕的基於XML的協議,用於交換Web上的結構化的和模式化的信息。SOAP的整體設計目標是使它保持儘量的簡單,而且提供最少的功能。這個協議定義了一個不包含應用程序或傳輸語義的消息框架。所以,這個協議是模塊化的而且很是利於擴展。在SOAP中,使用XML把數據傳送到XML Web服務或從XML Web服務取回消息,你能夠使用支持豐富的數據類型集。

更多SOAP規格的信息,請看W3C Web站點(http://www.w3.org/TR/soap)。

13.3.3    使用代理類的Web服務客戶端程序

(1)    控制檯應用程序

using System;

class Welcome;

{

static void Main()

{

string s;

int x,y,z;

Console.WriteLine("Please enter first number:");

s=Console.ReadLine();

x=Convert.ToInt(s);

Console.WriteLine("Please enter second number:");

s=Console.ReadLine();

y=Convert.ToInt(s);

Hollo h1=new Hollo();//代理類對象

z=h1.hello(x,y);//調用Web服務方法

Console.WriteLine("sum:={0}",z);

}

}

(2)    Windows應用程序

 

(3)    ASP.Net應用程序

 

 

13.3.4Visual Studio.Net創建Web服務客戶端程序

使用Visual Studio.Net很容易創建Web服務客戶端程序,這個客戶端程序沒必要必定和Web服務在同一臺計算機中,能夠在任意一臺Internet網中的計算機中。下邊是具體步驟:

(1)  打開Visual Studio.Net,新建windows應用程序項目,命名爲AddServiceClient,在窗體中增長一個按鈕用來調用Web服務的Web方法,三個文本框,兩個用來輸入兩個加數,另外一個用來顯示調用Web服務的Web方法後返回的結果。

(2)  創建Web服務客戶端程序通常要創建一個代理。選擇菜單項」項目」|/」添加Web引用」,在彈出的對話框中的地址欄中輸入Web服務的URL,例如Web服務所在的計算機的IP地址是202.206.96.20,Web服務的文件Service1.asmx在網站宿主目錄下的子目錄webserver中,地址爲:http://202.206.96.20/webserver/Service1.asmx。按回車鍵,出現添加Web引用對話框,如圖:單擊添加引用按鈕,在解決方案資源管理器中,能夠看到一個新的引用,以及從Web服務端發到客戶端的DISCO和WSDL文檔。在解決方案資源管理器中,還能夠看到新建立的類,這個類就是Web服務客戶端程序的代理程序,該類的用途是把Web服務客戶端程序調用Web服務方法轉換爲SOAP格式。

(3)  爲按鈕增長事件函數以下:

 

(4)  天出的對話框中再加入一個system.web.webservices的引用,在列表中有。在form1.cs裏,加入
using  System.Web.Services;
using  webserver;

而後在
private  System.Windows.Forms.Button  button1;
private  System.Windows.Forms.TextBox  textBox1;
後面,插入
private  webserver.service1  Client
創建一個service1的實例。雙擊按鈕,代碼以下:
private  void  button1_Click(object  sender,  System.EventArgs  e)
{
Client  =new  Service1();
string  name;
name=Client.show("龍捲風.NET");
textBox1.Text=name;
}
按F5,運行項目,點擊按鈕,文本框中顯示
http://www.ourfly.com歡迎龍捲風.NET


2. Asp.NET  web窗口的測試
方法與上面的如出一轍,添加引用,創建service1的實例
在此不在細說。
3.在VB中測試
這個就要相對來講複雜一些
首先在vb中創建一個」標準EXE」的項目。添加引用:Microsoft  Soap  Type  library。注意:若是沒有安裝Microsoft  Soap  Toolkit,是沒有這個類型庫的。
能夠在http://www.ourfly.com中下載。
添加一個text
Private  Sub  Form_Load()
        Text1.Text  =  add()
End  Sub

Public  Function  Add()  As  String
Dim  objSoapClient  As  New  SoapClient
        objSoapClient.ClientProperty("ServerHTTPRequest")  =  True
Call  objSoapClient.mssoapinit("http://localhost/webserver/service1.asmx?WSDL",  "Service1",  "Service1Soap")
這句也能夠
objSoapClient.mssoapinit("http://localhost/webserver/service1.asmx?WSDL")

        Add  =  objSoapClient.Show("龍捲風.NET")
End  Function

13.4創建Web服務客戶端程序通常方法

 

13.5發佈和發現Web服務

完成Web服務開發,如何發佈該Web服務,通知客戶使用,程序開發者如何發現並定位所需功能的Web服務,是這節要解決的問題。

13.5.1         Web服務目錄

和使用因特網上任何其餘的資源同樣,若是沒有某些查找方法的話,是不可可以找到一個特定的Web服務的。Web服務目錄提供了一個網址,例如:http://uddi.microsoft.org/,可讓Web服務供應者在其上發佈他們提供的Web服務的信息。這樣的目錄甚至能夠是Web服務自己,能夠編程訪問而且提供搜索結果來響應Web服務客戶端的查詢。使用一個Web服務目錄來定位一個提供Web服務的URL,這是很是必要的。

UDDI(統一描述發現和集成規範)規格定義了一個標準方法來發布和發現Web服務的信息,也就是經過UDDI發現指定Web服務的服務描述,該描述是一個使用WSDL語言的XML語法編寫的XML文檔。與UDDI關聯的XML模式定義了四個信息類型,能讓開發者使用一個發佈的Web服務。這些是:商業信息、服務信息、綁定信息和其餘用於服務的規範的信息。

做爲UDDI項目的核心控件,UDDI Business Registry(業務登記)容許Web服務開發者發佈其Web服務的信息。Web服務使用者能夠使用UDDI Business Registry來定位發現Web服務描述文件。更多信息,請看UDDI Web站點(http://uddi.microsoft.com)。

13.5.2    Web服務發現

程序設計者能夠經過如下步驟發現所需的Web服務:

(1)    首先,訪問Web服務目錄網址,例如http://uddi.microsoft.org/,查找所需Web服務,將返回一個所需Web服務URL。

(2)    按照返回URL,訪問這個網址,例如:http:// 返回Web服務URL/default.discro。.disco文件,是包含鏈接到其餘描述XML Web服務的資源的XML文件,可以編程發現一個XML Web服務。disco是一個包含與其它發現文檔、XSD模式和服務描述鏈接的XML文檔。換句話說,使用ASP.NET建立的XML Web服務自動地有提供一個產生髮現文檔的能力。

(3)    使用Web服務的WSDL創建一個Web服務客戶端程序代理類。

(4)    創建Web服務客戶端程序,使用代理類訪問Web服務方法。

 

Web服務發現是使用Web服務描述語言WSDL定位或發現一個或多個描述特定的XML Web服務的文件的操做。它讓XML Web服務客戶端得知一個XML Web服務是否存在而且到哪裏找到這個XML Web服務的描述文件。

一個發佈的.disco文件,是包含鏈接到其餘描述XML Web服務的資源的XML文件,可以編程發現一個XML Web服務。

相關文章
相關標籤/搜索