2009年8月31日 星期一

效能問題的最佳化模型(M01)

前言
一、效能問題的最佳化模型

二、效能調校的各項環結
1、正確的SQL組態-Default Setting(當瞭解各項設定意義)
2、硬體需求預估(封裝與分散)
3、商業Logic規則
4、資料Lock(資料特性)
5、正確(適當的)SQL指令
6、應用程式的開發(SQL Native Client)
7、資料庫設計
8、資料庫服務架構(Service Broker=非同步訊息佇列)

三、好的效能的基本要素
1、系統各個環節都擁有最好效能。
2、效能問題在開發中就要注意,尤其是資料庫設計,事後的修正會造成整個資料架構的異動
=>資料庫不應由前端應用程式碼直接存取資料表,而是透過View、Stored procedure、User define function來存取,以提高資料表擴充性。
=>程式開發時最好快速建立測試系統(prototype),讓使用者在測試環境中修正開發中的問題。
3、開發流程中,做壓力測試時,應高過使用者的標準,因為無法預測尖峰與離峰時間,最好一直加壓到系統無法承受,試出系統的各項邊界資訊ex:多少使用者可同時上線、最大資料容量,最小記憶體需求等。並記錄各項資料供日後參考。
4、當資料庫資料量大且商業邏輯要執行很久時,盡量讓使用者有部份回應。
====================
效能調校的定義
「太慢了」、「這系統毀了」、「它不會工作了」=>可進行效能調校
「這系統毀了」、「它不會工作了」=>備援回復、提高系統可獲得性(HA high Availability)
一、一般觀測的效能問題的現象有:
1、系統回應時間過久
2、每秒所完成的系統輸出入低於預期
3、相同環境,目前完成的工作量<先前完成的工作量 4、系統資源(ex:CPU、記憶體、硬碟或網路等)長時間處於耗量的狀態 =>調校目標主要以使用者的期望為依歸
====================
建立效能基準線(Baseline)
1、昔日系統正常運作的數據
2、調校前系統的各項數據
3、使用者希望達到的目標

一般使用者可以接受系統的回應時間是3~5秒。
使用者的期望通常來自於:
1、工作需求
2、以往系統的使用經驗
3、一些效能數據值(benchmark)
4、其它使用者使用類似功能的經驗
====================
效能調校的步驟
1、發現問題Discover the problem
=>對於問題是否有簡明的描述
=>使用者基準線與期待在哪裡
2、探究問題Explore the conditions
3、提供可能的解決方案Track down possible approaches
=>最早開始的,最晚結束
4、執行最有可能的解決方案Execute the most likely approach
=>Spend time now to save time later
5、完成收尾工作Tie up loose ends
====================
定義瓶頸
原本整個系統可以流暢地執行,但系統中若有一個環節無法處理該需求量,導致整個系統執行效率被卡住,該點就是瓶頸。
瓶頸=需求到達的速率>處理量(Throughput)

逐步縮小範圍問題
階段1:廣泛監控資料庫環境
階段2:建立模型,驗證假設
階段3:縮小效能問題到特定資料庫範圍
階段4:縮小效能問題到特定資料庫物件並隔離問題
階段5:施行解決問題

多執行緒中共用資源(M06)

多執行緒中共用資源
1、多執行緒中的共用資源必須要被保護
a、避免導致程式運算錯誤
=>多執行緒的執行環境中,執行緒輪流使用虎理器的資源做運算,當然也輪流休息。如果A執行緒休息的時間,有其他的執行緒修改A執行緒所使用的物件狀態;等A執行緒下次執行,就會產生錯誤的結果。
=>因此在多執行緒中,我們使用一些機制,保護多執行緒中共資源的狀態,這就稱之為同步化(Synchronization)

2、保護共用資源方式
a、Synchronization Lock
b、Monitor
c、Mutex
d、Semaphore
e、ReaderWriterLock
f、Interlocked
========================
Synchronization Lock(最常用)
1、確保程式碼區塊執行到完畢,不受其它執行緒打斷
a、C#:使用lock程式碼區塊
b、VB:使用SyncLock程式碼區塊
2、在方法宣告時使用Methodlmpl標籤
a、設定MethodlmplOptions.Synchronized
b、鎖定範圍為整個方法

=>保護共用資源的最簡單的方法,就是直接鎖定程式,讓程式只有一個執行緒執行,稱之為同步化鎖定(Synchronization Lock)。
=>使用時注意:鎖定愈短愈好,避免Thread排隊,多資源利用避免DeadLock

2009年8月26日 星期三

多執行緒應用程式(M06)

多執行緒應用程式

一、執行緒的基本觀念
1、虛擬的執行單元
2、可以讓程式同時進行多項工作
3、減少系統資源的浪費
4、共用資源的鎖定(Synchronization)

一般在應用程式開啟時,執行環境會自動建立一個執行緒執行程式中的功能,稱之為主執行緒(Main thread)。
每一個程式中的執行緒都是一個虛擬的執行單元,建立之後就會在程式的背景執行交付的工作。

優點
像是程式在開啟網路資源或是開啟資料連結的時候都會有一些等待的時間,多執行最大的好處利用這一些空閒時間執行其它的工作,增加系統資源的使用效率。

缺點
把程式變複雜,不容易除錯
多執行緒應用程式中需要處理共用資源鎖定(synchronization),以及避免程式死結(deadlock)
==========================
二、建立沒有回傳值、沒有參數列的執行緒
1、System.Threading命名空間
2、沒有回傳值、沒有參數列
3、建立執行緒步驟
a、建立執行緒所要呼叫的方法
b、將方式記錄在ThreadStart Delegate實體
c、建立Thread物件實體,傳入ThreadStart Delegate
d、呼叫Thread物件的Start方法,啟動執行緒
Imports System.Threading

Module Module1
Sub Main()
Console.WriteLine("MainThread:Application Start.")
Dim ts As New ThreadStart(AddressOf Work)
Dim worker As Thread = New Thread(ts)

'當背景程式時,主程式執行完,背景程式如未執行完,會直接結束,不會有結果產生
'worker.IsBackground = True

worker.Start()
Console.WriteLine("MainThread:Application End.")

End Sub
Private Sub Work()
'Thread.Sleep(1000)
Console.WriteLine("Thread{0}:" & DateTime.Now.ToLongTimeString())
End Sub
End Module
==========================
三、Thread物件常用成員
1、常用屬性
Name:取得或設定執行緒名稱
Priority:取得或設定執行緒的優先權
ThreadState:取得目前的執行緒狀態
2、常用方法
Join:將執行緒插入目前工作中
Thread.Sleep靜態方法:中止執行緒一段時間再執行

==========================
四、執行緒的生命週期



程式中建立的執行緒,實際由OS的環境執行。

一般機器只有一個CPU,因此雖可以建立多個執行緒,但不能同時執行,由系統排程之後決定先後執行順序,一般由優先權高的執行緒會先被執行。

Windows OS具有分時多工特性,因此執行緒管理較為簡單,當程式呼叫Thread物件方法就可以改變執行緒狀態。

下面是執行生命週期主要的狀態
1、Unstarted:當Thread物件被建立,但是並未進入執行狀態時,即為Unstarted狀態。

2、Running:
a、當Thread物件的start方法之後,執行緒被執行時,就進入Running狀態。
b、當Thread由WaitSleepJoin狀態或是呼叫ResetAbort方法恢復執行時,就進入Running狀態。

3、WaitSleepJoin:當程式呼叫Thread物件的Join方法、Sleep靜態方法或是Monitor.Wait方法時,都會進入WaitSleepJoin狀態,必須等到暫停的原因解除後,才會恢復執行。

4、AbortRequested:當程式呼叫Thread物件的Abort方法,執行緒就會進入AbortRequested狀態。如果沒有呼叫ResetAbort方法,則執行緒就會停止執行(Abort)。

=>執行緒的生命週期狀態,可以透過Thread物件的ThreadState屬性來取得。
=>通常執行緒狀態只與偵錯有關,不適宜使用來同步處理執行緒的活動。

==========================
五、ParameterizedThreadStart Delegate
1、ThreadStart無法代入資料到執行緒執行
改用ParameterizedThreadStart Delegate
=>.NET Framework 2.0中,增加ParameterizedThreadStart Delegate定義
2、規格
(1)沒有回傳值
(2)接收Object型別參數
3、呼叫Thread物件的Start方法時代入參數執行
Imports System.Threading

Module Module1

Private Sub Work(ByVal name As Object)
Console.WriteLine("Work with Parameter:" + name)
End Sub
Sub Main()
Dim doSomething As New ParameterizedThreadStart(AddressOf Work)
Dim worker As Thread = New Thread(doSomething)
worker.Start("John")
End Sub

End Module
==========================
六、中止執行緒執行
1、呼叫Thread物件的Abort方法
a、觸發ThreadAbortException
b、可能危及應用程式定義域中(AppDomain)的其它工作
=>當Abort方法被呼叫時,執行環境會產生ThreadAbortException,除非使用Thread.ResetAbort方法解除Abort狀態,不要執行緒會中止執行

2、建立CriticalRegion
a、使用BeginCriticalRegion及EndCriticalRegion建立關鍵區域
b、避免執行緒停止時導致的不穩定情況發生
=>.NET Framework2.0的執行緒架構中才有

Imports System.Threading
Module P12_2_StoppingThreads
Sub AbortThisThread()
Thread.BeginCriticalRegion()
Console.WriteLine("BeginCriticalRegion")
For i As Integer = 0 To 1000
Console.Write("O")
Next
Console.WriteLine("EndCriticalRegion")
Thread.EndCriticalRegion()
For i As Integer = 0 To 1000
Console.Write("1")
Next
End Sub

Sub main()
Dim newThread As New Thread(New ThreadStart(AddressOf AbortThisThread))
newThread.Start()
Thread.Sleep(1)
Console.WriteLine("abort")
newThread.Abort()
Console.WriteLine("end")
End Sub
End Module

==========================
七、執行緒執行環境(Execution Context)
1、當執行緒被建立時,預設會套用既有執行緒背景環境設定
a、安全性資訊
b、區域語系資訊
c、交易環境資訊
=>當程式建立新執行緒時,有執行緒的Execution Context的設定,像是安全性資訊、區域語系資訊及交易環境的資訊,都會傳遞到新執行緒中套用

2、ExecutionContext物件類別
a、常用方法
(1)SuppressFlow(static method):呼叫此方法可暫停將執行環境的設定傳遞給新的執行緒使用
(2)RestoreFlow(static method):呼叫此方法可恢復繼續執行環境的設定傳遞
(3)Capture(static method):複製目前執行緒的執行環境
(4)Run(static method):可以將程式執行在指定的執行環境中
(5)Undo:呼叫此方法可恢復繼續執行環境的設定傳遞
==========================
八、ThreadPool
1、更有效率的建立執行緒方式
a、系統會自動根據處理器的狀況做最佳化
b、可快速取得多個背景執行緒
=>許多應用程式建立的執行緒把很多時間花費在休眠狀態,等待事件發生;也有的執者進入休眠狀態後只負責定時甦醒,來輪詢變更更新狀態的資訊。
=>ThreadPool可將執行完的執行緒先暫存在集區中,下次程式需要執行緒執行工作時,就可以直接從集區中重覆使用執行緒,節省建立新執行緒所需要消眊的系統資源。

2、不適合情境
a、需要為個別執行緒設定優先權
b、需要為個別執行緒建立identity,讓後緒程式可以使用
c、執行長時間工作
d、用於single-threaded apartment應用程式環境中
=>因執行緒是由集區取出來使用的,因此程式對於該執行緒無法做太多設定,因而不適用在這些狀況
Module Module1
Sub Work(ByVal o As Object)
Console.WriteLine("Work with Parameter:")
End Sub

Sub Main()
Dim WCB As New WaitCallback(AddressOf Work)
If System.Threading.ThreadPool.QueueUserWorkItem(WCB) Then
Console.WriteLine("OK")
End If

End Sub
End Module
==========================
九、Timer物件類別
1、來源
a、System.Form.Form
b、System.threading=>CallBack,會以另一各Thread執行
c、System.Timers=> 事件,會以另一各Thread執行
2、用於定期觸發某特定方法執行
a、Threading.TimerCallback delegate
b、Change方法:用於調整觸發方法的間隔
c、Dispose方法:釋放Timer物件執行時所參考的外部資源
=>Timer可定間隔一段時間觸發某方法,透過Timer觸發方法參考必須要先記錄到TimerCallback Delegate物件之後,再傳到Timer物件中執行

Imports System.Threading

Module Module1

Sub Main()
Dim T1 As New Threading.Timer(New TimerCallback(AddressOf Time), Nothing, 0, 2000)
Console.Read()
End Sub
Sub Time(ByVal o As Object)
Console.WriteLine("Time:" & Date.Now)
End Sub
End Module

2009年8月24日 星期一

建立Windows Service(M07)

認識Windows服務(Service)

  • 作業系統的常駐程式
=>默默在背景執行的程式
=>電腦啟動時自動啟動
  • 例如
透過網路存取別人電腦資料時。
1、Server:提供透過網路存取服務(提供資源)
2、Workstation:提供與遠端使用者連線的用戶端服務(要求存取資源)
=>Windows服務是系統的常駐程式,在系統開機之後,不需經由使用者登入及啟動,服務就會自動啟動,並且在背景默默的執行服務程式。
=>Windows Service專案也是建置為.exe檔,但此程式並不能直接執行,而是必須先安裝到服務管理員啟動

=>Service類別屬性
  • 決定服務是否可啟用、停止、暫停與繼續
  • CanStop:預設為True
  • CanPauseAndContinue:預設為False
  • CanShutdown:預設為False
  • AutoLog:預設為True
=>Service類別事件
  • OnStart:啟用服務會執行的程式
  • OnStop:停用服務會執行的程式
程式實作
1、建立Windows Service的專案步驟如下:
a、File-->New Project-->Project types:選取Windows,在Templates:選取Windows Service

b、改寫Service類別的OnStart與OnStop程序
Imports System.IO

Public Class Service1
Dim WithEvents serviceTimer As System.Timers.Timer

Public Sub New()

' 此為 Windows Form 設計工具所需的呼叫。
InitializeComponent()

' 在 InitializeComponent() 呼叫之後加入任何初始設定。
serviceTimer = New System.Timers.Timer
serviceTimer.Interval = 60000
End Sub

Protected Overrides Sub OnStart(ByVal args() As String)
serviceTimer.Start()

End Sub

Protected Overrides Sub OnStop()
serviceTimer.Stop()

End Sub

Private Sub serviceTimer_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles serviceTimer.Elapsed
Dim cDrive As New driveinfo("C:\")
eventlog.WriteEntry("目前磁碟的剩餘空間:" & cdrive.TotalFreeSpace)
End Sub
End Class

c、加入安裝程式,並設定安裝屬性
d、建置專案
e、安裝服務
(1)使用InstallUtil.exe(適用於開發測試)
VS2005-->VS TOOL-->命令執行工具

安裝
InstallUtil 服務.exe
移除
InstallUtil 服務.exe -u
ps:將服務.exe直接拉至命令提示列就會自動帶出路徑

(2)使用安裝專案
f、從「服務管理員」啟動服務

服務管理員(SCM:Service Control Manager)(M07)

SCM:Service Control Manager

1、路徑
a、我的電腦-->管理-->服務(Window XP)
b、開始-->系統管理工具-->服務

2、啟動類型
a、自動(Automatic):服務在開機後自動啟動
b、手動(Manual):服務必須經由人為或程式啟動才會執行
c、停用(Disabled):服務不可啟動

3、狀態
a、啟動(Start):服務正在執行中
b、停止(Stop):服務尚未執行
c、暫停(Pause):服務執行中進入中止狀態
d、繼續(Resume):將中止狀態服務為繼續執行

限制應用程式定義域權限(M07)

限制應用程式定義域權限
  • 組件來源可能有安全上疑慮:限制組件的執行權限
  • Evidence:組件的安全性原則來源規則
  • Zone:組件的安全性區域(Security Zone)
=>由於應用程式可能需要載入由第三廠商所提供的組件,在組件來源不明的情況下,應用程式可能執行到惡意程式。
=>.NET Framework的程式安全存取(CAS:Code Access Security)處理原則是識別組件的來源,在確認來自於可信任的來源時,給予適當的執行權限。

程式實作

Imports System.Security
Imports System.Security.Policy


Dim hostEvidence() As Object = {New Zone(SecurityZone.Internet)}
Dim internetEvidence As New Evidence(hostEvidence, Nothing)
Dim ad As AppDomain = AppDomain.CreateDomain("newDomain")
ad.ExecuteAssembly("OtherApp.exe", internetEvidence)
AppDomain.Unload(ad)

AppDomain(應用程式定義域)(M07)

認識應用程式定義域(AppDomain)
  • 是一個邏輯上的容器
  • 可以多個執行組件在一個處理程序
  • 區隔記憶體空間及存取資源
  • 增進應用程式的可靠性及效率

=>Application Domain設定目的類似於Windows作業系統的處理程序,處理程序目的是用來隔離應用程式與應用程式之間的程式碼,避免在執行過程中受到其它用程式不穩定或安全性的影響,以提高每一個單一應用程式的穩定度和安全性。
=>Application Domain像是一個邏輯上的容器,開發者可依據組件的版本控制、安全性、可靠性等考量進行組件執行環境的隔離。
=>每一Application Domain有獨立的記憶體空間及存取資源,避免遭受其它不相干組件的不良影響,進而達到組件的可靠性和執行效能。
=>通常用在多人共享的服務類型應用程式,像是Web應用程式,每個獨立連進來的使用者,需要獨立的執行空間,避免被其它使用者不同的執行階段所影響。
=>以IIS5.0的Aspnet_wp.exe為例,假設有5個人瀏覽到ASP.NET會為每個使用者建立獨立的定義域,並將ASP.Net的Assembly執行在各別的Application Domain。

程式實例

Imports System.Security
Imports System.Security.Policy

Dim newAppDomain As AppDomain
'建立應用程式定義域
newAppDomain = AppDomain.CreateDomain("NewDomain")
'載入另一個組件
newAppDomain.ExecuteAssembly("OtherApp.exe")
Label1.Text = "組件路徑:" & newAppDomain.BaseDirectory
Label2.Text = "新的定義域名稱:" & newAppDomain.FriendlyName

Label3.Text = "取得目前應用定義域名稱:" & AppDomain.CurrentDomain.FriendlyName
'卸載應用程式定義域
AppDomain.Unload(newAppDomain)

2009年8月13日 星期四

lList介面 VS lDictionary介面(M03)

lList介面
  1. List介面代表一些按順序排列的物件所成的集合,可經由索引值存取其內含的元素。

  2. System.CollectionIList介面定義一個標準的List物件提供的方法和屬性。
  3. 包含ArrayList、Array、StringCollection都實作了IList介面。
  4. 常用方法
    • Add:新增一個項目
    • Clear:清除所有項目
    • Insert:新增一個項目到特定位置
    • IndexOf:判斷元素是否存在於List之中
    Dim lst As New ArrayList()
    lst.Add(25)
    lst.Add(62)
    lst.Add(98)
    lst.Add(32)
    lst.IndexOf(24) '不存在傳回-1
    lst.IndexOf(62) '不存在為-1;存在1
    • Contains:是否含有特定的Key,有傳回True
    • Remove:移除IList中特定的項目
    • RemoveAt:以索引值移除IList中特定的項目
    • Item[索引子]:存取IList內項目

  5. 常用屬性
    • IsReadOnly:是否唯讀
    • Item:可用數直索引存取數目
    • IsFixedSize:判斷IList的大小是否是固定的
lDictionary介面
  1. System.Collections.IDictionary介面定義一個標準的Dictionary基本的屬性和方法。
  2. HashTable、SortedList類別都實作了IDictionary介面。
  3. Dictionary是一個物件,可存放許多項目,其中的每個項目都是一對key/value配對組成的。
  4. =>Key,Value
    =>A,Tom
    =>B,John
    =>C,Mary
  5. 常用方法
    • Add:新增一個項目
    • Clear:清除所有項目
    • Insert:新增一個項目到特定位置
    • IndexOf:判斷元素是否存在於List之中
    • Contains:是否含有特定的Key,有傳回True
    • Remove:移除IList中特定的項目
    • RemoveAt:以索引值移除IList中特定的項目
    • Item[索引子]:存取IList內項目
  6. 常用屬性
    • Keys:Key所組成的集合
    • Values:value所組成的集合
    • IsReadOnly:是否唯讀
    • Item:可用數直索引存取數目
    • IsFixedSize:判斷IList的大小是否是固定的
    • Keys:所有Key值所組成的集合
    • Values:所有Value值所組成的集合

2009年8月12日 星期三

UNION VS UNIION ALL

Example: Table 1 : First,Second,Third,Fourth,FifthTable 2 : First,Second,Fifth,Sixth
Result Set:
UNION: First,Second,Third,Fourth,Fifth,Sixth (會移除重覆值)
UNION ALL: First,First,Second,Second,Third,Fourth,Fifth,Fifth,Sixth,Sixth (不會移除重覆值)

日期相關

抓取該月的最後一日
LAST_DAY(TO_DATE(:P_PERIOD,'YYYYMM'))

2009年8月8日 星期六

離線環境下的編輯作業-建立DataTable 物件

DataSet物件是SystemData命名空間中的一個物件,主要用途為提供應用程式一個於記憶體之中的資料儲存機制,其概念類似於資料庫之中的資料表。

<是否一定要將DataTable放入DataSet裡????>
  • DataSet物件裡可加入DataTable物件,並利用DataRelation物件將兩個DataTable物件關聯在一起
  • 亦可單獨使用DataTable,不涉及DataSet物件。
DataTable
-Rows
-DataRow1
-DataRow2

DataTable
-Columns
-DataColumn1
-DataColumn2
一、基本語法
1、建立DataTable物件
'宣告一個新的DataTable執行個體(於表單的全域範圍裡)
Private CustomersTable As New DataTable("Customers")
2、於DataSet加入DataTable
Private ds_Northwind As New DataSet("ds_Northwind")
Dim table_Customers As New DataTable("Customers")
ds_Northwind.Tables.Add(table_Customers)
3、於DataTable物件建立運算式資料行
  • 運算式(Expression)資料行可用來為DataTable加入額外的資料行,做為儲存現有資料行的計算結果用。
Private Sub ExpressionButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ExpressionButton.Click
'建立一個新的DataColumn並設定其名稱以及資料型態
Dim ds_Northwind1 As New ds_Northwind

Dim TotalPriceColumn As New DataColumn("TotalPrice", GetType(System.Double))
'在該欄位的Expression屬性設定指定的運算式
TotalPriceColumn.Expression = ("UnitPrice * Quantity")
ds_Northwind1.Order_Details.Columns.Add(TotalPriceColumn)

Dim da_Order_Details As New SqlDataAdapter("select * FROM dbo.[Order Details]", cn_SQL)
da_Order_Details.Fill(ds_Northwind1.Order_Details)
'將此欄位加入至DataTable之中

TableGrid.DataSource = ds_Northwind1.Order_Details

End Sub
4、於DataTable物件建立自動遞增的資料行
  • 常見於訂單資料中必須是唯一(Unique)的但實際內容值為不重要的「訂單編號」(OrderID)。
'此欄位為自動遞增行
CustomersTable.Columns("CustomerID").AutoIncrement = True
'為自動遞增行指定起始值
CustomersTable.Columns("CustomerID").AutoIncrementSeed = 1
'指定每次遞增的數值
CustomersTable.Columns("CustomerID").AutoIncrementStep = 5
5、於DataTable物件加入條件約束
'建立ForeignKeyConstraint
Dim ds_Northwind As New NorthwindDataSet
Dim ForeignKey As New ForeignKeyConstraint(ds_Northwind.Customers.Columns("CustmoerID"), ds_Northwind.Orders.Columns("CustmoerID"))
ds_Northwind.Orders.Constraints.Add(ForeignKey)
6、如何建立唯一的條件約束
Dim ds_Northwind As New NorthwindDataSet
Dim Unique As New UniqueConstraint(ds_Northwind.Customers.Columns("CustomerID"))
ds_Northwind.Customers.Constraints.Add(Unique)
7、建立DataTable物件練習
  • 畫面
  • 程式原始碼
Imports System.data
Imports System.Data.SqlClient


Public Class frm_Ex4
'宣告一個新的DataTable執行個體(於表單的全域範圍裡)
Private CustomersTable As New DataTable("Customers")

Private Sub CreateTableButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CreateTableButton.Click
'設定DataGridView以顯示資料表
TableGrid.DataSource = CustomersTable

'建立DataColumns物件並加入資料表的Columns集合之中,為資料表定義資料結構
CustomersTable.Columns.Add("CustomerID", Type.GetType("System.String"))
CustomersTable.Columns.Add("CustomerName", Type.GetType("System.String"))
CustomersTable.Columns.Add("ContactName", Type.GetType("System.String"))
CustomersTable.Columns.Add("ContactTitle", Type.GetType("System.String"))
CustomersTable.Columns.Add("Address", Type.GetType("System.String"))
CustomersTable.Columns.Add("City", Type.GetType("System.String"))
CustomersTable.Columns.Add("Region", Type.GetType("System.String"))
CustomersTable.Columns.Add("PostalCode", Type.GetType("System.String"))
CustomersTable.Columns.Add("Country", Type.GetType("System.String"))
CustomersTable.Columns.Add("Phone", Type.GetType("System.String"))
CustomersTable.Columns.Add("Fax", Type.GetType("System.String"))

'將CustomerID資料行設定為主索引鍵
Dim KeyColumns(1) As DataColumn
KeyColumns(0) = CustomersTable.Columns("CustomerID")
CustomersTable.PrimaryKey = KeyColumns


'將CustomerID以及CompanyName資料行設定為不允許空值
CustomersTable.Columns("CustomerID").AllowDBNull = False
''於DataTable物件建立自動遞增的資料行
'CustomersTable.Columns("CustomerID").AutoIncrement = True
'CustomersTable.Columns("CustomerID").AutoIncrementSeed = 1
'CustomersTable.Columns("CustomerID").AutoIncrementStep = 5

CustomersTable.Columns("CustomerName").AllowDBNull = False


End Sub

Private Sub AddRowButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles AddRowButton.Click
'建立一筆新的資料列(DataRow)
Dim CusRow As DataRow = CustomersTable.NewRow
With CusRow
.Item("CustomerID") = "ALFKI"
.Item("CustomerName") = "Alfreds Futterkiste"
.Item("ContactName") = "Maria Anders"
.Item("ContactTitle") = "Sales Representative"
.Item("Address") = "Obere Str. 57"
.Item("City") = "Berlin"
.Item("Region") = "Nothing"
.Item("PostalCode") = "12209"
.Item("Country") = "Germany"
.Item("Phone") = "030-0074321"
.Item("Fax") = "030-0076546"
End With
'將新增的資料列加入至資料表之中
CustomersTable.Rows.Add(CusRow)

End Sub
Private WithEvents cn_SQL As New SqlConnection("Data Source=PC9611107;Initial Catalog=Northwind;Integrated Security = True")
Private Sub ExpressionButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ExpressionButton.Click
'建立一個新的DataColumn並設定其名稱以及資料型態
Dim ds_Northwind1 As New ds_Northwind

Dim TotalPriceColumn As New DataColumn("TotalPrice", GetType(System.Double))
'在該欄位的Expression屬性設定指定的運算式
TotalPriceColumn.Expression = ("UnitPrice * Quantity")
ds_Northwind1.Order_Details.Columns.Add(TotalPriceColumn)

Dim da_Order_Details As New SqlDataAdapter("select * FROM dbo.[Order Details]", cn_SQL)
da_Order_Details.Fill(ds_Northwind1.Order_Details)
'將此欄位加入至DataTable之中

TableGrid.DataSource = ds_Northwind1.Order_Details
'Dim ds_Northwind As New NorthwindDataSet
'Dim Unique As New UniqueConstraint(ds_Northwind.Customers.Columns("CustomerID"))
'ds_Northwind.Customers.Constraints.Add(Unique)

End Sub
End Class

離線環境下的編輯作業-建立DataTable 物件

DataSet物件是SystemData命名空間中的一個物件,主要用途為提供應用程式一個於記憶體之中的資料儲存機制,其概念類似於資料庫之中的資料表。

<是否一定要將DataTable放入DataSet裡????>
  • DataSet物件裡可加入DataTable物件,並利用DataRelation物件將兩個DataTable物件關聯在一起
  • 亦可單獨使用DataTable,不涉及DataSet物件。
DataTable
-Rows
-DataRow1
-DataRow2

DataTable
-Columns
-DataColumn1
-DataColumn2
一、基本語法
1、建立DataTable物件
'宣告一個新的DataTable執行個體(於表單的全域範圍裡)
Private CustomersTable As New DataTable("Customers")
2、於DataSet加入DataTable
Private ds_Northwind As New DataSet("ds_Northwind")
Dim table_Customers As New DataTable("Customers")
ds_Northwind.Tables.Add(table_Customers)
3、於DataTable物件建立運算式資料行
  • 運算式(Expression)資料行可用來為DataTable加入額外的資料行,做為儲存現有資料行的計算結果用。
Private Sub ExpressionButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ExpressionButton.Click
'建立一個新的DataColumn並設定其名稱以及資料型態
Dim ds_Northwind1 As New ds_Northwind

Dim TotalPriceColumn As New DataColumn("TotalPrice", GetType(System.Double))
'在該欄位的Expression屬性設定指定的運算式
TotalPriceColumn.Expression = ("UnitPrice * Quantity")
ds_Northwind1.Order_Details.Columns.Add(TotalPriceColumn)

Dim da_Order_Details As New SqlDataAdapter("select * FROM dbo.[Order Details]", cn_SQL)
da_Order_Details.Fill(ds_Northwind1.Order_Details)
'將此欄位加入至DataTable之中

TableGrid.DataSource = ds_Northwind1.Order_Details

End Sub
4、於DataTable物件建立自動遞增的資料行
  • 常見於訂單資料中必須是唯一(Unique)的但實際內容值為不重要的「訂單編號」(OrderID)。
'此欄位為自動遞增行
CustomersTable.Columns("CustomerID").AutoIncrement = True
'為自動遞增行指定起始值
CustomersTable.Columns("CustomerID").AutoIncrementSeed = 1
'指定每次遞增的數值
CustomersTable.Columns("CustomerID").AutoIncrementStep = 5
5、於DataTable物件加入條件約束
'建立ForeignKeyConstraint
Dim ds_Northwind As New NorthwindDataSet
Dim ForeignKey As New ForeignKeyConstraint(ds_Northwind.Customers.Columns("CustmoerID"), ds_Northwind.Orders.Columns("CustmoerID"))
ds_Northwind.Orders.Constraints.Add(ForeignKey)
6、如何建立唯一的條件約束
Dim ds_Northwind As New NorthwindDataSet
Dim Unique As New UniqueConstraint(ds_Northwind.Customers.Columns("CustomerID"))
ds_Northwind.Customers.Constraints.Add(Unique)
7、建立DataTable物件練習
  • 畫面
  • 程式原始碼
Imports System.data
Imports System.Data.SqlClient


Public Class frm_Ex4
'宣告一個新的DataTable執行個體(於表單的全域範圍裡)
Private CustomersTable As New DataTable("Customers")

Private Sub CreateTableButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CreateTableButton.Click
'設定DataGridView以顯示資料表
TableGrid.DataSource = CustomersTable

'建立DataColumns物件並加入資料表的Columns集合之中,為資料表定義資料結構
CustomersTable.Columns.Add("CustomerID", Type.GetType("System.String"))
CustomersTable.Columns.Add("CustomerName", Type.GetType("System.String"))
CustomersTable.Columns.Add("ContactName", Type.GetType("System.String"))
CustomersTable.Columns.Add("ContactTitle", Type.GetType("System.String"))
CustomersTable.Columns.Add("Address", Type.GetType("System.String"))
CustomersTable.Columns.Add("City", Type.GetType("System.String"))
CustomersTable.Columns.Add("Region", Type.GetType("System.String"))
CustomersTable.Columns.Add("PostalCode", Type.GetType("System.String"))
CustomersTable.Columns.Add("Country", Type.GetType("System.String"))
CustomersTable.Columns.Add("Phone", Type.GetType("System.String"))
CustomersTable.Columns.Add("Fax", Type.GetType("System.String"))

'將CustomerID資料行設定為主索引鍵
Dim KeyColumns(1) As DataColumn
KeyColumns(0) = CustomersTable.Columns("CustomerID")
CustomersTable.PrimaryKey = KeyColumns


'將CustomerID以及CompanyName資料行設定為不允許空值
CustomersTable.Columns("CustomerID").AllowDBNull = False
''於DataTable物件建立自動遞增的資料行
'CustomersTable.Columns("CustomerID").AutoIncrement = True
'CustomersTable.Columns("CustomerID").AutoIncrementSeed = 1
'CustomersTable.Columns("CustomerID").AutoIncrementStep = 5

CustomersTable.Columns("CustomerName").AllowDBNull = False


End Sub

Private Sub AddRowButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles AddRowButton.Click
'建立一筆新的資料列(DataRow)
Dim CusRow As DataRow = CustomersTable.NewRow
With CusRow
.Item("CustomerID") = "ALFKI"
.Item("CustomerName") = "Alfreds Futterkiste"
.Item("ContactName") = "Maria Anders"
.Item("ContactTitle") = "Sales Representative"
.Item("Address") = "Obere Str. 57"
.Item("City") = "Berlin"
.Item("Region") = "Nothing"
.Item("PostalCode") = "12209"
.Item("Country") = "Germany"
.Item("Phone") = "030-0074321"
.Item("Fax") = "030-0076546"
End With
'將新增的資料列加入至資料表之中
CustomersTable.Rows.Add(CusRow)

End Sub
Private WithEvents cn_SQL As New SqlConnection("Data Source=PC9611107;Initial Catalog=Northwind;Integrated Security = True")
Private Sub ExpressionButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ExpressionButton.Click
'建立一個新的DataColumn並設定其名稱以及資料型態
Dim ds_Northwind1 As New ds_Northwind

Dim TotalPriceColumn As New DataColumn("TotalPrice", GetType(System.Double))
'在該欄位的Expression屬性設定指定的運算式
TotalPriceColumn.Expression = ("UnitPrice * Quantity")
ds_Northwind1.Order_Details.Columns.Add(TotalPriceColumn)

Dim da_Order_Details As New SqlDataAdapter("select * FROM dbo.[Order Details]", cn_SQL)
da_Order_Details.Fill(ds_Northwind1.Order_Details)
'將此欄位加入至DataTable之中

TableGrid.DataSource = ds_Northwind1.Order_Details
'Dim ds_Northwind As New NorthwindDataSet
'Dim Unique As New UniqueConstraint(ds_Northwind.Customers.Columns("CustomerID"))
'ds_Northwind.Customers.Constraints.Add(Unique)

End Sub
End Class

離線環境下的編輯作業-建立DataSet物件

DataSet物件是SystemData命名空間中的一個物件,主要用途為提供應用程式一個於記憶體之中的資料暫存機制
DataSet
-Tables
-DataTable1
-DataTable2
經由DataRelation物件來描述DataTable物件之間的關係。

一、DataSet物件
1、一般可區分為兩種不同型態的DataSet物件
  • 具型別(Typed):具型別的DataSet結構描述則是源自於.xsd檔,並包含明確的具型別集合。
  • 不 具型別(Untyped):自行建立DataTable(Untyped DataTable)物件,將DataTable加入至DataSet的Tables 集合中,手動地為DataSet建立資料結構描述(Schema)。可以職由集合的索引值來存取該DataSet中不具型別的DataTable及其 DataColumn物件。
2、Visual Studio提供了三種不同的方式建立DataSet物件
  • 於程式編輯器中撰寫程式宣告DataSet物件,建立空的DataSet物件後再另行建立DataTable物件,最後再選擇性加入DataRelation物件。
  • 選擇使用DataSet設計工具以及資料來源組態精靈(Data Source Configuration Wizard)兩者其中之一來協助建立,從選擇或建立資料連結開始逐步選取資料庫裡的資料對象,進而建立具型別的DataSet,最後再產生相關的程式碼。
  • 用滑鼠自工具箱拖曳一個DataSet物件到表單之上,再利用對應Table以及Column集合編輯為所屬的DataSet建立結構描述。
3、基本語法
  • 建立DataSet物件 Private ds_Northwind As New DataSet("ds_Northwind")
  • 建立DataTable並加入DataSet裡
Dim table_Customers As New DataTable("Customers")
table_Customers.Columns.Add("CustomerID", Type.GetType("System.Int32"))
table_Customers.Columns(0).AutoIncrement = True
table_Customers.Columns(0).Unique = True

table_Customers.Columns.Add("CustomerName", Type.GetType("System.String"))

Dim table_Orders As New DataTable("Orders")
table_Orders.Columns.Add("OrderID", Type.GetType("System.Int32"))
table_Orders.Columns(0).AutoIncrement = True
table_Orders.Columns.Add("OrderProduct", Type.GetType("System.String"))
table_Orders.Columns.Add("CustomerID", Type.GetType("System.Int32"))

ds_Northwind.Tables.Add(table_Customers)
ds_Northwind.Tables.Add(table_Orders)
  • 新增父表單資料
Dim newRow1 As DataRow = ds_Northwind.Tables("Customers").NewRow()
newRow1.Item("CustomerName") = "Jone"
ds_Northwind.Tables("Customers").Rows.Add(newRow1)

Dim newRow2 As DataRow = ds_Northwind.Tables("Customers").NewRow()
newRow2.Item("CustomerName") = "Amy"
ds_Northwind.Tables("Customers").Rows.Add(newRow2)

Dim newRow3 As DataRow = ds_Northwind.Tables("Customers").NewRow()
newRow3.Item("CustomerName") = "Jone"
ds_Northwind.Tables("Customers").Rows.Add(newRow3)
  • 新增子表單資料
Dim newRow4 As DataRow = ds_Northwind.Tables("Orders").NewRow()
newRow4.Item("OrderProduct") = "AProduct"
newRow4.Item("CustomerID") = 0
ds_Northwind.Tables("Orders").Rows.Add(newRow4)

Dim newRow5 As DataRow = ds_Northwind.Tables("Orders").NewRow()
newRow5.Item("OrderProduct") = "BProduct"
newRow5.Item("CustomerID") = 1
ds_Northwind.Tables("Orders").Rows.Add(newRow5)

Dim newRow6 As DataRow = ds_Northwind.Tables("Orders").NewRow()
newRow6.Item("OrderProduct") = "CProduct"
newRow6.Item("CustomerID") = 2
ds_Northwind.Tables("Orders").Rows.Add(newRow6)
  • 建立關聯
Dim customersOrders As New DataRelation("dr_customersOrders", table_Customers.Columns("CustomerID"), table_Orders.Columns("CustomerID"))

ds_Northwind.Relations.Add(customersOrders)
  • 將資料丟入DataGridView
DataGridView2.Columns.Clear()
DataGridView2.Rows.Clear()
For Each col As DataColumn In ds_Northwind.Tables("Customers").Columns

DataGridView2.Columns.Add(col.ColumnName, col.ColumnName)
Next

For Each row As DataRow In ds_Northwind.Tables("Customers").Rows
DataGridView2.Rows.Add(CInt(row(0)), row(1).ToString)
Next
  • 取得子資料列
ListView1.Items.Clear()
For Each Customer_Row As DataRow In ds_Northwind.Tables("Customers").Rows(e.RowIndex).GetChildRows("dr_customersOrders")
ListView1.Items.Add(Customer_Row("OrderProduct"))
Next
  • 其它
  • 合併DataSet:內容
ds_SaleHistory.Merge(ds_OldSales,True,MissingSchemaAction.Ignore)
  • 複製DataSet內容
Dim ds_Copy as new DataSet
ds_Copy = ds_Original.Copy

二、利用DataSet設計工具建立DataSet
1、首先建立一個名為DataSetDesignerExample的Windows Form
2、自「專案」功能表裡選擇執行「加入新項目」選項
3、選擇資料集樣版,並命名為NorthwindDataSet.xsd
4、自伺服器總管裡挑選Customers資料表及Order資料表,並將其拖曳至設計工具上。
完成拖曳Customers以及Orders資料表至DataSet設計工具上後的設計具看起來應接近下圖。

5、在進行後續步驟之前請先建置(Build)本專案
6、用滑鼠拖曳一個ListBox控制項至Frm_Ex1上,並命名為CustomersListbox
7、用滑鼠拖曳一個Button控制項至Frm_Ex1上
  • Name = GetCustomersButton
  • Text=Get Customers
8、用滑鼠雙擊Get Customers按鈕,並將下列程式碼加入GetCustomersButton_Click事件處理常式中
Imports System.Data
Imports System.Data.SqlClient

Private Sub GetCustomersButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles GetCustomersButton.Click
'建立一個具型別的Northwind DataSet執行個體
Dim ds_Northwind As New NorthwindDataSet

'建立一個CustomerTableAdapter的執行個體
Dim da_Customers As New NorthwindDataSetTableAdapters.CustomersTableAdapter

'呼叫Fill方法為Customers DataTable載入所有的客戶資料紀錄
da_Customers.Fill(ds_Northwind.Customers)

'將所有Customers資料表的CompanyName欄位加入ListBox之中
For Each ds_NW_customers As NorthwindDataSet.CustomersRow In ds_Northwind.Customers.Rows
CustomersListBox.Items.Add(ds_NW_customers.CompanyName)
Next

End Sub
9、執行結果



三、利用資料來源組態精靈建立具型別的DataSet
1、建立一個名為DatasourceWizardExample的Windows Form
2、至「資料」功能表裡選擇執行「加入新資料來源」選項以開啟資料來源組態精靈
3、選擇「選擇資料來源類型(Choose A Data Source Type)」畫面上的預設選項「資料庫」,並按「下一步」

4、清單控制項裡顯的是伺服器總管裡所有可用的資料連接。如下圖所示。於畫面上選取Northwind範例資料庫連接,或是建立新的資料連結,並按「下一步」。再按「是」(若出現詢問對話方塊時)以確認將資料庫連接加入至此專案。

5、選擇欲使用的資料連接後,將可選擇是否將設定儲存至應用程式組態檔(Application Configuration File)之中,在此請保留預設選項並按「下一步」。
6、展開「選擇你的資料庫物件」畫面上的「資料表」節點,並選取Customers資料表


7、按「完成」以結束此精靈的操作。此具型別的DataSet將自動被加到專案中。資料來源視窗裡將出現此資料來源,利用此資料來源將可快速開發資料繫結的表單。
8、切換至frm_Ex2的設計畫面,並自「資料」功能表裡選擇「顯示資料來源」選項。
9、自資料來源視窗中將Customers節點拖曳至frm_Ex2之上

自資料來源視窗拖曳至Customer資料表後,Visual Studio將於表單之中自動載入Customers DataTable資料的程式碼
10、執行結果


四、設定不具型別的DataSet物件
1、DataSet重要屬性
  • 自工具箱-->資料區段裡拖曳一個DataSet至Form之中
  • 自「加入資料集」對話方塊裡,選擇「不具型別資料集」並按「確定」
  • 選取DataSet1執行個體,切換到屬性視窗上的Table屬性,開啟「資料表集合編輯器(Table Collection Editor)」
  • 選取DataSet1執行個體,切換到屬性視窗上的Relations屬性,開啟「關聯性集合編輯器(Relations Collection Editor)」
  • Table下選取Columns屬性,開啟「資料行集合編輯器(Columns Collection Editor)」
2、DataGridView
3、ListView
4、相關程式碼
Public Class frm_Ex3

Private Sub FillDataSetButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles FillDataSetButton.Click
Dim newRow As DataRow = DataSet1.Tables("Categories").NewRow()
newRow.Item("CategoryName") = "Beverages"
DataSet1.Tables("Categories").Rows.Add(newRow)

Dim newRow1 As DataRow = DataSet1.Tables("Categories").NewRow()
newRow1.Item("CategoryName") = "Condiments"
DataSet1.Tables("Categories").Rows.Add(newRow1)

Dim newRow2 As DataRow = DataSet1.Tables("Categories").NewRow()
newRow2.Item("CategoryName") = "Seafood"
DataSet1.Tables("Categories").Rows.Add(newRow2)

Dim newRow3 As DataRow = DataSet1.Tables("Products").NewRow()
newRow3.Item("CategoryID") = 1
newRow3.Item("ProductName") = "Chai"
DataSet1.Tables("Products").Rows.Add(newRow3)

Dim newRow4 As DataRow = DataSet1.Tables("Products").NewRow()
newRow4.Item("CategoryID") = 2
newRow4.Item("ProductName") = "Aniseed Syrup"
DataSet1.Tables("Products").Rows.Add(newRow4)

Dim newRow5 As DataRow = DataSet1.Tables("Products").NewRow()
newRow5.Item("CategoryID") = 3
newRow5.Item("ProductName") = "Ikura"
DataSet1.Tables("Products").Rows.Add(newRow5)

Dim newRow6 As DataRow = DataSet1.Tables("Products").NewRow()
newRow6.Item("CategoryID") = 1
newRow6.Item("ProductName") = "Chang"
DataSet1.Tables("Products").Rows.Add(newRow6)

Dim newRow7 As DataRow = DataSet1.Tables("Products").NewRow()
newRow7.Item("CategoryID") = 2
newRow7.Item("ProductName") = "Chef Anton's Gumbo Mix"
DataSet1.Tables("Products").Rows.Add(newRow7)

Dim newRow8 As DataRow = DataSet1.Tables("Products").NewRow()
newRow8.Item("CategoryID") = 3
newRow8.Item("ProductName") = "Boston Crab Meat"
DataSet1.Tables("Products").Rows.Add(newRow8)
End Sub

Private Sub frm_Ex3_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
DataGridView1.DataSource = DataSet1.Tables("Categories")
DataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect
End Sub

Private Sub DataGridView1_CellDoubleClick(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView1.CellDoubleClick
'取得使用者選取的資料列的CategoryID欄位資料
Dim categoryID As Integer = CInt(DataGridView1.SelectedRows(0).Cells("CategoryID").Value.ToString())

'取得該資料的DataRow
Dim rows() As DataRow = DataSet1.Tables("Categories").Select("CategoryID =" & categoryID)
ListView1.Items.Clear()

'呼叫GetChildRows方法以取得相關聯的產品資料
For Each r As DataRow In rows(0).GetChildRows("DR_CategoriesProducts")
ListView1.Items.Add(r.Item("ProductName").ToString())
Next
End Sub
End Class

視窗表單進階主題-實作拖放功能

  • DragDrop:常見用法是透過按下滑鼠左鍵對資料進行抓取。
  • 一個字串或一個物件,:滑鼠左鍵保持按下的狀態不變(Drag),並移至有接收資料能力的控制項上,放開滑鼠(Drop)以完成資料傳送。
  • 基本上是一種事件導向的作業過程。

一、實作拖放功能時涉及來源控制項事件
  • MouseDown:發生於滑鼠左鍵按下,且游標位於某個控制貢上時,一般而言,都會在此對DoDragDrop方法做呼叫。
  • GiveFeedBack:提供使用者一個自定游標的機會。
  • QueryContinueDrag:允許拖曳來源可以決某一拖曳事件是否應該取消。
二、實作施放功能時涉及目標控制項的事件
  • DragEnter:發生於某個物件被施丈至某個控制項的範圍內時,此事件的處理常式將會接收到一個DragEventArg事件。
  • DragOver:發生於某個物件被拖丈經過某個控制項上時。此事件的處理常式將會接收到一個DragEventArgs物件。
  • DragDrop:發生於滑鼠按鍵在某個目標控制項上被釋放時。此事件的處理常式將會接收到一個DragEventArgs物件。
  • DragLeave:發生於某個物件被拖曳離開某個控制項範圍時。
PS:另外需呼叫DoDragDrop方法,及目標控制項的AllowDrop屬性必須設定為True。

三、拖曳作業的一般順序
1、透過呼叫來源控制項的DoDragDrop方法來初始化。
通常是在MouseDown的事件處理常式中完成。

Private Sub TextBox1_MouseDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles TextBox1.MouseDown
TextBox1.DoDragDrop(TextBox1.Text, DragDropEffects.Copy)
End Sub
2、GiveFeedBack及ueryContinueDrag亦發生在這個時間點。
  • GiveFeedBack:提供使用者一個自定游標的機會。
  • QueryContinueDrag:允許拖曳來源可以決某一拖曳事件是否應該取消。
3、滑鼠游標被拖曳並在目標控制項上移動。任何AllowDrop=True皆為潛的置放目標。當滑鼠游標移入某個AllowDrop=True的控制項時,將會觸發該控制項的DragEnter事件。該事件處理常式會接收到DragEventArgs物件則可用來檢驗並決定是否適合該目標控制項。若接收,則可將DragEventArgs物件的Effect屬性設成適當的內容值。
Private Sub TextBox2_DragEnter(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles TextBox2.DragEnter
If e.Data.GetData(DataFormats.Text) Then
e.Effect = DragDropEffects.Copy
Else
e.Effect = DragDropEffects.None
End If
End Sub
4、使用者於某一個有效的目標控制項上釋放滑鼠按鍵,進而觸發DragDrop事件。
DragDrop事件處理常式中的程式碼於獲取拖曳的資料後,即可於此目標控制項中做出適當的處理動作。
Private Sub TextBox2_DragDrop(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles TextBox2.DragDrop
TextBox2.Text = e.Data.GetData(DataFormats.Text).ToString
End Sub

5、DragDropEffects列舉的所有成員
使用地方:
  • TextBox1.DoDragDrop(TextBox1.Text, DragDropEffects.Copy)
  • e.Effect = DragDropEffects.Copy
成員:
  • All:資料從拖曳來源中複製、移除,並在置放目標中捲動。
  • Dopy:複製資料到目標之中。
  • Link:連結資料至目標之中。
  • Move:將資料移至目標之中。
  • None:目標不接受資料。
  • Scroll:將要開始進行捲動,或是目前有捲動作業正在目標中進行。
1、
Private Sub SourceTreeView_ItemDrag(ByVal sender As System.Object, ByVal e As System.Windows.Forms.ItemDragEventArgs) Handles SourceTreeView.ItemDrag
SourceTreeView.DoDragDrop(e.Item, DragDropEffects.Move)
End Sub
2、
Private Sub DistTreeView_DragEnter(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles DistTreeView.DragEnter
e.Effect = DragDropEffects.Move

End Sub
3、DistTreeView.AllowDrop=True
4
Private Sub DistTreeView_DragDrop(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles DistTreeView.DragDrop
If e.Data.GetDataPresent("System.Windows.Forms.TreeNode", False) Then

Dim SourceNode As TreeNode
Dim apoint As Point
Dim DictNode As TreeNode

apoint = CType(sender, TreeView).PointToClient(New Point(e.X, e.Y))
DictNode = CType(sender, TreeView).GetNodeAt(apoint)
SourceNode = CType(e.Data.GetData("System.Windows.Forms.TreeNode"), TreeNode)

DictNode.Nodes.Add(SourceNode.Clone)
DictNode.Expand()
SourceNode.Remove()

End If
End Sub

視窗表單進階主題-實作拖放功能

  • DragDrop:常見用法是透過按下滑鼠左鍵對資料進行抓取。
  • 一個字串或一個物件,:滑鼠左鍵保持按下的狀態不變(Drag),並移至有接收資料能力的控制項上,放開滑鼠(Drop)以完成資料傳送。
  • 基本上是一種事件導向的作業過程。

一、實作拖放功能時涉及來源控制項事件
  • MouseDown:發生於滑鼠左鍵按下,且游標位於某個控制貢上時,一般而言,都會在此對DoDragDrop方法做呼叫。
  • GiveFeedBack:提供使用者一個自定游標的機會。
  • QueryContinueDrag:允許拖曳來源可以決某一拖曳事件是否應該取消。
二、實作施放功能時涉及目標控制項的事件
  • DragEnter:發生於某個物件被施丈至某個控制項的範圍內時,此事件的處理常式將會接收到一個DragEventArg事件。
  • DragOver:發生於某個物件被拖丈經過某個控制項上時。此事件的處理常式將會接收到一個DragEventArgs物件。
  • DragDrop:發生於滑鼠按鍵在某個目標控制項上被釋放時。此事件的處理常式將會接收到一個DragEventArgs物件。
  • DragLeave:發生於某個物件被拖曳離開某個控制項範圍時。
PS:另外需呼叫DoDragDrop方法,及目標控制項的AllowDrop屬性必須設定為True。

三、拖曳作業的一般順序
1、透過呼叫來源控制項的DoDragDrop方法來初始化。
通常是在MouseDown的事件處理常式中完成。

Private Sub TextBox1_MouseDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles TextBox1.MouseDown
TextBox1.DoDragDrop(TextBox1.Text, DragDropEffects.Copy)
End Sub
2、GiveFeedBack及ueryContinueDrag亦發生在這個時間點。
  • GiveFeedBack:提供使用者一個自定游標的機會。
  • QueryContinueDrag:允許拖曳來源可以決某一拖曳事件是否應該取消。
3、滑鼠游標被拖曳並在目標控制項上移動。任何AllowDrop=True皆為潛的置放目標。當滑鼠游標移入某個AllowDrop=True的控制項時,將會觸發該控制項的DragEnter事件。該事件處理常式會接收到DragEventArgs物件則可用來檢驗並決定是否適合該目標控制項。若接收,則可將DragEventArgs物件的Effect屬性設成適當的內容值。
Private Sub TextBox2_DragEnter(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles TextBox2.DragEnter
If e.Data.GetData(DataFormats.Text) Then
e.Effect = DragDropEffects.Copy
Else
e.Effect = DragDropEffects.None
End If
End Sub
4、使用者於某一個有效的目標控制項上釋放滑鼠按鍵,進而觸發DragDrop事件。
DragDrop事件處理常式中的程式碼於獲取拖曳的資料後,即可於此目標控制項中做出適當的處理動作。
Private Sub TextBox2_DragDrop(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles TextBox2.DragDrop
TextBox2.Text = e.Data.GetData(DataFormats.Text).ToString
End Sub

5、DragDropEffects列舉的所有成員
使用地方:
  • TextBox1.DoDragDrop(TextBox1.Text, DragDropEffects.Copy)
  • e.Effect = DragDropEffects.Copy
成員:
  • All:資料從拖曳來源中複製、移除,並在置放目標中捲動。
  • Dopy:複製資料到目標之中。
  • Link:連結資料至目標之中。
  • Move:將資料移至目標之中。
  • None:目標不接受資料。
  • Scroll:將要開始進行捲動,或是目前有捲動作業正在目標中進行。
1、
Private Sub SourceTreeView_ItemDrag(ByVal sender As System.Object, ByVal e As System.Windows.Forms.ItemDragEventArgs) Handles SourceTreeView.ItemDrag
SourceTreeView.DoDragDrop(e.Item, DragDropEffects.Move)
End Sub
2、
Private Sub DistTreeView_DragEnter(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles DistTreeView.DragEnter
e.Effect = DragDropEffects.Move

End Sub
3、DistTreeView.AllowDrop=True
4
Private Sub DistTreeView_DragDrop(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles DistTreeView.DragDrop
If e.Data.GetDataPresent("System.Windows.Forms.TreeNode", False) Then

Dim SourceNode As TreeNode
Dim apoint As Point
Dim DictNode As TreeNode

apoint = CType(sender, TreeView).PointToClient(New Point(e.X, e.Y))
DictNode = CType(sender, TreeView).GetNodeAt(apoint)
SourceNode = CType(e.Data.GetData("System.Windows.Forms.TreeNode"), TreeNode)

DictNode.Nodes.Add(SourceNode.Clone)
DictNode.Expand()
SourceNode.Remove()

End If
End Sub

視窗表單進階主題-實作MDI表單

MDI應用程式是一種具有管理單一父表單下所有子表單的應用程式
一、建立一個MID父表單
1、建立一個新的表單應用程式
2、將設定該表單設定為父表單(MainForm)

IsMdiContainer = True
3、自工具箱拉一個MenuStrip進主表單
<=在MenuStrip設定File和New,其它可以先略過


二、建立一個MID子表單
1、建立一個新的表單應用程式(ChildForm)

2、在父表單(MainForm)的MenuStrip1的File->New中,雙點兩下滑鼠
程式設定

Private Sub NewToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles NewToolStripMenuItem.Click
Dim aChild As New frm_Ex3_2
'將MdiParent屬性設定成父表單
aChild.MdiParent = Me
aChild.Show()
End Sub


三、正在使用中的MDI子表單(MainForm)
1、ActiveMdiChild:取得正在使用中的MDI子表單
Dim ActiveForm As frm_Ex3_2 = Me.ActiveMdiChild
2、修改正在使用中MDI子表單
Dim ActiveForm As frm_Ex3_2 = Me.ActiveMdiChild
If ActiveForm Is Nothing = False Then
'在正在使用表單中要做的程式
ActiveForm.TextBox1.Text = "This is a Test"
End If
End Sub
3、對MDI表單進行排列
父表單可透過LayoutMdi(MdiLayout.列舉屬性)進行設定
Me.LayoutMdi(MdiLayout.Cascade)
Me.LayoutMdi(MdiLayout.TileHorizontal)
Me.LayoutMdi(MdiLayout.TileVertical)

視窗表單進階主題-全球化及當地語系化

一、文化特性:是以代表目前語言的Cultrue code做為表示方式
Cultrue code可以用表示語言及地區
ex:
en:英文
en-CA:英文-加拿大地區
可以用來指定Character Set
ex:
uz-UZ-Cyrl:分別表示英文、烏茲別克文和斯拉夫文

二、建立當地化語系表單
1、決定是否該表單被當地語系化
  • Form1.Localizable = true
2、選定適當語言
  • Form1.Language=Default:會針對表單上所有的UI屬性或控制項進行編緝,並自動建立Resource File(表單名稱.resx)
  • Form1.Language=特定語言:會針對此語言建立適當的Resource File(表單名稱.Cultrue code.resx)
3、針對表單上所有的UI屬性或控制項進行編緝Resource File
4、根據CurrentThread.CurrentUICulture的設定來管理資源檔的讀取作業

三、更改目前文化特性
Imports System.Threading.Thread
Imports System.Globalization

1、CurrentThread.CurrentCulture:用來格式化 資料的文化特性
2、CurrentThread.CurrentUICulture:用來決定執行階段載入當地語系化的表單(Localized Form)

ex1:
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
CurrentThread.CurrentCulture = New System.Globalization.CultureInfo("zh-TW")
CurrentThread.CurrentUICulture = New System.Globalization.CultureInfo("zh-TW")
frm_Ex2_2.Show()
End Sub
ex2:由控制台的地區語系設定
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
Dim ci As New CultureInfo(CultureInfo.CurrentCulture.Name)
CurrentThread.CurrentCulture = ci
CurrentThread.CurrentUICulture = ci
Form2.Show()
End Sub
四、其它
利用RightToLeft= true以實現控制項由右至左的功能
RightToLeft= true和RightToLeftLayout=true以對整個表單的項制項配置進行反轉

2009年8月4日 星期二

日期字串錯誤

當我傳入980807進PROC時,造成







原始錯誤程式
CREATE OR REPLACE PROCEDURE Proc_Media(P_REM_DATE IN CHAR)
AS
V_DATE CHAR(6) :='000000';
BEGIN
V_DATE:=P_REM_DATE;
END;
但是改成直接給值又不會錯誤
CREATE OR REPLACE PROCEDURE Proc_Media(P_REM_DATE IN CHAR)
AS
V_DATE CHAR(6) :='980806';
BEGIN
V_DATE:=P_REM_DATE;
END;
但覺得這樣實在太笨了,試用NUMBER,居然成功了,真是「小小智慧,大大學問」。
CREATE OR REPLACE PROCEDURE Proc_Media(P_REM_DATE IN NUMBER)
AS
V_DATE NUMBER;
BEGIN
V_DATE:=P_REM_DATE;
END;

使用ArrayList集合(M03)

使用ArrayList集合

1、定義在System.Collections命名空間,實作IList介面

2、使用循序的方式儲存項目,可使用數值索引存取其中的項目
=>Index ,元素
=>1 ,Tim
=>2 ,John
=>3 ,Mary

3、 可以動態地增加ArrayList中的項目

4、常用屬性
Count:可得知項目數目
Capacity:可得知系統預先配置來存放的空間,預設為16

5、 常用方法
Add:新增項目到ArrayList
Dim i As Integer
Dim lst As New ArrayList()
For i = 0 To 14
lst.Add(i)
Next i
Insert:新增項目到特定位置。
Dim lst As New ArrayList()
lst.Insert(0,”Hello Vivid”)
Contains:判斷ArrayList中是曾咆含某個特定的值。
IndexOf:可得知某個項目在ArrayList的索引值。
Sort:利用QuickSort演算法來排序ArrayList中的項目。
Dim lst As New ArrayList()
lst.Sort()
Remove:用來移排ArrayList中的項目。
RemoveAt:可移除特定索引值的項目。
Clear:清除所有項目
TrimToSize:將Capacity設定可容納ArrayList項目的最小容量。

6、 程式實例
 
'建立ArrayList實體
Dim lst As New ArrayList()
'ArrayList常用的屬性和方法
lst.Add(25)
lst.Add(62)
lst.Add(98)
lst.Add(32)
For Each i As String In lst
Console.WriteLine("排序前: {0}", i)
Next i
lst.Sort()
For Each i As String In lst
Console.WriteLine("排序後: {0}", i)
Next i
Console.Read()

使用ArrayList的考量

  • 適用於重態新增項目的物件存取上,特別是新增、刪除集合項目很頻繁時。
  • 如ArrayList項目不再變動的情況下,呼叫TrimToSize方法,固定它的大小,這樣可以最佳化記憶體的使用,如果已呼叫TrimToSize固定大小,後續又持續新增項目到其中,會造成效能變差,因為ArrayList需動態增加大小。