2009年12月15日 星期二

透過 jQuery 實現 可 縮合/展開 的資料表



ludo 寫了一個 jQuery 的外掛元件 treeTable (http://plugins.jquery.com/project/treeTable),可以很容易的將 table 以縮合/展開的樣式來呈現。上圖即是我想要呈現的結果。關於這外掛元件的詳細說明,請參考 ludo 的線上文件(http://ludo.cubicphuse.nl/jquery-plugins/treeTable/doc/index.html)。

在 treeTable 的定義裡, Table 裡面的每一個 <TR> 都必須要有一個唯一的 ID。如果某個 <TR> 他有個父親,則只需要在這個 <TR> 的 class 屬性加上以"child-of-"字首開頭,並接續著父親 ID 的屬性名稱,就可以將這個 <TR> 視為是某一個 <TR> 的兒子。

舉例來說,
<TR ID="Father"><TD>爸爸</TD></TR>
<TR ID="Son" class="child-of-Father"><TD>兒子</TD></TR>
只需在 ID="Son" 的 <TR> 中,加上 class="child-of-Father" ,就可以完成父子關係的描述。

最後,只需要使用 .treeTable() 就可以將縮合/展開的效果呈現出來。
假如我的 Table ID 是 treeTable ,則呈現縮合/展開的語法如下:
$("#treeTable").treeTable();


以下是實際將 treeTable 元件下載,整合到 .Net 專案的步驟:

0.下載 treeTable(v2.2.3) :
    http://plugins.jquery.com/files/treeTable-2.2.3.zip
1.解開 treeTable 壓縮檔
2.將 /treeTable/doc/javascripts 資料夾複製到自己專案的 /javascripts 下
3.將 /treeTable/doc/stylesheets 資料夾複製到自己專案的 /stylesheets 下
4.將 /treeTable/doc/images 資料夾複製到自己專案的 /images 下
5.將 /treeTable/src/javascripts 資料夾複製到自己專案的 /javascripts 下
6.將 /treeTable/src/stylesheets 資料夾複製到自己專案的 /javascripts 下
7.將 /treeTable/src/images 資料夾複製到自己專案的 /images 下
8.修改 /stylesheets/master.css ,將 body 的 font-family 改成
font-family: Verdana, Arial, Helvetica, sans-serif; (自己覺得預設的字型醜醜ㄉ)
9.在 <head> 裡定義好所引用的 .css 與 .js 。在這裡要特別強調,不要忘了將 master.css
引用進來,否則會無法正確顯示。


<head runat="server">
    <title>treeTable Demo</title>
    <link href="stylesheets/master.css" rel="stylesheet" type="text/css" />
    <script language="javascript" src="javascripts/jquery.js" type="text/javascript"></script>
    <script language="javascript" src="javascripts/jquery.treeTable.js" type="text/javascript"></script>
    <link href="stylesheets/jquery.treeTable.css" rel="stylesheet" type="text/css" />

    <script  type="text/javascript">
    $(function(){
        $("#treeTable").treeTable();       
    })
    </script>    
</head>

10.將測試的 Table 放到 <body> 裡:


<body>
<table id="treeTable" >
    <thead>
    <th>office</th><th>帳號</th><th>中文姓名</th>
    </thead>
    <tbody>
    <tr id="p1" ><td>3F</td><td></td><td></td></tr>
    <tr id="c1" class="child-of-p1"><td>3F</td><td>paladin</td><td>李志堅</td></tr>
    <tr id="c2" class="child-of-p1"><td>3F</td><td>hugo</td><td>馮世華</td></tr>
    <tr id="p2"><td>5F</td><td></td><td></td></tr>
    <tr id="c3" class="child-of-p2"><td>5F</td><td>panda</td><td>許世宗</td></tr>
    <tr id="c4" class="child-of-p2"><td>5F</td><td>polly</td><td>陳珮茹</td></tr>
    </tbody>
</table>
</body>

將 XML 資料轉到 DataTable

using System.Xml;

來源 xml :

string oriXML = @"<?xml version='1.0' encoding='UTF-8'?>
<people>
<user office='3F' />
<user office='3F' name='paladin' cname='李志堅' />
<user office='3F' name='hugo' cname='馮世華' />
<user office='5F' />
<user office='5F' name='panda' cname='許世宗' />
<user office='5F' name='polly' cname='陳珮茹' />
</people>";

主要程式:

protected void Page_Load(object sender, EventArgs e)
    {
        BindGV();
    }

    private void BindGV()
    {
        XmlDocument doc = new XmlDocument();

        //將 xml 讀到 XmlDocument
        doc.LoadXml(oriXML);

        //透過 XmlReader 將 XmlDocument 內容取出
        XmlReader XR = XmlReader.Create(new System.IO.StringReader(doc.OuterXml));

        DataSet ds = new DataSet();
        //指定DataSet 的來源是透過  ReadXml 方式取得
        ds.ReadXml(XR);

        //取出 DataSet 裡的  DataTable  , 這行不執行也可以,只要將 gv.DataSource 設為 ds
        DataTable dt = ds.Tables[0];
        gv.DataSource = dt;

        //重新繫結網頁上所放置的 GridView
        gv.DataBind();
    }

程式執行結果如下:

程式參考:
http://www.dotblogs.com.tw/tworhouse/archive/2009/11/18/12044.aspx
http://gemmarecord.blogspot.com/2008/12/datatsetxml.html (gemma 這篇更精簡些)

2009年12月11日 星期五

思考即能量



在湛若水先生所寫的「內經呼吸養生法」一書中提到「天地萬物皆為陰陽組成」,以一個人為例,這個人的體內就會同時有陰的能量與陽的能量存在。那麼人體裡面到底是陰比較多,還是陽比較多呢?這就是問己的功夫,是由你自己來決定的。「思考即能量」,您對一件事情的反應,如果是正面的,即是替自己注入陽性的能量,相反地,如果你選擇的反應是負面的,則是為自己注入陰性的能量。

不論是陽性的能量亦或陰性的能量,經過長期地累積,當其強度超過某個臨界點後,就會由原先陰陽平衡的狀態朝向兩極而發展。因此,每個人自身的正氣或邪氣都是自己創造出來的。換句話說,所謂的正氣,就是一個人品行端正所培養出來的陽性磁場;邪氣則是一個人長期怨恨、憂傷、恐懼或長期為病所苦而產生的陰性磁場。

人在安靜的時候,比較能夠累積能量,至於是累積陽性的能量,還是陰性的能量,則會形成不同的人格特質。孔夫子勸人「慎獨」,孟子、王陽明提倡「良知」,他們的目的都是在提醒世人:心念所產生的陽性能量與陰性能量可以左右我們的身心健康。正如佛家所言:要在動心起念處下功夫。

2009年12月2日 星期三

T-SQL 剔除重複資料

去除重複資料,在資料庫的查詢語法裡,算是很常見的一種需求,用膝蓋想,Distinct 這名詞就浮出來了。然而,T-SQL 沒辦法讓你指針對某個欄位去作 Distinct ,舉例說,如果你有三個欄位,則 T-SQL 的 Distinct 就會針對這三個欄位一起去作判斷,你不能限定他針對某一個或某幾個欄位來判斷。如果遇到這種情況時,我的膝蓋就想不出直接的方法了。

我用一段程式來說明:

create table #tmp 
( t_id int IDENTITY(1,1) NOT NULL,
t_name nvarchar(50),
t_login_date nvarchar(8))

insert into #tmp (t_name,t_login_date) values ('paladin','20091201')
insert into #tmp (t_name,t_login_date) values ('paladin','20091201')
insert into #tmp (t_name,t_login_date) values ('paladin','20091205')
insert into #tmp (t_name,t_login_date) values ('hugo','20091001')
insert into #tmp (t_name,t_login_date) values ('hugo','20091001')
insert into #tmp (t_name,t_login_date) values ('hugo','20091021')

我建立了一個暫存表 #tmp , 有三個欄位 t_id , t_name, t_login_date
同時塞了6筆預設值給他。

今天我希望查詢結果能夠包含這三個欄位的資訊,但如果 t_name, t_login_date 有重複時,只要保留一筆就好。

遇到這情況時,最簡潔的方式,就是使用 group by 來完成。我們可以把 t_name, t_login_date 當成 group by 的選項,這樣挑選後的結果,就不會有 t_name 與 t_login_date 重複現象發生。但為了要能夠讓 t_id 欄位資訊也能夠保留,剛好目前也還欠 group by 一個交待,就是使用 group by 時要包含一個彙總函數 ,所以可以用 max( t_id ) 或 min( t_id ) 來使用,而查詢語法如下:

select max(t_id) t_id,t_name,t_login_date from #tmp
group by t_name,t_login_date

因為彙總函數結果欄位的欄位名稱會被視為[沒有資料行的名稱],所以我又再透過 alias 別名方式重新指定他的資料行名稱為 t_id。而執行後的結果正是我所需要的方式。


2009年11月26日 星期四

使用 jQuery 的 trigger

撰寫 javascript 時,有時只是很單純的希望能夠在某些條件下,接下來要做的動作跟觸發某個按鈕一樣。其實重覆寫個一模一樣的程式並不是不行,只是違反了自己「懶」的原則。

在 jQuery 的線上文件裡,找到 trigger 這個事件,正巧是描述著可以透過程式去觸發某個控制項的事件。自己也順便練習了一下這個使用方法。

首先,在頁面放了兩個按鈕 btn1, btn2。分別會觸發 Do1() ,Do2()
<input id="btn1" type="button" value="btn1" onclick="Do1()" />
<input id="btn2" type="button" value="btn2" onclick="Do2()" />

<script language="javascript" src="js/jquery-1.3.2.js" type="text/javascript"></script>
    
    <script type="text/javascript">
    function Do1()
    {
        alert("是的!");
    }    
    
    function Do2()
    {
        alert('吃過飯了ㄇ?');
        
        $("#btn1").trigger('click');
    }
    </script>

在 Do1(),很簡單的只是 alert 一句話。而 Do2()裡,除了 alert 「吃過飯了ㄇ?」,還順便去觸發 btn1 原本的 click 事件。所以,當 user 壓下 btn2 時,就會依序跳出兩個訊息:「吃過飯了ㄇ?」,「是的!」

ref:http://docs.jquery.com/Events/trigger

2009年11月25日 星期三

window.open 最大化

近來一直在拜求如何讓 window.open 所跳出的新視窗能夠一開始就最大化,不需讓 user 還要再去點選一次瀏覽視窗的最大化,可惜,一直沒找到真正的解決方案。

有人透過

window.open(url,"","fullscreen=yes");

雖然是把畫面變大了,但它是屬於全螢幕的呈現方式,對於一般瀏覽器操作比較不熟的 user ,可能無法很順利的處理如何解除全螢幕的設定。

最後找到比較接近需求的方式,是透過 JavaScript 去控制新開啟的視窗,把它的寬高放大到與 user 目前的螢幕相同。
他的 code 如下所示:
sc=window.open(url,"","resizable=yes,scrollbars=yes");
sc.resizeTo((screen.availWidth),(screen.availHeight));
sc.moveTo(0,0);


參考:http://www.lslnet.com/linux/f/docs1/i57/big5380574.htm

2009年11月19日 星期四

/dev/null 的功用

在 Linux ,/dev/null 目前想到的功用有兩個:

1. 清除 Log
    ex:   /home/paladin/List.log   (是某一個應用程式的 Log 檔)

            cat   /dev/null  >>  /home/paladin/List.log

             這行指令就可以簡單的清除掉目前的 Log 紀錄
          


2.開一個空白的檔案

           cat   /dev/null   >>   /home/paladin/newFile.txt

           這行指令可以新增一個空白檔案 (檔案名稱: newFile.txt )

2009年11月5日 星期四

BULK Insert

當你有大量的文字檔要輸入到 SQL Server 的資料表時,可以使用 BULK Insert 指令來完成,
且其效能會比一筆一筆 insert into 來的好。

舉例來說,你有個文字檔,其內容如下:

===== list.txt ====
李志堅,aa@3probe.com.tw
馮世華,bb@3probe.com.tw
洪崇富,cc@3probe.com.tw


測試資料表:
CREATE TABLE [dbo].[BULKTest](
 [BName] [nvarchar](50) NULL,
 [BMail] [nvarchar](100) NULL
) 

在 SQL 下,就可以執行以下指令來匯入資料到DB
BULK insert BULKTest from 'C:\MailList.txt' WITH (FIELDTERMINATOR = ',')

為了實際比較效能,另外寫了一段程式來比較:
declare @count int
set @count=0
while @count<100000
begin
insert into BULKTest (BName,BMail) values (N'李志堅','aa@3probe.com.tw')
set @count=@count+1
end
同時也將 MailList.txt 資料比數複製到100000筆,其所花費時間(秒)的結果是 2:23 真的在大量資料的環境下,使用 BULK Insert 是有利可圖的。 另外也實際測試了一下 BULK Insert 的資料來源是否可以支援網路磁碟,

BULK insert BULKTest from '\\GroupServer\share\test\MailList.txt' WITH (FIELDTERMINATOR = ',')

 結果是正常的。 如果您的資料量是好幾G以上的,建議可以參考一下「黑暗執行緒」的一篇 BULK INSERT Performance, 他提到有關 Log 資料增長的問題,因為大量新增資料後,留下的 Log 紀錄可能會灌暴硬碟空間,裡面介紹 一些參數與設定,讓你在使用 BULK Insert 時不留下 Log。 綜整所謂完美範本如下以茲盜拷:

BULK INSERT BULKTest
FROM 'C:\MailList.txt'
WITH
(
    BATCHSIZE = 1000,
    FIELDTERMINATOR = ',',
    ROWTERMINATOR = '\n',
    TABLOCK
)


參考資料:Using BULK INSERT to Load a Text File

2009年11月4日 星期三

透過 jQuery 以 ajax 方式抓取後端回傳的 xml 資料

後端伺服器要回應 xml 資料給前端網頁,你可以用 aspx 來寫,但更好的選擇,則是用 ashx (泛型處理常式)。其中的差別,在於 aspx 所回傳的是網頁型態,但 ashx 則可以回傳更多樣的型別,如圖片、附件檔、或是目前所要實現的 ajax 結果。

當然,aspx 也是可以,只是要在輸出結果前,清掉原先 aspx 頁面上預設的所有標籤。你可以事先刪除 aspx 上的 HTML 標籤,或是在 .cs 裡面寫一行 Page.Controls.Clear();  都可以。

先寫一段 aspx 後端的程式:

using System.Xml;

protected void Page_Load(object sender, EventArgs e)
{
    //建立 XMLDOCUMENT 物件
    XmlDocument ObjXML = new XmlDocument();

    //建立 根節點 物件
    XmlElement root = ObjXML.CreateElement("people");
    //插入 根節點物件到 XMLDOCUMENT 物件
    ObjXML.AppendChild(root);
    //建立子節點物件
    XmlElement user = ObjXML.CreateElement("user");
    //插入 子節點物件 到 根節點物件
    root.AppendChild(user);

    //設定子節點屬性
    user.SetAttribute("name", null, "paladin");
    //設定子節點屬性
    user.SetAttribute("cname", null, "李志堅");

    XmlDeclaration xmldecl;
    xmldecl = ObjXML.CreateXmlDeclaration("1.0", null, null);
    xmldecl.Encoding = "UTF-8";
    ObjXML.InsertBefore(xmldecl, root);
    //插入XML類型標頭
    string myxml = ObjXML.InnerXml.ToString();    


    //清除頁面上的控制項,只回傳所需的 xml 資料
    Page.Controls.Clear();
    Response.ContentType="text/xml";
    Response.Write(myxml);

}

透過這段程式,可以回傳 xml 的測試結果。
這裡要注意的,是記得設定好 Response.ContentType ,讓他為 "text/xml",如果你沒有設定,在 IE 瀏覽器可能會無法正確分辨。另外要做的,就是在輸出結果前,寫上一句: Page.Controls.Clear(); ,清除頁面上既有的HTML控制標籤。

比較推薦的方法(看起來比較專業一點啦),是用 ashx 來撰寫,程式如下:

resultXml.ashx
using System.Xml;

public void ProcessRequest (HttpContext context) {
    context.Response.ContentType = "text/xml";

    //建立 XMLDOCUMENT 物件
    XmlDocument ObjXML = new XmlDocument();

    //建立 根節點 物件
    XmlElement root = ObjXML.CreateElement("people");
    //插入 根節點物件到 XMLDOCUMENT 物件
    ObjXML.AppendChild(root);
    //建立子節點物件
    XmlElement user = ObjXML.CreateElement("user");
    //插入 子節點物件 到 根節點物件
    root.AppendChild(user);

    //設定子節點屬性
    user.SetAttribute("name", null, "paladin");
    //設定子節點屬性
    user.SetAttribute("cname", null, "李志堅");

    XmlDeclaration xmldecl;
    xmldecl = ObjXML.CreateXmlDeclaration("1.0", null, null);
    xmldecl.Encoding = "UTF-8";
    ObjXML.InsertBefore(xmldecl, root);
    //插入XML類型標頭
    string myxml = ObjXML.InnerXml.ToString();    

    context.Response.Write(myxml);        
    
}

使用 ashx 唯一要注意的,就是要設定 context.Response.ContentType ,將他設成 "text/xml",因為要回傳的結果是 xml 格式。

後端回傳結果:
<?xml version="1.0" encoding="UTF-8"?><people><user name="paladin" cname="李志堅" /></people>


最後,開始撰寫前端的 jQuery 叫用方法:

<script>
function DoAjax()
{   
   //{ name:"paladin" } 是用來傳到後端的參數,目前用不到   
   // $(xml).find("user") 會回傳每個 "user" 元素集合
   // 再透過 .each( ) 去取得 每個 user 元素 的屬性
   $.post("resultXml.ashx",{ name:"paladin" } ,function(xml){        
    $(xml).find("user").each(   
        function(){ 
        var _name = $(this).attr('name');
        var _cname=$(this).attr('cname');
        alert(_name);
        alert(_cname);
        $("input[id*=txt01]").val(_name+':'+_cname);        
    });
   } );
}
</script>

<asp:TextBox ID="txt01" runat="server"></asp:TextBox>
<input id="btnNoPostBack" type="button" value="NoPostBack" onclick="DoAjax()" />


如此,就有一個很完整的 jQuery 使用 ajax 傳遞 xml 的程式樣板可參考了。


ref:TIPS-神奇的jQuery XML查詢魔法

透過 jQuery 抓取網頁 URL 的參數

推薦一個 jQuery 外掛的程式,可以很輕鬆的完成抓取目前 url 上的參數。
詳細網站可以參考:
JQUERY.URL.JS (http://ajaxcssblog.com/jquery/url-read-request-variables/)

使用方法,
需先引用 jQuery.js ,再加上 jquery.url.js

<script type="text/javascript" src="js/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="js/jquery.url.min.js"></script>

當你要使用時,只要執行 $.url.param("參數名稱") 就可以取得參數值
舉例來說:
如果你目前的網頁是 http://www.xxx.com.tw?paladin=handsome
$.url.param("paladin") 則會回傳 handsome

但如果所查詢的參數是不存在,則回傳空字串,
同上例: $.url.param("hugo")   就回傳空字串啦。

如果你希望將url 後面所有的參數都抓回存成陣列,則可以使用
$.url.paramAll()  即會回傳所有參數集合的陣列

下載網址:
jquery.url.js
jquery.url.min.js 

附上作者原始 source code:

/*
jQuery Url Plugin
 * Version 1.0
 * 2009-03-22 19:30:05
 * URL: http://ajaxcssblog.com/jquery/url-read-get-variables/
 * Description: jQuery Url Plugin gives the ability to read GET parameters from the actual URL
 * Author: Matthias Jäggli
 * Copyright: Copyright (c) 2009 Matthias Jäggli under dual MIT/GPL license.
*/
(function ($) {
 $.url = {};
 $.extend($.url, {
  _params: {},
  init: function(){
   var paramsRaw = "";
   try{
    paramsRaw = 
     (document.location.href.split("?", 2)[1] || "").split("#")[0].split("&") || [];
    for(var i = 0; i< paramsRaw.length; i++){
     var single = paramsRaw[i].split("=");
     if(single[0])
      this._params[single[0]] = unescape(single[1]);
    }
   }
   catch(e){
    alert(e);
   }
  },
  param: function(name){
   return this._params[name] || "";
  },
  paramAll: function(){
   return this._params;
  }
 });
 $.url.init();
})(jQuery);

JQuery 取得 checkbox 群組內被選取的項目



在 ASP 程式裡,只需要下 Request("cbox") 語法,就可以將所有 checkbox name="cbox" 的項目內容取回並以逗號(,)區隔。可是在 JQuery 就沒辦法用一行指令來完成了。以下分別使用 jQuery 與 JavaScript 來完成同樣的目的。

首先定義一下情境。

<input type="checkbox" name="pet" value="1"/>
<input type="checkbox" name="pet" value="2"/>
<input type="checkbox" name="pet" value="4"/>

<BR>
<input type="button" value="JQueryclick" OnClick="JQClick()" />
<BR>
<input type="button" value="JSclick"  onclick="JSClick()"  />

一共有三個 checkbox ,都是同樣的 name (pet),另外多了兩個 button,一個是呼叫 jquery 寫法,另一個則是 javascript 。

既然有要使用 jQuery,所以一開始就要記得將 jQuery.js 引用進來:
<script src="jquery.js" type="text/javascript">

接著就需要定義 JQClick() 與 JSClick() 。

JQClick:
function JQClick()
{  
   var str="";  
//$("input[name=pet]:checked") 
//可以先將畫面上 name=pet 且 有被勾選的 checkbox 選出來   
//然後再透過 each ( ) 去分別處理每個被選取的項目
   $("input[name=pet]:checked").each(function(i){str=str+$(this).val()+",";})
//將字串最後一個逗號去除
   if(str.length>0)
     str=str.substr(0,str.length-1);
     alert(str);
}

JSClick:
function JQClick()
{
  var checkedItems=""
  //取得畫面上 name = pet 的元素,他會回傳一個陣列集合
  var ckItems=document.getElementsByName('pet');
  //針對陣列集合的項目逐筆去處理
  for ( var i=0;i
    //如果有被勾選 ,才記錄下來
    if(ckItems[i].checked==true)
    {    
       checkedItems=checkedItems+ckItems[i].value+",";
    }
  }

  if(checkedItems.length>0)                
     checkedItems=checkedItems.substr(0,checkedItems.length-1);

  alert(checkedItems);
}

2009年11月1日 星期日

少做


想做的事情,永遠都做不完
該做的事情,往往都忘了做
你可以當個濫好人,讓生活忙碌下去
也可以聰明去選擇,讓生命更有意義

慶生的時候,只給壽星三個願望,
並非大家小氣吝嗇,
而是要你去找出生命裡重要的事

如果你什麼事都想做,那乾脆去把圍裙穿上,
對著老闆說:「主人,今天您需要什麼服務?」

有本書譯名為「少做一點不會死」
但自己卻不這麼認為,
如果你指導教授叫你寫論文,
而你卻不寫,看你會不會死。

然而,如果你用心去做你該做的事,
剔除不必要的工作,
自然所做的事情就少了。

「少做」,並非方法,而是結果。

我比較肯定原書作者的標題:「The Power of Less 」

但「少做」,不代表你將更輕鬆、更有自己的時間,
而是更明確知道自己為何而活、為何而做。

你若問我自己做到了沒,
我會回答:「主人,今天中午要去哪裡吃飯?」

2009年10月30日 星期五

取某個字元之前的字串

假設有個字串是:0.10#p1
我現在想要取得的是#字符號之前的0.10
可能一開始就會想到使用 substring( ) 這函式。
但是要使用這個函式,必須先知道 # 字符號所在的索引位置,
並推算出在此之前的字串長度是多少,才能正確取得 # 字符號之前的字串。
雖然不難,但卻顯得有點令人覺得繁瑣。

剛好,是懶惰救了我。
推薦一個不錯的寫法:

string str="0.10#p1";
str.split('#')[0];    //---- >  這一行就會回傳 # 字符號之前的字串  0.10
str.split('#')[1];    //----->  延伸一下,這一行,就會回傳# 字符號之後的字串 p1

他的原理,是先透過 split 函式,將 # 字符號當作是切割點,將字串轉換成陣列,而[0]指的,則是陣列的第一個元素,也正好是我們所需要的結果。如此一來,程式就簡潔許多了。

2009年10月27日 星期二

ASP.Net 產生 XML 格式

轉載 ASP.Net 產生 XML 的方法。


using System.Xml;



XmlDocument ObjXML = new XmlDocument();//建立 XMLDOCUMENT 物件

XmlElement root = ObjXML.CreateElement("people");//建立 根節點 物件
ObjXML.AppendChild(root);//插入 根節點物件到 XMLDOCUMENT 物件
XmlElement user = ObjXML.CreateElement("user");//建立子節點物件
root.AppendChild(user);//插入 子節點物件 到 根節點物件

user.SetAttribute("name", null, "paladin");//設定子節點屬性
user.SetAttribute("cname", null, "李志堅");//設定子節點屬性

XmlDeclaration xmldecl;
xmldecl = ObjXML.CreateXmlDeclaration("1.0", null, null);
xmldecl.Encoding = "UTF-8";
ObjXML.InsertBefore(xmldecl, root);
string myxml = ObjXML.InnerXml.ToString();//插入XML類型標頭
Response.Write(myxml);//輸出 XML 文件格式




執行上面這段程式,就可以產生以下結果:



< ?xml version="1.0" encoding="UTF-8"? >
< people >
< user name="paladin" cname="李志堅" / >
< /people >


透過jQuery變更奇偶欄位的樣式

要讓 Table 裡的每列資料可以根據奇偶之分來採用不同的顏色區分,如果透過 jQuery來實作,似乎比較簡單哩。

首先,先建立一個測試用的 Table。其內容如下:




< Table id="tb" border="1" style="border-collapse: collapse;" >
< TR class="gvh" >
< TH> School < /TH >< TH > Location </TH>
< /TR>
< TR>
< TD> NTU </TD>< TD > 台北 </TD>
< /TR>
< TR>
< TD> NTHU </TD>< TD > 新竹 </TD>
< /TR>
< TR>
< TD> NCTU </TD >< TD > 新竹 </TD>
< /TR>
< TR>
< TD> NCKU </TD >< TD > 台南 </TD>
< /TR>
< /TABLE>



接著,將我們會用到的 style 設定寫好:



< style >
.gvh
{
background-color: Blue;
font-weight: bold;
color: Red;
font-size: 14px;
text-align: center;
}
.gvr
{
background-color: #EFEFEF;
font-size: 14px;
}
.gva
{
background-color: #FFFFFF;
font-size: 14px;
}

< /style >


關鍵的 jQuery 控制,則如下所示:



< script >
$(function() {
$("#tb tr[class!=gvh]:even").addClass("gva");
$("#tb tr[class!=gvh]:odd").addClass("gvr");
});
< /script >



由於我們一開始在原先的 Table 的第一列就把他的 TR 樣式設為 "gvh" ,所以在 jQuery 的程式碼裡,要避免去覆蓋已經設為 Header 的樣式,所以會透過屬性設定的過濾條件濾掉 class=gvh ,這樣才會讓奇偶樣式的效果正確呈現出來。


2009年10月7日 星期三

four-part notation(naming) in SQL

介紹在 SQL 所提到的一個名詞 four-part notation(naming) 。

當你有好幾台 SQL Server 時,每台SQL Server 都各自有各自的資料庫。人怕撞衫而 SQL Server 則怕撞庫。為了存取資料庫時避免發生混淆不清的現象,則定出了 four-part notation,這四個部份分別是:

For SQL Server 2000
server.database.owner.object

For SQL Server 2005
server.database.schema.object

如果你的北風資料庫是放在 paladin_SQL 上,要存取Sales 資料表,則採用 four-part notation 時,就會寫成:
paladin_SQL.NorthWind.dbo.Sales

另外,如果你今天是在 amy_SQL 上想要存取 paladin_SQL 資料,

select * from paladin_SQL.NorthWind.dbo.Sales

這樣子的作法理論上是對的,但別忘了,要跨 DB Server 去存取資料,要記得先設定 link servers,才能順利完成。

2009年9月29日 星期二

在 ASP.Net 程式裡避免 User 連續觸發 Button

當網路回應速度不快時,user 壓下某個 button 後,畫面卻還停留著而尚未回應,此時如果再壓一次該 button ,則就會再觸發一次該 button 的事件。為了避免這問題,可以透過一段 javascript 來處理。

btn.Attributes["onclick"] = "this.style.display='none'; alert('some message..');";

如果原先這個 button 已經有呼叫 confirm( ) 時,例如會詢問 user 是否確定要執行,如果「」,則將 button 隱藏是可達成避免連續觸發的問題,但如果「」,實際上是不需要隱藏 button 的。所以,如果是已經有 confirm( ) 時,則先用一個變數來存 confirm( ) 的值,再依據這個值來決定是否要隱藏 button。

btn.Attributes["onclick"] = "var vRW=confirm('是否確定要重新修改?'); if(vRW) { this.style.display='none'; return true; } else { return false; } ";

2009年9月27日 星期日

項目'LocalSqlServer'已加入

在 web 站台上,突然出現 項目'LocalSqlServer'已加入 的錯誤訊息,並且指出是 web.config 發生的。而檢查目前的 web.config 檔,有這下面一段:

< add name="LocalSqlServer" connectionString="Data Source=192.168.1.1,5433;Initial Catalog=Test;User ID=sa;Password=sa" providerName="System.Data.SqlClient"/>


自己也只有這個地方在設定資料庫連線而已,真不知道為何還是會出現已加入的錯誤訊息,但把程式安裝在其他台電腦卻又是正常的。所幸,在MSDN上發現一篇類似問題的解法,就是在 < add name="LocalSqlServer" /> 之前,先強制移除,也就是使用 < remove
name="LocalSqlServer"/> 。這招真的有效,下次如果有人也遇到相同的狀況,可以試試。

BinarySearch (二)

在先前 BinarySearch(一)的介紹,陣列裡面的元素為字串,但陣列所支援的,並非只有字串而已,而現在正要討論的,是當陣列內容是我們自己定義的類別時,還可以用 BinarySearch 嗎?

首先,我定義了一個簡單的 Person 類別:


class Person
{
public string Name = string.Empty;
public string Department = string.Empty;

public Person (string strName, string strDep)
{
Name=strName;
Department=strDep;
}

public string ShowDetail()
{
return string.Format("Name:{0}, Dep:{1}", Name, Department);
}
}





接著,我很開心的一一鍵入我的測試資料:

Person p1 = new Person("paladin", "BPO");
Person p2 = new Person("hugo", "BPO");
Person p3 = new Person("ken", "BPO");
Person p4 = new Person("keen", "BPO");
Person p5 = new Person("polly", "BPO");
Person p6 = new Person("panda", "BPO");
Person p7 = new Person("lillian", "BPO");
Person p8 = new Person("gemma", "BPO");
Person p9 = new Person("hana", "BPO");

Person[] arrayOffice = { p1, p2, p3, p4, p5, p6, p7, p8, p9 };
Array.Sort(arrayOffice);




當我寫到這裡時,傻住了,目前我的 arrayOffice 陣列,可以排序ㄇ?當程式一執行,馬上就丟出了不好的消息:「無法比較陣列中的兩個元素」。的確,字串、數字是可以用來比較大小,但是自己所定義的類別,如果你沒定下比較規則,那真的是拿芭樂比蓮霧了。

所以,重新修改了自己所定義的 Person 類別,讓他實作 IComparable 介面 來解決。


class Person :IComparable //宣告使用了 IComparable 介面
{
// 原先的程式碼
// XXXXXXXXXXXXX
// XXXXXXXXXXXXX

//實做 IComparable 介面
int IComparable.CompareTo(object obj)
{
Person p2 = obj as Person;
if (p2 == null) throw new ArgumentException("Object is not a Person!");
int iNameResult = this.Name.CompareTo(p2.Name);
if (iNameResult == 0)
{
int iDepResult = this.Department.CompareTo(p2.Department);
return iDepResult;
}
else
{
return iNameResult;
}
}



在自己所實作的 CompareTo( )裡,先比較兩個 Person 的 Name 是否一致,如果一致,接著再比較Department 是否一致。也就是當 Name 與 Department 相同時,才視這兩個 Person 物件為相等。



當解決了 Sort( ) 的問題後,接下來的 BinarySearch( )就不是問題了,於是可以繼續將先前打住的程式繼續往下寫下去。



Person p1 = new Person("paladin", "BPO");
Person p2 = new Person("hugo", "BPO");
Person p3 = new Person("ken", "BPO");
Person p4 = new Person("keen", "BPO");
Person p5 = new Person("polly", "BPO");
Person p6 = new Person("panda", "BPO");
Person p7 = new Person("lillian", "BPO");
Person p8 = new Person("gemma", "BPO");
Person p9 = new Person("hana", "BPO");

Person[] arrayOffice = { p1, p2, p3, p4, p5, p6, p7, p8, p9 };
Array.Sort(arrayOffice);
foreach (Person p in arrayOffice)
Console.WriteLine(p.ShowDetail());

Person pSearch = new Person("panda", "BPO");
int iIndex = Array.BinarySearch(arrayOffice,pSearch);
Console.WriteLine("Index of 'panda' object is :" + iIndex.ToString());

Console.Read();

BinarySearch (一)



在 .Net 的 Array 物件,有個 BinarySearch 方法,光從字面上猜,應該是用來「找查」用的。 於是寫了一段 code 來試試。




string strInput = "paladin,hugo,ken,keen,polly,panda,lillian,gemma,hana";
string[] strArray = strInput.Split(',');

foreach (string s in strArray)
{
Console.WriteLine(s);
}

int iLocation=Array.BinarySearch(strArray, "panda");
Console.WriteLine("Index of 'panda' is :"+iLocation.ToString());
Console.Read();



蠻不給面子的,竟然沒用!
後來發現,要使用 BinarySearch( ),必須要先將資料進行排序才行,也就是說,不排序,就不給用。而在 Array 物件,他也同時提供了 Sort( )方法,正是使用 BinarySearch( ) 所需要的。於是修改了一下上面的程式,加上 Array.Sort(strArray) 。




string strInput = "paladin,hugo,ken,keen,polly,panda,lillian,gemma,hana";
string[] strArray = strInput.Split(',');
Array.Sort(strArray);

foreach (string s in strArray)
{
Console.WriteLine(s);
}

int iLocation=Array.BinarySearch(strArray, "panda");
Console.WriteLine("Index of 'panda' is :"+iLocation.ToString());
Console.Read();




的確,加上排序後,查詢的功能就正確了。但這時心裡頭不免偷偷地「暗」一下微軟,幹麼不乾脆一點,還要讓人這麼麻煩。後來發現,其實這是有原因的。Binary Search (二分搜尋法),是用來搜尋已經排序過的資料。基本上,是先將要比較的資料與所有資料的中間值作比較,根據比較結果的大、小或相等,再來決定下一個搜尋範圍或直接得到搜尋結果。而這種搜尋方式,當然會比我們寫一個迴圈從第一筆慢慢找到最後一筆還來的快許多。

然而,別忘了使用 BinarySearch ( ) 的前提是必須先將資料排序,所以必須將排序所花的時間與搜尋時間加在一起才公平。在效能上來說,如果你要查詢的陣列只有使用一次而已,循序搜尋也不見得會比較慢,因為當資料量很龐大時,光排序也需要花不少時間。相反地,如果你的陣列會一直不斷的被重複使用,只要事先執行一次排序,之後就只需不斷地呼叫 BinarySearch( )則會較佔優勢,這正也是為何自己先前質疑使用 BinarySearch( ) 為何要與 Sort( ) 分開的原因。

2009年9月26日 星期六

Tomcat 6 & JDK 6

紀錄目前在 Windows XP 環境下設定 JSP 的開發環境,選擇的工具為 Tomcat 6 與 Java 的JDK 6 版本。這次所使用的軟體,可以到以下連結去下載:

JAVA JDK 6 [下載]
Apache Tomcat 6.0.20 [下載]

JAVA 所選擇的是 Java SE Development Kit 的 JDK 6 Update 16 版本。

Tomcat 所選擇的是 Binary Distributions 的 zip 格式。

首先,需要先安裝 JAVA 的環境。解開並執行剛剛所下載的 JDK 即可。

接著,安裝 Tomcat。執行所下載的 .EXE 執行檔,我在安裝路徑上選擇了 C:\Tomcat。在安裝動作的尾聲,會跳出一個視窗,問你目前要用來呼叫 JAVA 的路徑,則是填寫上一個安裝JAVA步驟後的位置:
C:\Program Files\Java\jdk1.6.0_16

緊接著,他會跳出一個畫面,提供你設定 Apache Tomcat 的管理員帳號及密碼。這管理員資訊在安裝完後,是存放在 C:\Tomcat\conf\tomcat-users.xml 。

當安裝完 JAVA 與 Tomcat 後,需要作一些環境設定。
打開 [我的電腦] - [右鍵] - [內容] - [進階] - [環境變數] - 在環境變數下選擇 [新增]

變數名稱變數值
CLASSPATHC:\Program Files\Java\jdk1.6.0_16\bin
CATALINA_HOMEC:\Tomcat
JAVA_HOME C:\Program Files\Java\jdk1.6.0_16


如此,就完成了 Windows XP 安裝 JSP 開發環境的安裝了。

在 Tomcat 過去的版本,都會在根目錄下有以下幾個主要資料夾產生:





資料夾說明
bin程式指令(啟動與停止)
common執行所需jar函式庫
conf 設定檔
logs日誌檔
webapps 存放網頁應用程式目錄


但在 6.X 版,已經廢棄了 common 資料夾了。而原先在 /common/lib ,現在則是
將 /lib 資料夾提到根目錄下。所以在根目錄下面,就可以找到 lib 資料夾了。原先用來
存放擴展的 jar 檔案,也因此改放到根目錄下的 /lib 資料夾下(也就是說,當你有需要
引用別人包好的 jar 函式類別時,記得要放到 /lib 下方)。

參考網址一:http://tw.myblog.yahoo.com/aloha-tw/article?mid=359
參考網址二:http://www.javayou.com/diary/6413

2009年9月21日 星期一

An INSERT EXEC statement cannot be ne...


最近在撰寫一支 SQL Server Store Procedure 時,一直發生
An INSERT EXEC statement cannot be nested 的錯誤訊息。
SQL 語法如下:
create table #tFinishAll ( IsFinish int )
insert into #tFinishAll (IsFinish) 
exec pr_prog_section3_is_report_finish  
當我單純的只有執行 exec pr_prog_section3_is_report_finish 時,
結果是正常的,但跟 insert into #tFinishAll (IsFinish)  一起執行時,
就會出錯。

詳細檢視了 pr_prog_section3_is_report_finish 這支 Store Procedure,
發現它裡面也有類似先建立一個暫存資料表,然後又透過 執行 
Store Procedure 來新增資料的方式。

原來,這種情況在 SQL 2005 就會被視為 Nested Insert Exec而被禁止。
詳細文章可參考:http://www.windows-tech.info/15/fe648af19f711aba.php
所以,我就需要改寫自己的 Store Procedure ,改成透過 OPENROWSET
的方式來解決。於是將自己的程式改寫如下:

SELECT *
FROM OPENROWSET
(
'SQLOLEDB',
'Server=SQLServer;uid=test_id;pwd=test_pwd',
' SET FMTONLY OFF exec pr_prog_section3_is_report_finish '
)


除了使用 OPENROWSET 語法改寫之外,另外要注意的,就是要加上
SET FMTONLY OFF關鍵字,宣告這個 Script 語法裡面是可以允許建立
暫存資料表的。

使用 C# 的 "as" 關鍵字

使用 C# 的 "as"  關鍵字

 

自己在C#語言關於使用轉型(cast)的記憶中,常常都很直覺的就會使用
強迫轉型方式來處理。就以 Person 的類別來舉例:

 


    class Person
    {
        public string Name = string.Empty;
        public string ID = string.Empty;


        public Person(string _name,string _id)
        {
            Name = _name;
            ID = _id;
        }


        public override bool Equals(object obj)
        {
            Person p = (Person)obj;
            return p.Name == this.Name && p.ID == this.ID;
        }



    }


 

Person p =(Person) obj;
會直接就用 (Person)去強迫轉型,原因是因為自己認為 obj 一定是屬於
Person型別,才會有如此的寫法。但是,真的能保證 obj 一定是屬於
Person型別嗎?這可能是自己的一廂情願吧!

當 obj 並非屬於 Person 型別時,系統就會丟出 InvalidCastException
的錯誤訊息。

為了避免轉型錯誤的發生,可以使用 "as" 這關鍵字。他會先去幫你作轉型
的動作,如果成功,自然就會回傳轉型成功後的物件型別;如果失敗,則會
回傳 null。所以,當使用了 "as" 關鍵字後,在透過判斷回傳值是否為 null
來完成型別轉換工作。

而上述的程式,修正如下:

 

        public override bool Equals(object obj)
        {
            Person p = obj as Person;

            if (p==null) return false;

            return p.Name == this.Name && p.ID == this.ID;
        }

 


 

 

2009年9月20日 星期日

Overriding Equals

Overriding Equals

 

當我們定義好一個類別之後,如果用這個類別來創建2個實體(Instance),
這兩個實體在記憶體分別儲存存在不同的位址,由此看來,這兩個實體的確
是不同的。 

以下面 Person 類別來說明: 


    class Person

    {

        public string Name = string.Empty;

        public string ID = string.Empty;

        public Person(string _name,string _id)

        {

            Name = _name;

            ID = _id;

        }

    }


 


Person 有兩個公開屬性,分別是 Name 與 ID。
如果程式如下:
Person p1=New Person("paladin","01");
Person p2=New Person("paladin","01"); 


這 p1 與 p2 ,雖然所傳入的值,都是 Name="paladin" ,ID="01",
但他們彼此卻是不相同的,可以透過以下的 Equals( )來知道。 


p1.Equals(p2)  


他會回傳 False。 


然而,今天如果我們想要重新定義,只要是 Name 與 ID 相同,就要視
兩個實體為相同,可以嗎? 


可以的,此時,可以透過覆寫 Equals( ) 來達成。


 


在 Person 類別裡,針對這個類別的 Equals( ) 方法進行覆寫,只要
Name 與 ID 相同,就視為相同的物件。 


將 覆寫的程式描述如下:


 


 


        public override bool Equals(object obj)
        {
            Person p = (Person)obj;


            return p.Name == this.Name && p.ID == this.ID;
        }


 


如此,執行 p1.Equals(p2) 時,
則會去比較 p2.Name 是否等於 p1.Name 且 p2.ID 是否等於 p1.ID ,
然後以此來回傳 Equals( ) 的值。


 


完整的 Person 的定義如下:


 


    class Person
    {
        public string Name = string.Empty;
        public string ID = string.Empty;


        public Person(string _name,string _id)
        {
            Name = _name;
            ID = _id;
        }


        public override bool Equals(object obj)
        {
            Person p = (Person)obj;


            return p.Name == this.Name && p.ID == this.ID;
        }



    }


 


 


而在實際比較時,就可以發現,此時 p1.Equals(p2) 就會回傳 True 了


 


        static void Main(string[] args)
        {
            Person p1 = new Person("paladin", "01");
            Person p2 = new Person("paladin", "01");


            Console.WriteLine(string.Format("p1 is the same with p2 ? {0}", p1.Equals(p2) ? "True" : "False"));
            Console.ReadKey();
        }


 


 



2009年9月11日 星期五

hammer & nail

今天在看書時,偶然看到這句英文:「If all you have is a hammer, everything looks like a nail.」。細細玩味後,覺得蠻有意思的。照字面上直譯,是說:當你有了一隻槌子之後,任何東西對你來說就像是釘子一樣不足為懼。

在 IT 界也是常常看到這種現象。偶而出現一種程式語言、或一項產品,有些人就會冀望它能夠實現任何東西,就會期待他能有十八般武藝什麼功能都能做得到。若是如此,就不免落得「以井觀天」,不切實際了。

2009年9月2日 星期三

PuTTY 連 Ubuntu 中文出現亂碼

PuTTY 官方網站:PuTTY: A Free Telnet/SSH Client

中文亂碼解決辦法:

開啟 PuTTY -->左側選單 Window-->Translation-->Received data assumed to be in which character set-->改為『UTF-8』

最後左側選單的 Session-->Saved Sessions-->輸入連線資訊,
例:17-0526xxx-01-->按 Save 儲存

如此就不需要每次連線都去修改。

2009年8月24日 星期一

在 OpenOffice的資料表上方新增一行空白

 

在 OpenOffice Writer ,如果一開始就先拉好一個資料表,但事後想要在資料表上新

增一行空白,可能要加個標題之類的需求,卻在操作畫面上找不到一個可以新增的地方。

[圖1]



的一篇文章後,真的有效。只需要把游標移到資料表的第一個空格,然後壓一下 Enter

鍵即可。

 

[圖2]



 

[圖3]



圖3的結果,可以看到資料表上方多了一行出來。可是,如果你在這時候又在

資料表的第一個空格上又再點一次Enter 鍵的話,則就不會再出現資料表上方

多一行空白的效果囉!


 

2009年8月21日 星期五

避免檔案上傳 timeout

當檔案上傳的資料量很大時,除了要設定可上傳的資料大小之外,
還要設定 TimeOut 時間,因為大檔在上傳時,會花很多時間。

可以在 web.config 的 <httpRuntime> tag 上,加設 executionTimeout 屬性。

範例:<httpRuntime executionTimeout="6000" maxRequestLength="1000000"/>

但要記得,如果有使用 executionTimeout 屬性,務必要將 compilation 的偵錯設為 false 才有效果。
<compilation debug="false">


補充 MSDN 資料:

executionTimeout

選擇性 TimeSpan 屬性。

指定由 ASP.NET 自動關閉之前允許執行要求的最大秒數。

這個逾時只在 compilation 項目中的偵錯屬性為 False 時才適用。
若要在偵錯時避免關閉應用程式,請不要將這個逾時設定為大的數值。

預設值為 "00:01:50" (110 秒)。


在 .NET Framework 1.0 和 1.1 版中,預設值為 90 秒

maxRequestLength

選擇性 Int32 屬性。

指定輸入資料流緩衝臨界值的限制,以 KB 為單位。這個限制可以用來防止服務拒絕攻擊,例如由使用者將大型檔案回傳至伺服器所引起的攻擊。

預設值為 4096 (4 MB)。



參考網址:


2009年8月18日 星期二

去除 html tag

如果發現從資料庫抓回來的資料,含有許多 html tag,但你不想要這些 tag 時,
可以透過以下 RegularExpression 方式去除這些 html tag



using System.Text.RegularExpressions;


protected void Button1_Click(object sender, EventArgs e)
{
string str = @"<a href="""" target=""_blank"">cftea</a>";
Regex regex = new Regex(@"<(.|\n)+?>");
str = regex.Replace(str, "");
Response.Write(str);
}


2009年7月25日 星期六

很讓人開心的婚禮



意外的發現一個很令人難忘的婚禮開場。真的是對很幸福的新人,且擁有這麼多不計形象奮力演出的伴郎伴娘。

原始網站:http://www.youtube.com/watch?v=4-94JhLEiN0

2009年7月23日 星期四

text box 浮水印




在 text box ,如果想要達到秀出浮水印提示文字的效果,除了用 ASP.NET AJAX Control Toolkit 所內建的浮水印文字方塊(TextBoxWatermark)功能之外,可以參考一個 jQuery PlugIn 的外掛功能:Jquery TextBox Help Plugin。

可以去下載 0.1.1 版本,有修正了重複點選 text box 會清掉 user 已經輸入文字的 bug。

使用方法也相當簡單:

/* 加入兩行 javascript 的引用,一個是指定 jquery 位置,一個則是 外掛的 plugin */
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="textboxhelp.js"></script>


/* 使用方式,則是在 ready( ) 事件中,去設定文字方塊的 textboxhelp 屬性即可 */
<script type="text/javascript">
$().ready(function(){
$("#search").textboxhelp({help:'預設說明'});
});

</script>


<input type="text" name="search" id="search" >

2009年7月17日 星期五

取得某資料表中的所有欄位資訊

在 SQL Server ,如果想要取得某資料表中的所有欄位,有兩種方法。

方法一、

透過 INFORMATION_SCHEMA.COLUMNS ,並篩選出 TABLE_NAME 是你想要的資料表即可。

SELECT * FROM
INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_NAME = 'test_column'
ORDER BY ORDINAL_POSITION ASC;

方法二、
使用 sp_help 。
如果在 sp_help 後面加上 資料表 名稱,他就會回傳該資料表所有資訊。
ex: sp_help 'test_column'


PS: 20131009 補充

如果有需要取得 DB 裡面每一個資料表的需求時,可以使用以下語法:
 SELECT * FROM INFORMATION_SCHEMA.TABLES 

2009年7月1日 星期三

設定 jQuery 取出的多筆結果

透過 jQuery ,簡單的一行 $("input[id*=btn_rec_edit]") 就可以取得畫面上所有名稱包含 btn_rec_edit 字眼的按鈕。但如果是要用來設定每個按鈕的 onclick 事件,且會個別抓取每個按鈕上所具有的特定值時,要如何撰寫?

$("input[id*=btn_rec_edit]").click(function(){
   
});

假設我的每個按鈕,都有自己的屬性 prd_id ,有看到網路上有人使用 this.id this.value 等語法去抓屬性的值,而我也針對自己的需求,寫了 this.prd_id ,真的可以。然而,當我換到 FireFox 之後,這語法就失效了,跑出 undefined出來。

$("input[id*=btn_rec_edit]").click(function(){
   alert(this.prd_id);
});

自己再詳細的看了 jQuery 的 Documentation 之後,看到有這個用法,$(this) ,就表示目前被壓下去的按鈕物件。這語法在 FireFox 上就可以正確執行了。

$("input[id*=btn_rec_edit]").click(function(){
   alert($(this).attr("prd_id"));
});


只要一開啟某個資料夾就顯示Explorer.exe發生問題


工作使用的 XP 系統,近來只要一開啟檔案總管,沒多久就會出現

『Explorer.EXE發生問題,必須關閉,謹此致歉。』

的錯誤訊息。網路上找了很多相關的介紹,不是說中毒就是檔案損毀,但真的很不想重灌。心想著,好吧!就算是中毒,也要看看兇手是誰。當我打開事件檢視器的應用程式時,發現一堆 Error 出現,隨便點了幾個,都是 Explorer.EXE 在掛掉前所拋出的求救訊息。詳細看了一下描述裡的內容。哇!Keykey.ime ? 不就是 Yahoo 輸入法的應用程式名稱嗎?想想,也是最近才更新了 Yahoo 輸入法的版本。當下含淚親手移除了 Yahoo 輸入法。沒想到大義滅親之後,電腦真的又重生了。但是沒有一個好用的輸入法,真的很寂寞,寂寞到連打字速度都變慢了。還好這時新酷音下載後,用起來也還可以接受,也就填補了這一段沒Yahoo的空窗期了。



2009年6月21日 星期日

值得好好學的 GIMP

剛開始接觸 Linux 的 GNOME 桌面,單純的想要使用類似 windows 小畫家功能來貼些圖,卻無心開啟了 GIMP 影像處理軟體。看到桌面跳出一堆看不懂的控制介面,真的傻掉了。今天有蓮花颱風逼近,外頭從中午之後就開始下雨,哪也去不了,只好上網進一步了解一下什麼叫做 GIMP。
『哇!』,這真的是一個很棒的免費軟體。原來 GIMP 當初的開發者,是以 Photoshop 繪圖軟體為模仿對象,最大的差別,就是一個要錢,一個不要錢。推動 GIMP 持續開發的最大動力,是一股熱情與理想。但缺乏經費的奧援,總是離他模仿對象 Photoshop 仍有一段差距。然而,以 GIMP 目前已經支援的功能來說,或針對我個人來說,基本的需求其實已經能夠滿足,甚至比我想要的還要更多了。
看到網路上有不少人聲稱,雖然目前 GIMP 無法跟的上 Photoshop的腳步,但卻可以跟目前國內知名影像處理軟體 - PhotoImpact 互相媲美。因自己沒有實際使用過 PhotoImpact,所以這點就不予置評了,但如果誠如網友所言,這產品可相互媲美,那只能祝福 PhotoImpact,『要好好加加油了』。
GIMP 軟體在 Linux 的 GNOME 桌面,是內建的。但如果你是 windows 使用者,也是一樣可以免費去使用。可到 GIMP 官網 (http://www.gimp.org/ )點選 Download 按鈕去下載。目前最新版本為 2.6.6。下載安裝後,如果你跟我一樣不知從何開始,可以參考幾位國內大力推動自由軟體的網友所整理或製作的教學網站,大概花個半天就可以學會基本的操作了。
             由  簡良諭老師、林家吉 老師合力製作
             ps: GIMP2 數位影像處理 http://maylike.kh.edu.tw/course/gimp268/index.html

教學網二:GIMP 影像處理錄影教學  http://163.20.160.21/xoops22/t167/gimp/list.htm
             由 歐展嘉 老師 製作

教學網三:風城社區大學 http://eos.hscu.hc.edu.tw/~x93c0125/94bgimp/

教學網四:數位修片技巧 http://linux400.dfes.tpc.edu.tw/gimp/

教學網五:[GIMP] 只是開始  http://www.mobile01.com/topicdetail.php?f=164&t=147270

教學網六:Gimp & 免費資源 http://tw.myblog.yahoo.com/jw!5nbbef.RAx8aIbO00RkKIw--/

教學網七:GIMP基礎功與範例教學 http://gimpbasic.blogspot.com/

教學網八:國外豐富的教學網站 http://www.gimp-tutorials.com/index.php

以下是用了教學網一裡面的移花接木技巧所完成的。


2009年6月6日 星期六

領軍3千人,打造百萬人生

刊載於 cheers 雜誌的一篇文章,介紹張景富在個人事業上的態度以及職涯歷程上的起伏。

2009年6月2日 星期二

VirtualBox

近日順利裝了一台 Fedora NB,心裡真的開心。但這熱情沒持續多久,就在第二台NB給澆息,真的灌到三字經都出來了。用 Virtual PC 2007 來裝,卻無法順利進入圖形安裝介面。後來發現網路上有許多文章有相關介紹,需要在進入安裝歡迎畫面後,按 Tab 鍵,在 Kernel 參數加上 vesa noreplace-paravirt clocksource=pit psmouse.proto=imps nohz=off  。可以參考這篇文章:Installing Fedora 10 on Virtual PC 。(補充:雖然加了參數後可以進入圖形安裝介面,但安裝到一半時,就會出現 Virtual PC 發生內部錯誤而被強迫重新開機導致安裝失敗~~)

就在 Google 找了許多有關 Virtual PC 2007 與 Fedora 10 的文章裡,意外發現有人推薦了 Virtual Box 這套虛擬機器,官網如下:VirtualBox 。詳細安裝過程可參考  重灌達人安裝說明 。這套虛擬機器可以讓你安裝在 Windows 或 Linux 作業系統上,而另一個吸引人的特色,就是免費。

實際在 XP 作業系統上安裝 VirtualBox,過程中會一直出現軟體安裝的警告訊息,請選擇【繼續安裝】即可。







2009年5月30日 星期六

Fedora 10 安裝記事

好久沒摸 Linux 了,剛好最近有台 NB 需要合法的作業系統,索性就給它從頭到腳都是合法。
雖然 Fedora 官網倒數著 7 天候就會釋出
Fedora 11,但心裡還是等不及地直接裝上
Fedora 10。出乎自己意料,目前的 Fedora 10
的版本,硬體支援度竟是這麼的棒,連我這台
2 年前雜牌 NB 都可以跑得嚇嚇叫,果然非昔日吳下阿蒙,不可同日而喻了!



以下紀錄安裝完 Fedora 10 後,額外需安裝的套件:



1. flash player:讓你使用 FireFox 瀏覽網頁時,可以看到 Youtube 影片或 Yahoo 網站
的動畫廣告

b.先要去 Adobe 網站下載 .rpm 檔案。
c.打開:應用程式 >> 系統工具 >> 終端機 ,輸入指令 rpm -Uvh 剛下載的檔案.rpm
d.再執行 yum install flash-plugin
e.關掉所有目前已開啟的 FireFox 頁面, 重新開啟 FireFox 就可安裝完成。

2. 更新你的系統:你目前雖然剛安裝好作業系統,但難保目前有些軟體已經有較新的版本發佈,
透過這步驟,可以確保你作業系統上的軟體是最新的。

a.參考這篇:Fedora7 設定軟體更新程式 (Freshrpms 套件庫 )
b.打開:應用程式 >> 系統工具 >> 終端機
c.如果 /etc/yum.repos.d/ 這個目錄內有 freshrpms.repo 這個檔案,請先將檔案刪除。
d.
在終端機內輸入
rpm -ivh http://ftp.freshrpms.net/pub/freshrpms/fedora/linux/7/freshrpms-release/freshrpms-release-1.1-1.fc.noarch.rpm
這個指令會安裝 freshrpms 套件,並在/etc/yum.repos.d/目錄下,新增一個檔案,
檔案名稱為freshrpms.repo。
e.在工作列上點選 應用程式-->系統工具-->軟體更新程式。根據自己經驗,會花半個小時以
上去完成軟體的更新。


3. 下載 xmms-mp3:電腦如果不會唱 mp3 歌曲很像很遜
a.到 xmms-mp3 - MP3 output plugin for XMMS 下載 xmms-mp3
b.下載後直接安裝即可。

4. 播放影片 (rmvb, avi)
a.參考這篇:Fedora 9装mplayer播放rmvb经验总结
b.安裝 mplayer。
yum -y install mplayer
c.安裝 smplayer。
yum -y install smplayer

d.安裝解碼器。
下载地址:http://www1.mplayerhq.hu/MPlayer/releases/codecs/essential-20071007.tar.bz2

安装方法:
tar -xf essential-20071007.tar.bz2
mkdir -p /usr/lib/codecs/
cp -p essential-20071007/* /usr/lib/codecs/



5. PDF 檔案支援。
Fedora 10 所內建讀取 pdf 檔案的程式為 Document Viewer (文件檢視器)。如果 pdf
文字是中文,則會出現文字糊掉或亂碼的現象。目前尚未找到針對 Document Viewer 的
解決方式。解鈴還須繫鈴人,我們回頭到 Adobe 的官方網站,去下載 Adobe Reader 的
rpm 回來直接安裝,酷!中文字的問題完全解決。

6. 檔案關聯設定。
針對播放影片,PDF 等檔案,都安裝了非預設的開啟程式。當然我們是希望以後遇到特定
副檔名,就要能夠用我們所安裝的程式來播放。這時,可以透過指定軟體開啟來設定。舉例
來說,我在某個 .PDF 檔案點選右鍵,執行『屬性』後,並選擇 『用指定軟體開啟』頁籤,
挑選 Adobe Reader,就是希望以後這類檔案都是用 Adobe Reader 來開啟。


7. 中華電信撥接上網
a.設定 Hinet 撥接。
b.打開 系統 >> 管理 >> 網路
c.點選左上角的『新增』圖示,在『裝置類型』選擇 xDSL 連線,然後執行下一頁。
d.乙太網路裝置挑選目前的網卡名稱。
提供者名稱則可以自己任意為這個連線命名
帳號類型在此則不要挑選
登入名稱/密碼,則依中華電信給您的帳號及密碼就可以。
完成後點選下一頁並選擇套用。


e.當設定完連線資訊,點選該連線想要啟動連線時,會發現『啟動』按鈕竟然是關閉
的。我們在該連線點兩下以開啟組態設定。


f.在此,僅需將 NetworkManager 取消,並按確定之後,就可以出現『啟用』按鈕。

2009年5月25日 星期一

兩者中都有型別的錯誤問題

兩者中都有型別的錯誤問題

在 VS2005 執行重建專案時,跑出一堆如下的錯誤訊息。


錯誤 13
d:\ItriWeb\ProjMng\ProjMng\ProjMngWeb\plan\dialog_EditOutComeType.aspx.cs(33): error CS0433: 
'c:\...\Temporary ASP.NET Files\projmngweb\70148ad8\4f87a4e0\App_Web_zc0mxaol.dll' 和 
'c:\...\Temporary ASP.NET Files\projmngweb\70148ad8\4f87a4e0\App_Web_3u5qu2vi.dll' 
兩者中都有型別 'MasterPage_Plan'
D:\ItriWeb\ProjMng\ProjMng\ProjMngWeb\codetbl\dialog_EditEmpnoList.aspx 1


google 了一下,看看有沒有跟我同樣遭遇的網友,
MSDN 找到一篇類似的文章,
自己也依照建議步驟,執行了

  1. 先執行 iisreset 把 IIS 重新啟動
  2. 關閉 Visual Studio 2005
  3. 把 c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files 
    目錄下所有目錄刪除掉 

但還是無效。

回頭檢視自己專案,發現當初在設計時,
將 階段 A ,階段 B , 階段 C 的程式都分別放在三個資料夾下。
這三個階個別都有自己的 MasterPage。

VS2005 預設在 .aspx 頁面,當你取好檔案名稱後,會自動幫你產生對應的 .cs 檔。在 .cs 檔裡,
就會產生如下程式。


using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class MasterPage_Plan : System.Web.UI.MasterPage
{

}



MasterPage_Plan 這個類別名稱,也是 VS2005 幫我們取的。這就是問題的癥結。因為我三個階段都是
以資料夾來分的,每個資料夾又有自己的 MasterPage。而很幸運的,VS2005 幫我自動命名的類別名稱
都剛好一樣,所以造成命名的混淆。所以,當我手動將物件類別名稱改名,再重建專案之後,就正常了。

2009年5月21日 星期四

SQL2005資料分割範例


/*
分割範例-建立 TranLog 資料表 
*/

CREATE TABLE [dbo].[TranLog](
[TID] [bigint] IDENTITY(1,1) NOT NULL,
[TCreate] [datetime] NULL,
[TStatus] [nvarchar](50) NULL,
 CONSTRAINT [PK_TranLog] PRIMARY KEY CLUSTERED 
(
[TID] ASC
)WITH (PAD_INDEX  = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]


/*
  TranLog 資料表新增預設資料,2007 年度 60 筆, 2008 年度 60 筆 , 2009 年度 60 筆
*/


declare @datetime datetime
set @datetime=getdate()
set @datetime=DateAdd(yy,-2,@datetime)

declare @items int
set @items = 60

while(@items>0)
begin
set @datetime=DateAdd(d,1,@datetime)
insert into TranLog (TCreate,TStatus) values (@datetime,'OK')
set @items=@items-1
end

set @datetime=DateAdd(yy,1,@datetime)
set @items = 60

while(@items>0)
begin
set @datetime=DateAdd(d,1,@datetime)
insert into TranLog (TCreate,TStatus) values (@datetime,'OK')
set @items=@items-1
end

set @datetime=DateAdd(yy,1,@datetime)
set @items = 60

while(@items>0)
begin
set @datetime=DateAdd(d,1,@datetime)
insert into TranLog (TCreate,TStatus) values (@datetime,'OK')
set @items=@items-1
end


select * from TranLog


/*
   Demo 
*/


--Partition Function的名稱,及要分割條件
CREATE PARTITION FUNCTION pf_TranLog_Date (datetime)   
AS RANGE RIGHT 
FOR VALUES (convert(datetime,'2008 01 01'), convert(datetime,'2009 01 01'))  



CREATE PARTITION SCHEME ps_TranLog_Date        --建立Partition scheme 
AS PARTITION pf_TranLog_Date                   --依所建立的Partition function設定分割點 
TO (TranLog_FG_2007, TranLog_FG_2008, TranLog_FG_2009)   --將Partition scheme指定給三個filegroup 
GO 


-- Create partitione table     --建立Partition Table 
CREATE TABLE TranLog_Partitioned
   TID int IDENTITY(1,1) NOT NULL, 
   TCreate datetime NOT NULL,    
   TStatus nvarchar(50)  NULL 
ON ps_TranLog_Date(TCreate) 
GO 

-- 將原本 TranLog 的資料匯入到  TranLog_Partitioned 分割資料表
insert into TranLog_Partitioned ( TCreate,TStatus )
select TCreate , TStatus from TranLog

select * from TranLog
select * from TranLog_Partitioned



-- 建立  對照組 資料表 (不建任何索引 不切割)
CREATE TABLE TranLog_NoAnyThing
   TID int IDENTITY(1,1) NOT NULL, 
   TCreate datetime NOT NULL,    
   TStatus nvarchar(50)  NULL 

--將 TranLog 資料匯入到 對照資料表 TranLog_NoAnyThing
insert into TranLog_NoAnyThing ( TCreate,TStatus )
select TCreate , TStatus from TranLog



/*  使用【顯示估計執行計畫】分析以下資料 */

-- 查詢條件:  不設定
select * from TranLog 
select * from TranLog_Partitioned  
select * from TranLog_NoAnyThing 

--查詢條件: 日期 大於 20090401
select * from TranLog  where TCreate  < convert(datetime,'2008 01 01')
select * from TranLog_Partitioned  where TCreate < convert(datetime,'2008 01 01')
select * from TranLog_NoAnyThing  where TCreate < convert(datetime,'2008 01 01')

--查詢條件: By ID
select * from TranLog  where TID  =1  
select * from TranLog_Partitioned  where TID  =1 
select * from TranLog_NoAnyThing  where TID  =1 

-- 查詢條件:  By ID  + 日期小於 20080101
select * from TranLog  where TID  =1 and TCreate  < convert(datetime,'2008 01 01')
select * from TranLog_Partitioned  where TID  =1 and TCreate  < convert(datetime,'2008 01 01')
select * from TranLog_NoAnyThing  where TID  =1 and TCreate  < convert(datetime,'2008 01 01')



/*
 讓每個 Table 各增加 9 萬筆,提升資料量後再重新分析一次
 */


declare @iCount int
set @iCount=30000


declare @tDate datetime
set @tDate = convert(datetime,'2007 04 01')

while (@iCount>0)
begin
insert into TranLog (TCreate,TStatus) values (@tDate,'OK')
insert into TranLog_NoAnyThing (TCreate,TStatus) values (@tDate,'OK')
insert into TranLog_Partitioned (TCreate,TStatus) values (@tDate,'OK')
end

set @iCount=30000
set @tDate = convert(datetime,'2008 04 01')
while (@iCount>0)
begin
insert into TranLog (TCreate,TStatus) values (@tDate,'OK')
insert into TranLog_NoAnyThing (TCreate,TStatus) values (@tDate,'OK')
insert into TranLog_Partitioned (TCreate,TStatus) values (@tDate,'OK')
end

set @iCount=30000
set @tDate = convert(datetime,'2009 04 01')
while (@iCount>0)
begin
insert into TranLog (TCreate,TStatus) values (@tDate,'OK')
insert into TranLog_NoAnyThing (TCreate,TStatus) values (@tDate,'OK')
insert into TranLog_Partitioned (TCreate,TStatus) values (@tDate,'OK')
end


2009年5月20日 星期三

SQL 2005 資料分割 (Partition)

SQL 2005 資料分割 (Partition)

想要對資料表進行切割動作,翻閱一下 SQL 的線上說明文件,在 create table 陳述式裡可以找到這一段 :

CREATE TABLE
    [ database_name . [ schema_name ] . | schema_name . ] table_name
        
( { <column_definition> | <computed_column_definition> }
     [ <table_constraint> ] [ ,...n ] ) 
[ ON { partition_scheme_name ( partition_column_name ) | filegroup
| "default" } ]
[ { TEXTIMAGE_ON { filegroup | "default" } ]
[ ; ]


可以注意黃色醒目背景的地方,在 CREATE TABLE 指令就可以設定資料分割的動作了。

ON { partition_scheme_name ( partition_column_name ) }
裡面的 partition_scheme_name ,是指當我們如果需要建立一個切割資料表時,
需要明確定義這個資料表是要根據何種方式來切割。而這個定義,稱為 partition schema
也就是說,資料切割只需要在 create table 指令加上 partition schema 的名稱就可以了。

此外,也要宣告一個切割時所要依據的欄位。譬如說,你希望未來資料切割方式是根據你的日期欄位來切,
2007 年 放一塊,2008 年放一塊 ,2009年放一塊,那就要將日期欄位指定為切割所依據的欄位了
(partition_column_name )。

很可惜,事情不是這樣就結束了。因為殺出一個程咬金 partition schema 出來,那要怎麼去產生這個
partition schema 呢?

也是一樣,翻一下SQL 的線上說明文件,在 create partition schema 說明裡,有以下一段:


CREATE PARTITION SCHEME partition_scheme_name
AS PARTITION partition_function_name
[ ALL ] TO ( { file_group_name | [ PRIMARY ] } [ ,...n ] )
[ ; ]


原來,要產生 partition schema ,有兩個步驟要做,
第一:產生 partition function
第二:指定 file group

首先,產生 partition function。線上說明文件有提到:

CREATE PARTITION FUNCTION partition_function_name ( input_parameter_type )
AS RANGE [ LEFT | RIGHT ]
FOR VALUES ( [ boundary_value [ ,...n ] ] )
[ ; ]

input_parameter_type:
是指用來切割時依據欄位的資料格式,如果是用日期的話,這裡就要用 datetime
boundary_value:
是指切割的臨界值。如果希望將資料切割成 2007年 、 2008年 、2009年 三份的話,就必須切兩次,依據  20080101  與 20090101  就可以讓資料依年度分為三類,而boundary_value 就是指20080101 與 20090101。當然,因為是屬於datetime 欄位,所以實際上我們要將輸入的參數轉型為適當型別。以我們的範例來說,就需要改成  convert(datetime,'2008 01 01'), convert(datetime,'2009 01 01')
LEFT | RIGHT:
剛剛有提到的臨界值,如果這麼恰巧,有一個日期  就是 20080101  ,那我們會希望這臨界值放在臨界值左邊還是右邊?就要用 LEFT 或 RIGHT 來設定。以我們的範例,20080101 當然是希望放在他的右邊囉,因為它的左邊都是 2007 年的,右邊才是 2008 年。


接著,產生 file group。
我們嘴裡喊著要將資料表做切割,雖然表面上看起來,我們存取的是一個資料表,但實際上,因為我們的切割,他會根據我們切割的
規則而分別存放在各個檔案裡。以我們的範例來說,根據 20080101 與 20090101 的分割法則,會產生三個資料區塊:
資料<2008 ,  2008<= 資料  < 2009 , 2009<=資料 。實際上,就需要產生三個不同的檔案來存放。而每個檔案要對應一個檔案群組,
所以我們同時也需要產生一個檔案群組給每一個檔案。

產生檔案群組方式:

ALTER DATABASE TestDB ADD FILEGROUP fg_date_1 

很簡單,只要  ADD FILEGROUP 就可以了。


產生檔案的方式:

ALTER DATABASE TestDB  
ADD FILE  
( NAME = TDate1, 
 FILENAME = 'c:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Data\TranDate1.ndf', 
 SIZE = 1MB, 
 MAXSIZE = 100MB, 
 FILEGROWTH = 1MB) 
TO FILEGROUP fg_date_1 


NAME 是指定檔案的名稱
FILENAME 是檔案實體名稱,預設都會放在c:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Data\ 下面,後面就是我們自己對實體檔案的命名
FILEGROUP 是指定對應的檔案群組


當我們完成上述所有步驟之後,就可以產生一個具有分割特性的資料表。以後所有 insert 到這資料的資料,就會根據分割原則存放在所分配的實體檔案裡。





2009年5月16日 星期六

jQuery in select

針對 < select > 挑選物件 ,比較一下 javascript 與 jQuery 的差別。假設要挑選 物件 select (id="s1") 裡的第三個選項。javascript 會寫成

document.getElementById("s1").value=3

但 jQuery 只要寫

$("#s1").val(3)

真的簡潔多了。




此外,如果自己想 try jQuery 語法又不想大費周章的去建立網頁的話,可以試試黑暗執行緒所提供的測試網頁 mini jQuery Lab ,蠻方便的。

2009年5月14日 星期四

jQuery UI 對話視窗


javascript 內建的 alert 視窗按鈕選項,只有【確定】、【取消】兩個。但偏偏我的客人執意要【是】、【否】、【取消】。以前我可能會告訴她做不到,但時下景氣這麼差,只好找些替代方案來取悅人家了。

在 jQuery 1.3 版後,同時 jQuery UI 也發佈了 1.7.1 版本。在這新的 jQuery UI 裡,widgets >> Dialog 所內建的對話盒真的漂亮許多,且她提供的 Modal Dialog  模式剛好可以取代原先 alert 的效果,也可以自訂 Buttons。


可自行到 Download 頁籤下載,壓縮檔解開後,/css 與 /js 資料夾是程式開發所必要的。可以將這兩個資料夾複製到自己開發的專案下面。接著要介紹的,就是自己撰寫一個使用 jQuery UI Dialog 的程式。


< script type="text/javascript" > 
$.ui.dialog.defaults.bgiframe = true;
$(function() {
$("#dialog").hide();
$("#dialog").dialog({   buttons:{
"取消":function(){  $("input[id*=h_DeliverType]").val('0'); $(this).dialog("close");},
"否":function(){  $("input[id*=h_DeliverType]").val('2'); $(this).dialog("close"); },
"是":function(){  $("input[id*=h_DeliverType]").val('1'); $(this).dialog("close"); }       
},
modal: true,
autoOpen: false,
close: function(event,ui){alert('使用者按 X 離開視窗');}

});  
});

function ShowDeliverDialog()
{
$('#dialog').dialog('open');
}

< /script >

< /head >
< body >
< div class="demo" > 

< div id="dialog" title="對話視窗"> 
如果您要吃披薩,請按 '是' ,如果不要吃披薩,請按 '否'。如果目前不想選擇,請按 '取消'。
< /div >




在測試頁面,先置放一個 id=dialog 的 div,當作我們對話視窗的說明文字,title 屬性則是對話視窗最上層會顯示的文字。我希望這個對話視窗內容,是要在 User 壓了 button 按鈕後才出現,所以預設會用  jQuery 的 .hide() 方法將他隱藏。jQuery UI 的 Dialog 有一個 Options 選項叫做 buttons ,你可以在這裡定義自己所要新增的 button 以及這個 button 所要觸發的事件。modal 屬性設為 true ,則表示這個對話視窗是以獨占方式顯示,其背景物件都會以暗化來處理。autoOpen 屬性設為 false ,則是因為我們不希望對話視窗在頁面一載入就跳出,而是要等按鈕觸發後才跳出。

完成設定後,就會跟上圖結果一樣了。

補充: 20091202
在程式裡面加上 攔 close 的事件,也就是當 user 按了視窗右上角的 X 符號離開視窗時會觸發的事件。

$('.selector').dialog({
   close: function(event, ui) { ... }
});

參考網址:http://jqueryui.com/demos/dialog/#event-close  「請選擇 Events 頁籤」

2009年4月4日 星期六

努力休息


就身體結構而言,休息的期間才是真正在修補、重建的時機。而我們在運動、勞作期間,對身體來說,都是在破壞、消耗。

很少人真正了解休息所帶給我們生理上的益處,尤其是睡眠。在睡眠當中,身體會釋出生長激素來修補日間訓練所造成的損傷,並且支撐住因訓練而衰弱的任何系統(註一)。這個觀點我很肯定,因為小時常常熬夜看書,沒有分泌到生長激素,唉~ 。不知道現在還會不會分泌?


眼下有許多人,包括我自己,都有著數字迷思,今天 5 公里,明天 6 公里,後天 7 公里 ....。多跑多健康,有騎有保庇。可是我們都不知道,如此強大的破壞力道,身體的復原是否跟的上腳步。如果跟的上,你就會得到阿諾的『胸肌』;如果跟不上,你就會有一雙『天殘腳』。



所以別忘囉!要努力休息~






※註一:出自『鐵人三項訓練聖經




延伸閱讀:

2009年4月2日 星期四

與 jQuery 的第一次相遇




剛開始接觸人氣指數很高的 jQuery 時,難免會跟這陌生的人氣王有著大家都會想問的問題。就如同去參加聯誼時,大家老是脫離不了問對方姓名、興趣、假日都在做些什麼...?


第一個問題:為何要將程式放在 $(document).ready( ) 裡?
當網頁被開啟時,頁面上可能同時放置了許多同片、Banner...等等,這時如果使用 javascript去執行,可能會發生頁面上的物件都還沒完全下載就被存取的問題發生。所以,以往在 javascript 都會用以下方式避免:

window.onload = function(){ alert("welcome"); }

在jQuery,則是使用:


$(document).ready( function()
{
// ... your code
});


可參考:http://docs.jquery.com/How_jQuery_Works

第二個問題:以 $( ) 包起來的標記代表什麼意思?
在jQuery,以 $( ) 標記表示所謂的選取元素( Selectors) 。舉例來說,在 JavaScript 要抓取一個 ID 為 tbx_Account 的物件,會用 document.getElementsById("tbx_Account"),但在 jQuery 只需要使用 $("#tbx_Account") 就可以了。

列舉常用的例子:
$("a"); // 取得頁面中所有的<a>標籤元素
$("#tbx_account"); // 取得id為tbx_account的元素
$(".UsrDefine"); // 取得class name為UsrDefine的所有元素
$('#container a'); // 取得id為container之元素其內部的所有連結
$("div > p"); // 取得div父元素其下所有的p子元素
$("tr:first"); // 取得第一個找到的tr標籤元素
$("tr:even"); //取得所有 tr 標籤元素的偶數集合
$("tr:odd"); //取得所有 tr 標籤元素的奇數集合
$("input[name='account']"); // 取得其name屬性值為account的input元素
[注意] 使用 指定屬性方式時,記得中括號與前方的指定類別不可留空白


[補充] :具有AND 與 OR 的效果。
AND : $("  table tr td span "); // 這就會去找 在 table下  且  在 tr 下   且在  td 下  的 span
OR: $("div , span"); // 這就會去找  div  或  span
[補充]:如果您取得的結果是個多項目的集合,若要取得這集合裡的項目數,可以使用 .size() 來取得。
範例:alert($("input[name=pet]:checked").size());

[補充]:如果畫面上有好多 TextBox,你想要統計 TextBox 目前有值的數目,可以使用下面的語法:
alert($("input[id$=tbx_psd_carstyleno1][value!='']").length );

這裡連續使用了兩次指定屬性的方式,表示這屬性的條件可以讓我們用 And 的方式一直增加。而 value 其實也是 input 的屬性的一部分,而  !=''  是用來找出不是空白的項目。


第三個問題:什麼是 chaining (串接)?
參閱jQuery的屬性[http://docs.jquery.com/Attributes],發現大部分屬性的回傳值都是 jQuery物件。舉例來說:

$("#container").css("color", "blue") --> 回傳 jQuery

$("#container").css("background-color", "red") --> 回傳 jQuery

當設定完第一個屬性後,回傳了一個 jQuery 物件,如果我們把這個回傳物件繼續加以使用,就不須要像第二行指令這樣從頭再指定 $("#container") 了,而是接在第一行屬性設定的後面。這種作法可以大大減少程式設計師重複撰寫相同的程式。

第四個問題:怎麼加入事件( event ) ?
網頁上的控制項,免不了要去撰寫 blur( ) 、 click( )、change( ) ... 相關事件。查閱 jQuery 的 Event , click ( )  與 click ( fn ) 都是成對出現的,同樣的情況也出現在 blur( ) , change( ) ...。這其中的差異,就是 click ( ) 是去觸發 「點選」動作的事件,click ( fn) 則是去撰寫 「點選」動作後要做的事情。

舉例來說:今天需要判斷一個ID為 tbx_Account 的文字輸入對話盒物件是否為空,則可以用以下語法來完成:


$(document).ready(function() {
$("#tbx_Account").blur(function()
{
if(!this.value)
{
alert("Please enter some text!");
}
else
{
alert(this.value);
}
})
});


在tbx_Account,去實作 blur 事件觸發時要執行的動作。同時使用了 this.value 去抓目前這個物件的值,來判斷 user 是否有輸入資料。

第五個問題:如何使用 Ajax ?
提到 Ajax 時,以前針對不同的瀏覽器,宣告 XMLHTTP 的方式會不同。但 jQuery 把這些繁瑣的工作自動幫我們處理好了。只需要使用 jQuery 提供的方法即可完成。

以一個簡單例子來說明:


<html>
<body>
<form id="form1" runat="server">
<div>
Get Now Date:<span id="spTime"></span>
</div>
</form>
</body>
</html>


我們希望 <span>: spTime 標籤會去呼叫一支自動回傳現在時間的 AjaxGetTime.aspx 。則在jQuery 可以用下面寫法:


<script>
$(document).ready( function(){
$("#spTime").load("AjaxGetTime.aspx");
});
</script>


的確,只需一行 .load( ) 就可以完成 Ajax 的使用。
完整的 .load( url, data, callback)  語法裡,
url: 是指所叫用的遠端程式網址,是必填的參數。
data: 則是當你在呼叫遠端程式時,有需要進一步傳其它參數時使用。它可以是 key / value 成對出現或是字串( jQuery Ver:1.3  開始支援)。
callback: 則是當遠端程式完成後,接著要執行的程式。這裡的 callback 名稱取的好,「呼叫(遠端程式)回來後(要做的事情)」。不管成功或失敗都會執行。


擷取 jQuery 官網上的一段 code 來參考 .load(url, data, callback ):


$("#feeds").load("feeds.php", {limit: 25}, function(){
alert("The last 25 entries in the feed have been loaded");
});



如果簡單的 .load( ) 不能滿足您的需求,可以進一步去參考 .get( ) 、.post( ) 語法。
延伸閱讀:http://webdesign.enjoyitsimply.com/jquery/jquery_ajax [中文]

第六個問題:為什麼一定非 $ 不可?
在使用 jQuery 時,常常會以 $ 符號當作開始,而這 $ 符號,其實是 jQuery 的縮寫。如果你不想使用縮寫,直接打 jQuery 也是可以的。

舉例來說:

$("#tbx01").val('aa');
jQuery("#tbx01").val('aa');

這兩行的指令是功能是一樣的。

另外,如果你的程式除了 jQuery 之外,還有使用其他如:Prototype, MooTools, YUI 程式,可能別的程式已經用 $ 當作他們程式的縮寫,這情況就很容易造成混淆。所以,你可以使用 jQuery.noConflict();  來宣告以下程式要使用 jQuery ,而不是其他的。

<script>
 jQuery.noConflict();
 
 // Use jQuery via jQuery(...)
 jQuery(document).ready(function(){
   jQuery("div").hide();
 });
 
 // Use Prototype with $(...), etc.
 $('someid').hide();
</script>

或許能夠用比較簡短的縮寫,是比較吸引人的。於是可以用以下方法,讓 $j 來代替原先的 $。

var $j = jQuery.noConflict();

所以程式就可以寫成:

<script>
 var $j = jQuery.noConflict();
 
 // Use jQuery via $j(...)
 $j(document).ready(function(){
   $j("div").hide();
 });
 
 // Use Prototype with $(...), etc.
 $('someid').hide();
</script>

參考來源:
1.http://blog.wu-boy.com/2008/09/22/412/
2.http://docs.jquery.com/Using_jQuery_with_Other_Libraries
3.http://jsgears.com/thread-63-1-1.html

2009年3月24日 星期二

Page and Extent In SQL Server

在SQL Server 裡,最基本的儲存單位為 page。當一個新 Table 被建立時,就會在硬碟裡建立一塊以 8K 的連續空間,以便儲存我們想要保留的資料。這 8K 的連續空間,正是 SQL Server 的基本儲存單位: Page。當這 8K 的空間用完時,又會自動再產生一個 8K 的新 page。

如右圖所示,每個 page 最前面會先放一個 96 byte 的 Page header,在 Page header 裡頭紀錄了 page number, page type, page 剩餘空間, 以及配置單位編號。

page number 的分配是由 0 - 7,因為每 8 個 page 在 SQL Server 裡就會被視為一個 Extent。

page type 則是定義了以下格式:Data, Index, Text/Image, Global Allocation Map, Shared Global 
Allocation Map,Page Free Space, Index Allocation Map, Bulk Changed Map, Differential Changed Map。

Data row 則是緊接在 Page header 的後面。而放在最後面的則 Row offsets。Row offsets 它擺放的順序是從頁尾開始,主要是記載著每個 Data row 它離頁首的距離。

雖然 page 是最基本的儲存單位,但 SQL Server 為了在空間管理上更有效率,它將 8 個連續的 page 空間 ( 64 K) 視為一個 Extent。但如果你的資料量很小,則 SQL Server 就不會主動幫你建立一個 Extent。

Extent 因裡面 8 個 page 的型態,而有 Uniform extents 與 Mixed extents。簡言之,如果你的 8 個 page 都是同一個型態,則稱為  Uniform extents ,反之則為  Mixed extents。

以上圖為例, Mixed extent 裡頭 同時包含了 table2, table3, index1, index2, index3 等等的混何型態,所以稱為 Mixed extent。而 Uniform extent 裡面的 8 個 page 則都是 table1。





文獻參考:

2009年3月20日 星期五

動態置換 Master Page

在 .Net 2.0 提供了 Master Page 功能,可以讓我們將事先定義好的樣板快速的套用在各個開發頁面。接下來要介紹的,是讓一個頁面可以透過程式動態的去變更頁面的 Master Page。

舉個例子來說,我們設計了兩個 Master Page,一個叫做 MTeacher.master (專門提供給老師看的樣板),另一個叫 MStudent.master(專門提供給學生看的樣板)。當檢視我們頁面的使用者是老師時,就要選用 MTeacher.master,當視我們頁面的使用者是學生時,就要選用 MStudent.master。

直覺的,很像可以在程式裡直接去設定  MasterPageFile ,如下所示:


protected void Page_Load(object sender, EventArgs e)
{
MasterPageFile = "MTeacher.master";
}

但回傳的結果卻是:
'MasterPageFile' 屬性只能在 'Page_PreInit' 事件內或之前設定。

根據錯誤訊息的提示,如果要設定 MasterPageFile ,必須要在 Page_PreInit 事件執行才可以。所以,改採用 覆寫 Page_PreInit 事件,應該就可以了。動手改一下程式如下:

protected override void OnPreInit(EventArgs e)
{
MasterPageFile = "MStudent.master";
string strType = "" + Request["isTeacher"];

if(strType=="1")
MasterPageFile = "MTeacher.master";


base.OnPreInit(e);
}


為了簡單起見,透過 URL 參數 isTeacher 來決定登入者角色是否為老師。 當 isTeacher 是 1 時,即表示目前是老師在檢視頁面;如果不是 1 ,則為學生。程式修改後,就可以正確的呈現出我們所希望的樣子了。

當你有需要更換 MasterPage 樣板時,記得要覆寫 Page_PreInit 事件,並在這事件裡完成你的程式。

2009年3月16日 星期一

為什麼我的 Button 沒有呼叫 __doPostBack

一如往常所見,檢視網頁原始碼時,可以找到 __doPostBack 的 JavaScript 宣告。同時包含著兩個 hidden 欄位的宣告: __EVENTTARGET, __EVENTARGUMENT。


<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />

function __doPostBack(eventTarget, eventArgument) {
if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
theForm.__EVENTTARGET.value = eventTarget;
theForm.__EVENTARGUMENT.value = eventArgument;
theForm.submit();
}
}

__EVENTTARGET 用來儲存是誰觸發了 PostBack。
__EVENTARGUMENT 則是用來儲存這次的 PostBack 是否有其它參數須一併傳遞。

以 DropDownList 為例,在網頁放置一個 DropDownList 後,它的原始碼變為

<select name="DropDownList1" onchange="javascript:setTimeout('__doPostBack(\'DropDownList1\',\'\')', 0)" id="DropDownList1">
<option value="A">A</option>
<option value="B">B</option>
</select>

當你的 DropDownList 的挑選項目被更動之後,就會觸發__doPostBack( )。eventTarget指的是造成發生PostBack的控制項是誰?而 eventArgument則是觸發PostBack同時,是否有其他參數需要傳遞。
在範例中,當發生PostBack時,就可以知道造成PostBack的就是 DropDownList1 ,而此次並沒有其他參數傳遞,所以是空字串。__doPostBack( ) 此時會將2個隱藏欄位(__EVENTTARGET,__EVENTARGUMENT)作一次更新後再將本頁面送出(Submit)。透過這種機制,送出後新載入的頁面,就可以透過
string strTarget = ""+Request.Form["__EVENTTARGET"];
來取得觸發PostBack的物件是誰了。
 

然而,這種機制並不適合 ButtonImageButton 兩個控制項。
現在再拉一個Button控制項並檢視它的原始碼。

<input type="submit" name="Button1" value="WebControl" id="Button1" />

可以看到Button的原始碼並沒有去呼叫__doPostBack( )。而先前提到的兩個隱藏欄位 __EVENTTARGET,__EVENTARGUMENT 也就不會被更新,當頁面送出後,還可以透過 Request.Form["__EVENTTARGET"] 去抓到觸發 PostBack 的控制項是誰嗎?試著測試一下,您會發現得到的是空白。所以,為何 Bubbon 或 ImageButton 在 PostBack 之後的頁面無法透過 Request.Form["__EVENTTARGET"] 抓到值,主要是它產生的程式碼裡並非透過 __doPostBack( )來實作,也沒有留下紀錄到 __EVENTTARGET 隱藏欄位裡頭,所以才會抓不到資料。
 

雖然 Button 或 ImageButton 沒有辦法讓送出後的頁面抓到 __EVENTTARGET 的值,但可以有其他的選擇。捨棄 Sever Control 改用 Html Control。在 VS(Visual Studio) 的工具箱裡,選擇 HTML 的群組,拉一個 HTML Button 控制項出來,同時將這個控制項的屬性設定為【以伺服器控制項執行】(其實就是設定 runat="server"),接著在 HTML Button 快點兩下,以產生 onserverclick 事件。做完這些動作後,檢視程式碼可以發現如下的改變:

<input language="javascript" onclick="__doPostBack('IamHtmlButton','')" name="IamHtmlButton" type="button" id="IamHtmlButton" value="HtmlControlinServer" />

這個HTML Button 使用了 __doPostBack( ) ,不意外的,我們可以在送出後的頁面抓到 __EVENTTARGET 裡面所記錄的值,就是這個 HTML Button。
 

參考資料:
[1]Understanding the JavaScript __doPostBack Function
[2]藍色小舖

2009年1月9日 星期五

Server端註冊client端的Javascript

在ASP.net ,如果從 server 端想在 client 端註冊 Javascript,可以使用

RegisterStartupScript(keyscript)


RegisterClientScriptBlock(keyscript)




雖然都可以達到註冊 Javascript 的目的但他們實際上是有所差異的。




RegisterClientScriptBlock( ),他會將我們自訂的 JavaScript 產生在
<form runat="server"> 標籤之後,你可以在檢視網頁原始碼

時看到他。





RegisterStartupScript( ),則是產生在 </form> 標籤之前。

產生的先後順序,會造成影響的地方,在於觸發 Client 端 JavaScript
的時機。 假設你有一個 JavaScript 要將滑鼠游標停駐在某一個 TextBox,
如果你將 JavaScript 放在 <form runat="server">之後,則 TextBox 
的 HTML Code 尚未來得及產生,卻硬是要去設定游標位置,這時就會出現
JavaScript的錯誤。在這情況裡,選擇 RegisterStartupScript 會是個合適的
選擇。

參考網址:http://msdn.microsoft.com/en-us/library/aa478975.aspx
(Injecting Client-Side Script from an ASP.NET Server Control)