2008年11月22日 星期六

DynamicProperties動態屬性設定1-3

RunPC 109期:在.Net上保存應用程式設定(一)
(2) 如何在專案中設定非預設的動態屬性設定(自訂的動態屬性設定)
在Form1表單屬性視窗上點DynamicProperties下之Advanced出現如圖六之對話盒,其列表皆為預設的動態屬性,所以我們在屬性視窗中與該對話盒內比對找尋沒有對應的屬性來成為這節的例子,恰好我們找到屬性視窗中有Location屬性,而Dynamic Properties對話盒沒有該設定視窗位址的選項,就讓我們舉Location屬性為非預設的動態屬性的例子,步驟如下:

(圖六)


1. 於app.config內輸入:

< key="Form1.X" value="10">
< key="Form1.Y" value="10">
儲存,代表設定表單於瑩幕上的位址。
註:Location屬性內由X,Y所組成,表示表單Form1左上角點,是故該例子以保存表單的X,Y值(“Form1.X;Form1.Y)為例。

2. 於Sub New程序內模擬InitializeComponent內的作法利用AppSettingsReader類別來讀取設定檔的內容值;宣告x,y為整數,利用AppSettingsReader的GetValue方法,傳入二參數一為key值("Form1.X","Form1.Y")另一為傳回值所屬的資料型態為System.Int32再將資料型態轉為整數Integer,最後將表單的位置移至(x,y)這點上。

Dim MyConfigReader As System.Configuration.AppSettingsReader=New system.Configuration.AppSettingsReader()
Dim x,y As Integer
x = CType(MyConfigReader.GetValue("Form1.X",GetType(System.Int32)), Integer)
y = CType(MyConfigReader.GetValue("Form1.Y",GetType(System.Int32)), Integer)
Me.Location = New System.Drawing.Point(x, y)

注意:因為InitializeComponent是系統所產生的程序,不允許被修改。
3. 執行後卻發現未能如預期的將表單移置(x,y)這點上,甚至呈現的位置也都沒有改變,那是因為未將將StartPosition改為Manual,將StartPosition改為Manual再次執行,表單就可以移置正確的位置上。

這段我們模擬系統所產生的程式碼,來完成我們自訂動態屬性部分,重點是在如何利用AppSettingsReader類別來取得設定檔案的設定值,接下來讓我們思考當所開發的系統安裝後,使用者使用時我們總不可能請他手動去更改設定檔案部分,那該怎樣可以在系統執行時期時,提供如VS.Net IDE環境設定 (圖七) 般的使用者介面(UI)給使用者來設定,以防手動設定上造成不可預期的錯誤,這正是下面所要討論的。


(圖七)

(3) 如何在執行時期保留動態屬性值
此處我們會說明怎樣用.Net所提供的System.Xml名稱空間下的相關類別來維護XML(即app.config)的資料,及使用System.Reflection來找到設定檔的位置。
讓我們延續上面的例子使它可以在執行時期,保存視窗目前的位置(X,Y),待下次再次載入表單時,可以取回上次保存後的設定值,以便設定視窗位置。
1. 使用者介面:在表單上建立二個Label(Label1、Label2)、二個TextBox(txtX、txtY)來呈現目前視窗的位置、二按鈕(CmdSet、CmdSave),當按下CmdSet按鈕時來設定視窗位置;而當按下CmdSave時儲存視窗目前位置至設定檔案中, Label1、Label2的Text屬性分別設X:和Y:。
2. 在Sub New程序中之Me.Location = New System.Drawing.Point(x, y)下加入:

txtX.Text = CType(x, System.String)
txtY.Text = CType(y, System.String)

取得目前視窗啟動所在位置。
3. 於CmdSet_Click事件中加入以下程式碼,用來立即設定視窗位置。

Dim X, Y As Integer
X = CType(txtX.Text, System.Int32)
Y = CType(txtY.Text, System.Int32)
Me.Location = New System.Drawing.Point(x, y)

4. 於Form1_Move事件中加入以下程式碼,在視窗位置移動時txtX、txtY立即顯示視窗所在位置。

txtX.Text = CType(Me.Location.X, System.String)
txtY.Text = CType(Me.Location.Y, System.String)

5. 於CmdSave_Click事件中撰寫儲存目前位置至設定檔中。
利用Reflection來找設定檔的位置

Dim RA As System.Reflection.Assembly = System.Reflection.Assembly.GetExecutingAssembly
Dim StrCnfgPath As String = RA.Location & ".config"
Dim XmlDoc As New System.Xml.XmlDocument()
XmlDoc.Load(StrCnfgPath)
Dim AddNode As System.Xml.XmlNode
For Each AddNode In XmlDoc.Item("configuration").Item("appSettings")
If AddNode.Name = "add" Then
Select Case AddNode.Attributes.GetNamedItem("key").Value
Case "Form1.X"
AddNode.Attributes.GetNamedItem("value").Value = CType(Me.Location.X, System.String)
Case "Form1.Y"
AddNode.Attributes.GetNamedItem("value").Value = CType(Me.Location.Y, System.String)
End Select
End If
Next
XmlDoc.Save(StrCnfgPath)

RA.Location取得目前執行檔案的位置,而再加上".config"即前面說的佈署時設定檔的位置,而非開發時期用的app.config設定檔案。再來利用.Net操控XML的XmlDocument類別載入設定檔(StrCnfgPath),再找出每個在"configuration"下"appSettings"的節點,判斷節點的名稱是否為"add",如果是的話比較該節點的"key"值是否為"Form1.X"或"Form1.Y"(當然也可以是其它您所設定的key值),再將目前表單的位置存回它對應"key"的"value"值,最後存回設定檔中,即可完成儲存設定的動作。
註:在本例VS.Net IDE中按F5執行,儲存目前所在位置(X,Y),停下重新執行是否發現並未如預期的將設定值儲存下來呢?可別太快下結論以為這是系統Debug還是程式有謬誤喔!那是因為在開發環境中每次執行時會將app.config內容蓋回我們儲存的設定檔內,而我們在上面程式碼所抓取的StrCnfgPath卻是『執行檔名.exe.config』而非app.config設定檔案,是故只要在佈署時就不會有此問題。

結論:
這篇文章中讓我們體驗到微軟在VS.Net IDE內的一個體貼的設計(DynamicProperties),甚至讓我們不用撰寫一行程式碼就可以輕鬆設定預設的動態屬性,完成早期需要繁雜程序才可完成的動作,而自訂的動態屬性設定只要模擬學習系統產生的程式碼,即可以輕易完成設定,最後我們談到怎麼在執行時期保留動態屬性值,讓使用者可以簡易的完成保存應用程式設定值,而不至於要手動修改設定檔案。其中我們也說明了開發時期的app.config設定檔與佈署安裝的『執行檔名.exe.config』設定檔案的關係,希望該篇文章對讀者有所幫助。我們預計於下一篇文章中為各位介紹如何在.Net中更彈性的保存應用程式設定值,怎麼利用.Net上XML相關物件來操控自訂的XML設定檔案,如表(一)中選項配分中的階層關係……等,而非只是Key與Value的成對關係。

2008年11月16日 星期日

DynamicProperties動態屬性設定1-2

RunPC 109期:在.Net上保存應用程式設定(一)
二、.Net動態屬性設定方式

當各位讀者看完以上.Net之前保存應用程式各種設定的方式,是否可以意識到保存應用程式設定檔於真實系統中的重要性和在佈署系統上的方便性,可將應用程式的相關設定參數展期至系統佈署時期才做,增加系統設定上的彈性,而非一定要在開發時期將系統相關參數綁死在程式碼內。
如果您接觸過.Net一段時日,您是否發覺到XML已被廣泛的應用在.Net上,這就是我們常聽到的.Net是架構在XML的基礎上,不論是ADO.Net內的DataSet還是Web Service的Soap、WSDL甚至於此篇文章所提及的設定檔案部分亦是XML的格式,但它的副檔名為config而非正常情況下的xml,在視窗應用程式它的設定檔案預設檔名為app.config;而Web應用程式它的設定檔預設檔名為web.config,在VS.Net中建立Web應用程式專案時,web設定檔(web.config)即隨專案而被建立,而VS.Net 中建立視窗(Windows)應用程式專案時,app.config卻沒有隨專案而被建立,而要等到在屬性視窗中設定DynamicProperties的時間點上才會被建立,這是二設定檔建立時間上的差異點。
接下來讓我們開始探索.Net上的動態屬性設定,在此篇文章中將為各位介紹(1)如何設定預設的動態屬性(DynamicProperties)。(2)如何在專案中設定非預設的動態屬性設定(自訂的動態屬性設定)。(3)如何在執行時期保留動態屬性值。

讓我們舉一個動態設定資料庫連結參數的例子,如何利用.Net所提供的DynamicProperties將資料庫連結參數的設定延展至系統佈署時期,接下來就讓我們來看它的操作步驟:
(1) 設定預設的動態屬性步驟:
操作步驟前我們先假設:開發電腦上所連結的資料庫所在電腦名稱為DevPc,佈署後要連結的資料庫電腦名稱為RunPc,測試資料庫為Pubs;測試開發時期連結到DevPc這台電腦上的Pubs資料庫,而安裝佈署後連結至正式使用的電腦名稱為RunPc上的資料庫Pubs。
1. 建立新專案:選擇您所喜好的語言,VB.Net或VC#…等,在此以VB.Net為例,選Windows Application專案,將此專案命名為ProDynamicPropers。
2. 設定資料連結:利用『Ctrl+Alt+S』叫出Server Explorer,點選Connect to Database圖( ),則系統會出現資料連結對話盒,於伺服器名稱上打上DevPc(開發時期所用的測試資料庫機器)後輸入連至該資料庫的帳號、密碼,勾選允許儲存密碼,再選Pubs資料庫後按確定,到現在為止只是在VS.Net IDE上建立一個資料連結(DevPc.Pubs.dbo),再來讓我們用簡單而快速的拖曳方式來建構應用程式資料連結物件部分。
3. 建立應用程式資料連結相關物件:展開Data Connections下DevPc.Pubs.dbo資料連結,再展開其下的Tables後將authors資料表拖曳至Form1表單上,系統會自動建立SqlConnection1、SqlDataAdapter1這兩個物件,選SqlDataAdapter1物件按右鍵點Generate Dataset,出現Generate Dataset對話盒後按OK,產生DataSet11物件。
註:SqlConnection1物件是應用程式與MS SQL資料庫連結的物件;SqlDataAdapter1物件是應用程式透過SQL命令經由SqlConnection1物件對MS SQL資料庫進行操作;而DataSet11物件是一分在類似在記憶中的資料庫且是離線的,它可來自不同的資料庫或其它實體檔案;對於.Net上詳細的操控資料的方式可參考相關ADO.Net的書籍。
4. 建立資料呈現介面:利用『Ctrl+Alt+X』快速鍵叫出Toolbox,點選Windows Forms頁籤,拖曳DataGrid控制項 至Form1上,雙按Form1表單進入程式碼視窗或直接點選Solution Explorer上的View Code按鈕,於Form1_Load事件中輸入以下程式碼:
Me.SqlDataAdapter1.Fill(DataSet11, "Authors")
Me.DataGrid1.DataSource = DataSet11.Tables("Authors").DefaultView
透過SqlDataAdapter1的Fill方法,從MS SQL資料庫中取回資料放到DataSet11離線資料庫中,且命名為"Authors"的DataTable;利用DataGrid1來呈現資料而它的來源正是上面DataSet11內"Authors"的DataTable。按F5執行資料庫中的資料會於DataGrid1中呈現。
5. 觀察動態屬性設定前之連結參數設定處:於程式碼視窗中展開 ”Windows Form Designer generated code”,您可以在InitializeComponent程序中找到底下這段程式碼:
Me.SqlConnection1.ConnectionString = "data source= DevPc;initial catalog=pubs;password=1234;persist security info=T" & _
"rue;user id=sa;workstation id=DevPc;packet size=4096"
由此可知目前程式碼與資料庫連結參數是綁在一起的,每次安裝前就得改這部分的連結碼,再次編譯方可正確的佈署到正式的平台上工作。
6. 建立動態屬性:點選SqlConnection1物件,按F4叫出屬性視窗,展開DynamicProperties選項,選擇ConnectionString之ellipsis按鈕( ),勾選[Map Property to a key in configuration file]按OK,此處的Key是存在app.config的Key值除非特殊需求否則不建議修改,它的命名規則為『物件名.屬性名』。
注意:此時app.config才被建立。
7. 觀察建立完動態屬性後的差異:
a、屬性視窗中被設定為動態屬性之屬性會出現 小圖示見圖四,左邊還未建立ConnectionString的DynamicProperties而右邊已建立ConnectionString的DynamicProperties。



(圖一)VB6內設計時期內設定命令列引數

(圖二)VS.NET內設計時期設定命令列引數

(圖三)佈署時期設定引數



b、解析設定檔(app.config)物件的建立:
Dim configurationAppSettings As System.Configuration.AppSettingsReader = New System.Configuration.AppSettingsReader()
AppSettingsReader類別是.Net內建用來解析設定檔的類別,位於System.Configuration名稱空間之下,所建立解析物件configurationAppSettings之GetValue方法可用來傳入app.config 檔appSettings內add元素的key值來取得該value值。
c、連結參數的改變:
Me.SqlConnection1.ConnectionString = CType(configurationAppSettings.GetValue("SqlConnection1.ConnectionString", GetType(System.String)), String)
SqlConnection1.ConnectionString:為6、Dynamic Property對話盒中的Key也是app.config內appSettings下的其中之一Key值,而後的GetType(System.String)參數是代表"SqlConnection1.ConnectionString" 鍵值所取回的資料型態是屬字串。


8. 模擬應用程式連結測試資料庫(DevPc)改為連結至正式資料庫(RunPc):將app.config內key為SqlConnection1.ConnectionString之data source=DevPc改為data source=RunPc(前題假設資料庫名稱同為Pubs,而帳號、密碼不變),按F5執行,觀查是否已抓取正式資料庫之資料。
9. 佈署上設定檔的差異:在.Net上只要利用XCopy即可佈署所開發的系統,現在將該系統的執行檔(ProDynamicPropers.exe)與設定檔(app.config)複製到另一台電腦同一個目錄後,檢查設定檔案(app.config)的連結設定,正確無誤後執行,但卻會出現如下圖五的錯誤,那是因為系統真正參考到的設定檔案並非app.config檔案而是在bin資料夾下的ProDynamicPropers.exe.config設定檔,是故將app.config檔名改為ProDynamicPropers.exe.config即可正確運作。
註:在VS.Net IDE環境下每次執行時,會將bin資料夾內的ProDynamicPropers.exe.config的內容改成app.config的內容,而該執行檔案也是參考該資料夾下的『執行檔名.exe.config』。


(圖五)


至此我們已經完成預設的動態屬性設定操作步驟,而且在動態屬性部分還沒寫一行程式碼,完全利用VS.Net IDE自動設定的功能來完成,讀者是否體驗到用VS.Net來開發系統就是這麼簡單呢?接下來讓我們來探索非在DynamicProperties下所提供的動態屬性設定方式。

2008年11月12日 星期三

DynamicProperties動態屬性設定1-1

MyShare furl Yahoo! My Web TwitThis ');//-->

RunPC 109期:在.Net上保存應用程式設定(一)

在與各位讀者探索.Net的應用程式設定DynamicProperties(動態屬性)設定方法之前,我們先來了解一下它可能運用地方:如:資料庫的連結這是它最常被應用到的地方,各位是否和筆者早期於學校撰寫畢業專題(進銷存管理系統),用VB開發資料庫應用程式一般,將Visual Basic與MS SQL Server相關連結的部分深植於應用程式中或直接由ADODC按右鍵設屬性頁簡易設定而帶來往後安裝與維護上的惡夢,每當開發系統的資料庫由本機移植到另一台學校測試的SQL Server上時,系統與資料庫連結的部分須重寫,然後再次重新編譯原始碼,方可以安裝、佈署系統,雖然當時的筆者已知要將連結資料庫的參數設成常數,往後維護只要更改常數部分即可,但還是造成筆者在佈署上的諸多不便。後來筆者於實作中了解到動態設定屬性參數對真實開發系統的重要性,如:上面所提到的資料庫連結參數、系統環境參數的配置…等,將其配置於外部檔案,在所部佈署的機器上即使系統環境不同時只需改變外部設定檔案參數即可,而不用重新再次編譯原始碼。

一、早期動態參數設定方式概述
當然早在.Net還未出現前,我們已經可找到相關的動態應用參數設定解決方式,請參考如下:
1、 最簡單的方式是利用File System Object讀取外面某個文字檔內儲存值來當系統參數(參考:Programming in the FSO Object Model),File System Object讀取外面文字檔為非標準作法,不建議使用。
2、 早期系統開發上較常用的是讀取ini檔案的方式,可參考Using INI Files to Save Application Data - Saving Entire Sections 這篇文章,此方式會有所限制,所以建議改採用第五項作法(XML設定檔方式)。
3、 直接截取命令列引數:使用Command方法來當參數,在.Net上改用System.Environment.CommandLine方法來截取命令列引數,在此簡述它們的開發和佈署時期的應用方式;VB6的開發設定方式:選專案功能表內『專案屬性』打開專案屬性對話盒,選擇『製成』頁讖,於命令列的引數內輸入相關引數(如:Arg1,Arg2…)見圖一;VS.Net的開發設定方式:選Project功能表內Properties,出現Project Property Pages選擇Configuration Properties內的Debugging在於Start Options項目中找到Command line arguments輸入相關引數(如:Arg1,Arg2…)見圖二;佈署後的設定方式:建立該專案執行檔(如:MyApp.exe)的捷徑,再選擇捷徑內容於『捷徑』頁讖內目標項內後帶相關參數見圖三,即可用Command或System.Environment.CommandLine來截取。


(圖一)VB6內設計時期內設定命令列引數

(圖二)VS.NET內設計時期設定命令列引數

(圖三)佈署時期設定引數

4、 利用註冊檔為參數值儲存所,使用GetSetting方法取得註冊檔內資料、SaveSetting方法來儲存資料到註冊檔內、DeleteSetting方法刪除應用程式在註冊檔內的機碼。
註:一般VB6所儲存的註冊檔位置為『HKEY_CURRENT_USER\Software\VB and VBA Program Settings\』到當然若要儲存到非該位置下,則需使用到特殊API的呼叫。
5、 彈性最佳的方式,配合MSXML取得外部自訂的XML設定檔。如今該方式已成為筆者開發系統最常應用留存系統設定檔的方式,也是筆者在XML應用上最為廣泛使用。如:筆者在系統開發上的一個實際的例子,財吉寶現金卡融資審核表及其相關消費性貸款融資審核表,因業務上需求各選項配分必須隱藏且必須因應市場反應而作適當彈性調整配分,而XML恰好俱自我描述功能與樹狀結構設計,是故筆者以XML來訂定相關系統選項配分、描述與資料庫連結參數…等,請見表一。
註:此處融資審核表還有一處有趣的部分,它產生出來的融資審核表為非HTML而是動態的Word報表,且是不可以修改的喔!有興趣的讀者可參考以上的網址。


(表一)消貸系統融資審核表XML設定檔

以上五種方法為非.Net平台上的作法而此篇文章將焦點放置於.Net的應用上,在此就不加以詳細說明,讀者若有興趣了解相關主題可參考相關連結或來信與筆者討論。

MyShare furl Yahoo! My Web TwitThis ');//-->

加入書籤: MyShare HemiDemi Baidu Google Bookmarks Yahoo! My Web PChome Del.icio.us Digg technorati furludn bookmark 其他更多書籤

BOOKS:New and Upcoming