2009年2月12日 星期四

Ajax UpdatePannel注意事項

在 ASP.NET 2.0 預設實現 AJAX 有二種方式,一種是 CallBack 機制,另一種是 ASP.NET AJAX 的 UpdatePanel。只要是在 UpdatePanel 中的控制項,它需要在執行 AJAX 非同步更新時維護所有子控制項的狀態,所以需傳遞更多的資訊。如果沒有傳輸量的問題,UpdatePanel 無疑是實現 AJAX 的完美機制。[參考ASP.NET魔法學苑]。因為它讓畫面看起來不會Full PostBack,讓操作者感覺互動效果與使用一般應用程式相同。但是如果你在aspx頁面寫了JavaScript code要讓畫面onLoad時觸發執行,不論你是寫在body標籤的onLoad屬性或者寫成這樣:

<html>
<head>
<script type="text/javascript">
function alwaysDo( ) {
alert("hello!");
}

alwaysDo( );
</script>
</head>

<body>
.......
</body>
</html>

都只會讓alwaysDo()在第一次載入網頁時才會執行
之後的互動都不會觸發!
理由很簡單,因為畫面無Full PostBack所以瀏覽器始終存在第一次進來時的內容(HTML source code)
那如果這樣做呢?

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Me.ClientScript.RegisterStartupScript(GetType(Page), "", "alert('hello!');", True)
End Sub

看起來好像可以
因為RegisterStartupScript()就是在頁面註冊一段"當頁面載入後可立即執行的Script"
不過,遇到UpdatePannel還是沒輒
實際上,不論是RegisterStartupScript()或其他ClientScriptManager的Shared Method設計用意
是希望讓開發人員在後端"動態"加入Script到頁面中
當畫面載入瀏覽器後,我們用[檢視原始碼]的功能都可以看到被我們註冊的Script
但是,遇到UpdatePannel,因為頁面根本沒刷新
它回到後端後只是利用Ajax的CallBack技巧把要更改的內容置換掉
(雖然看起來畫面有變,實際上它的原始碼根本沒變,與第一次進來時相同!)
除非拿掉UpdatePannel,這樣頁面每次都可以"徹底"刷新,Script才有機會執行!
幸好,微軟發現這個問題了
在.Net Framework 2.0之後
只要有用到UpdatePannel的畫面
請用ScriptManager取代ClientScriptManager,例如:

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
ScriptManager.RegisterStartupScript(Me.Page,GetType(Page), "", "alert('hello!');", True)
End Sub

2009年1月13日 星期二

指定網頁資源的路徑

如果要指定畫面中控制項的href或src屬性
有兩種方式:
 (1)絕對位置
就是完整URL
例如:目前畫面路徑為http://localhost/web1/forms/1.aspx
如果在1.aspx裡有一張圖放在http://localhost/web1/forms/form_img/a.jpg
則路徑指定為src="http://localhost/web1/forms/form_img/a.jpg"

(2)相對位置
也就是相對於"目前畫面"的位置。
所以上一個例子來說
如果以相對位置來表示
因為a.jpg位在與1.aspx相同目錄內的form_img子目錄
所以路徑指定為src="form_img/a.jpg"

那如果圖放在http://localhost/web1/web_img/a.jpg
即1.aspx的上層目錄內的web_img子目錄
則路徑指定為src="../web_img/a.jpg"
其中".."表示[上一層]目錄

理論上絕對路徑肯定不會出錯,但是它太長了
相對路徑好像比較簡單
不過當畫面有層層目錄
或者有用到user control
那問題就很煩了
Asp.Net提供一種指定根目錄的方式 "~/"
例如: src="~/forms/form_img/a.jpg"
表示存在網站根目錄下的[forms]資料夾,裡面的[form_img]資料夾,裡面的a.jpg檔
看起來用這個只是少打一點字
其實不然,
因為如果我們把1.aspx搬到其他目錄中(這個我們常做,尤其專案越做越大,目錄結構越建越多層)
我們不用去改src的路徑了(前提是img沒有被搬動)
用這個方式有個限制
就是只有後端程式碼或者server端的控制項才可以用!
所以如果是html元件就不行
然後asp.net會負責把"~/"出現的地方在轉成html code時加上網站的根目錄(請自己try)
另外,如果User control中要link css or javascript 檔
看到一篇還不錯的作法


<link type="text/css" rel="Stylesheet" href='<%=ResolveUrl("~/UserControl/css/top.css")%>'/>
<script type="text/javascript" language="javascript" src='<%=ResolveUrl("~/UserControl/js/check.js")%>'></script>

2009年1月12日 星期一

巢狀select

如果要對一組已經select出來的結果做select動作
記得要把前一個select結果先加上別名(alias)
語法:

Select col_1,col_2,.. From
(Select col_1,col_2,... From table_1 [Where Expression])[As] table_temp

情況:已知table tb_coil_log有兩個欄位coil_date與coil_id
想要找出coil_date比coil_id='1234'的coil小的"前五筆(遞減排序前五筆)"中"最小coil_date"
分兩個步驟:

(1)先找出coil_id='1234'的coil_date
Declare @temp_coil_date As datetime;
Select @temp_coil_date=(Select coil_date From table_1 Where coil_id='1234');
(2)利用@temp_coil_date變數組合槽狀select
Select min(coil_date) From
(Select Top 5 coil_id,coil_date From table_1 Where coil_date<@temp_coil_date Order By coil_date Desc) temp_table


步驟(1)用到T-Sql宣告區域變數的語法
以及填入變數
也可以寫
Set @temp_coil_date=(.....);

本機以外電腦使用Webservice,以及調用Webservice

WebService調用與Server端設定

Client:
一般開發好的Webservice開放給其他人使用,也就是本機以外的人使用,可以直接加入Web參考並搜尋到相關的Webservice後即可使用,不管是Webform或是Winform都可以用此方式使用.

若使用Ajax並且要在前端調用Webservice則必須在ScriptManager中加入








Server:
而開發端,也就是放置Webservice的主機,必須將Webservice放置在網站下或是將目錄設定為一個網站,並將IIS設定中的匿名登入的權限打開,其他人才有權限使用Webservice.

另外,用IE直接進入Webservice頁面時,會有所謂的Webservice測試頁,在本機中可完全調用其功能,但是若是本機以外的電腦進入Webservice測試頁時,執行功能時會顯示只有本基電腦可使用的訊息,此時只要在Web.config中的system.web中加入下述程式碼,即可進入Webservice測試頁並完整使用其功能.


......
......






......
......

2008年12月30日 星期二

static vs. shared in VB.Net

在C++中stitic修飾詞有兩個主要功能

1)在fuction中修飾區域變數,讓這個變數的value不會在離開function後就從記憶體中消失
也就是可以保留前一次function留下的"痕跡"
2)在class定義中修飾class member,讓這個member由該class的所有instance共用

但是在VB.Net這兩個功能被拆成兩個修飾詞,分別是"Static"與"Shared"
以下簡述它的特性
Static:
MSDN說明:Normally, a local variable in a procedure ceases to exist as soon as the procedure stops. A static variable continues to exist and retains its most recent value. The next time your code calls the procedure, the variable is not reinitialized, and it still holds the latest value that you assigned to it. A static variable continues to exist for the lifetime of the class or module that it is defined in.
規則:
1.Static只能修飾Local Variable(函式內的變數)
2.不能修飾Struct的成員函式
3.不能與ReadOnly, Shadows, Shared同時使用
舉例:
Function updateSales(ByVal thisSale As Decimal) As Decimal
Static totalSales As Decimal = 0
totalSales += thisSale
Return totalSales
End Function

因為Satic所以只有第一次進來function才會初始化
所以totalSales不會被歸零
Shared:
MSDN說明:Sharing a member of a class or structure makes it available to every instance, rather than nonshared, where each instance keeps its own copy. This is useful, for example, if the value of a variable applies to the entire application. If you declare that variable to be Shared, then all instances access the same storage location, and if one instance changes the variable's value, all instances access the updated value.
Sharing does not alter the access level of a member. For example, a class member can be shared and private (accessible only from within the class), or nonshared and public.

規則:

1.Shared只能修飾Struct or Class的member(方法或變數)
2.不能與 Overrides, Overridable, NotOverridable, MustOverride, Static 同時使用
3.建議以Struct或Class名稱操作Shared變數,如:Class1.SharedVal1 += 3
(如果用instance操作也可以,不過會有warnning! 這個與C++不同)
4.Shared variable只會存有一份,不管物件有多少個,而Shared function的local variable也是!
(也就是Shared function的local variable隱含的是Shared)
5.不能修飾module與interface的成員、Constant變數,但是他們仍是Shared
6.Shared函式不能使用non-shared變數,只能用shared變數。
但是nonshared函式卻可以使用non-shared、shared變數
(因為non-shared變數是每個instance都有一份專屬的,Shared函式根本不知道你要使用誰的!)

舉例:

Sub main()
shareTotal.total = 10
' The preceding line is the preferred way to access total.
Dim instanceVar As New shareTotal
instanceVar.total += 100
' The preceding line generates a compiler warning message and
' accesses total through class shareTotal instead of through
' the variable instanceVar. This works as expected and adds
' 100 to total.
returnClass().total += 1000
' The preceding line generates a compiler warning message and
' accesses total through class shareTotal instead of calling
' returnClass(). This adds 1000 to total but does not work as
' expected, because the MsgBox in returnClass() does not run.
MsgBox("Value of total is " & CStr(shareTotal.total))
End Sub
Public Function returnClass() As shareTotal
MsgBox("Function returnClass() called")
Return New shareTotal
End Function
Public Class shareTotal
Public Shared total As Integer
End Class

注意:即使returnClass()會回傳shareTotal的物件
但是實際上complier遇到這類的shared操作手法
會直接用shareTotal.total+=1000來解讀
也就是他根本不會進去returnClass()!!!!

2008年12月22日 星期一

前端Script呼叫後端事件處理函式

__doPostBack(TargetObjID,EventArgs)是Asp.net轉成html code會自動加進來的script function
目的在於驅動後端處理函式動作
例如
__doPostBack("Btn1","");

就會馬上執行Btn1.Click的事件處理函式
事實上,Asp.Net元件幾乎都是利用這種方式postBack
我們可以這樣做:
拉一個DropDownList到畫面,
然後把AutoPostBack打開
執行網頁後再看看它的原始碼:


<form name="form1" method="post" action="testpage.aspx" id="form1">
<div>
<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />
<input type="hidden" name="__LASTFOCUS" id="__LASTFOCUS" value="" />
</div>
<script type="text/javascript">
//<![CDATA[
var theForm = document.forms['form1'];
if (!theForm) {
theForm = document.form1;
}

function __doPostBack(eventTarget, eventArgument) {
if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
theForm.__EVENTTARGET.value = eventTarget;
theForm.__EVENTARGUMENT.value = eventArgument;
theForm.submit();
}
}
//]]>
</script>
<select name="DropDownList1" onchange="javascript:setTimeout('__doPostBack(\'DropDownList1\',\'\')', 0)" id="DropDownList1"></select>
</form>

提醒一下:doPostBack前面的底線是"兩條",只打一條會出錯的!
還有,如果兩個參數都是空字串""
那PostBack回去就只會做Page_Load()

Button's onClinetClick and onClick attribute

有時候我們需要在Button按下後先彈出一個對話框
詢問user是否確定要執行這個動作
如果user選擇"取消"則回到畫面什麼是也不做
在Asp.Net的Button裡有另外一個attribute===>onClientClick
這個可以指定Script function提供送出表單前的先行作業
例如:


.....


之前一直被一個問題困擾
那就是onClientClick="return false;"可以擋掉畫面postback
為什麼onClientClick="Validate()"
然後function Validate()中只有return false一行卻失敗!!
現在終於曉得了
因為onClientClick="Validate()"
而Validate()又return false時,等於OnClientClick="false"不等於OnClientClick="return false"