2010年3月31日 星期三

在自訂類別裡存取使用者頁面 URL 資訊

在 asp.net ,如果你在 .aspx.cs 頁面要取得目前頁面 url 的資訊,可以透過 Request.Url 。但如果你的程式是那種很有架構性的,也就是分了好幾層,如 MVC 之類,你可能有時候偷懶,希望在底層自己定義的類別裡,也想要抓取使用者目前頁面的 URL 資訊,這時候,Request.Url 就失效了。這時,你可以透過以下程式來完成 :

HttpContext.Current.Request.Url

HttpContext 是 .Net Framework 一個重要類別,他封裝了有關 HTTP 請求的所有 HTTP 特定的訊息。所以透過 HttpContext ,我們可以取得最原始的 HTTP 相關資訊。

參考:http://www.ourys.com/post/109.html

2010年3月18日 星期四

重新指定 SQL 自動編號

SQL Server 的資料欄位型態如果有設定為 IDENTITY,可以省下我們為資料編號的力氣。但如果你想要保留現有資料,且新資料要從指定的號碼開始編(例如:10000 開始),那可以使用下面三行指令來完成:

--關閉自動編號

SET IDENTITY_INSERT tmp_table ON  

--重新指定自動編號起始位置
DBCC CHECKIDENT (tmp_table, reseed, 10000)

--開啟自動編號
SET IDENTITY_INSERT tmp_table OFF 




參考:http://www.dotblogs.com.tw/chhuang/archive/2008/04/18/2944.aspx

2010年3月5日 星期五

jQuery 民國年日曆

遇到有日期欄位的需求時,常常都會需要在旁邊加個小日曆以供挑選,這小日曆其實不難在網路上找到相關的免費又好用的程式。但是如果要強調以民國年來顯示,雖然知道一定會有人寫,但要找到好用又夠用的,還真的要花些時間。

就是因為找了好多炷香的時間,所以不得不將自己認為還不錯的日期挑選程式記錄下來。在羅必達工作室,我看到一篇 「jQuery DatePicker 日期選擇(民國年)」的文章,寫的真的很棒。如果對於作者開發的來龍去脈有興趣的話,可以進一步去參考他的文章。

擷取執行畫面如下:















程式下載網址:
1.原站台
2.備份



測試程式:
<script type="text/javascript">
$(function() {

  //設定 tbx_DateNeed_start 為日期挑選欄位
  $('input[id*=tbx_DateNeed_start]').datepicker({
      dateFormat: 'yymmdd', 
      showOn: 'button', 
      buttonImageOnly: true, 
      buttonImage: '../images/calendar.gif',
      formatYear:function(v){return '民國'+(v-1911)+'年';}        
      });          
});
</script>           

2010年3月4日 星期四

jQuery 的 extend 與 fn.extend 差別

使用擴展的好處,是讓你透過 jQuery 去定義原先不存在的功能,方便你擴充 jQuery 既有的功能。在探討 jQuery 的擴展功能時,也因此就會分為兩類:靜態全域 ,或 需依附於元素。

  1. 靜態全域 (jQuery.extended)
    定義後,只需使用 jQuery 的前置符號就可以使用。
  2. 需依附於元素(jQuery.fn.extend)
    定義後,只針對 jQuery 所選取的元素有效。
我引述西風瘦馬所提供的程式來介紹:

jQuery.extended
所定義的 add 方法, jQuery 任何時候都可以叫用。
<script>
jQuery.extend({
    add: function(a, b) {
        return a + b;
    }
});

alert($.add(3, 4)); //7
</script>

jQuery.fn.extend
所定義的 red 方法,必須是某個 jQuery 所挑選到的元素才能使用。如範例,符合 $('#test') 的所有元素,都可以執行 red( )。
<script>
jQuery.fn.extend({
    red: function() {
        return $(this).css('color', '#ff0000');
    }
});

$('#test').red();
</script>

上述所介紹,都是針對 jQuery 原先所沒有的功能而進行新增。但有個問題來了,假設如果原先就已經存在了某個方法 add( ),但擴展的方法也同樣有個方法 add( ),那不就鬧雙包?接下來的問題,則是要以誰的為主?是元配,還是新歡呢?通常都是只見新人笑,不見舊人哭囉~在 jQuery 官網上可以找到這問題的處理方式。

情況一:合併兩個物件,後面的物件內容會覆蓋前面的物件內容
var object1 = {
  apple: 0,
  banana: {weight: 52, price: 100},
  cherry: 97
};
var object2 = {
  banana: {price: 200},
  durian: 100
};

$.extend(object1, object2);

//結果
object1 === {apple: 0, banana: {price: 200}, cherry: 97, durian: 100}


情況二:合併兩個物件,後面物件內容裡的詳細屬性會覆蓋前面內容裡的詳細屬性(若前面內容裡的詳細屬性沒有重複,會被保留下來,也可視為深層合併)

var object1 = {
  apple: 0,
  banana: {weight: 52, price: 100},
  cherry: 97
};
var object2 = {
  banana: {price: 200},
  durian: 100
};

$.extend(true, object1, object2);

//結果
object1 === {apple: 0, banana: {weight: 52, price: 200}, cherry: 97, durian: 100}

情況三:合併兩個物件,但不會影響到這兩個物件的預設值。這是常見的 plug-in 開發模式作法。
var empty = {}
var defaults = { validate: false, limit: 5, name: "foo" };
var options = { validate: true, name: "bar" };
var settings = $.extend(empty, defaults, options);

//結果
settings == { validate: true, limit: 5, name: "bar" }
empty == { validate: true, limit: 5, name: "bar" }


綜合以上三個範例,

如果你想要對合併物件進行深層的物件合併,要在第一個參數加上 true
如果你不想影響2個合併物件的預設值,要採用情況三的開發模式
而其他,就是後面物件蓋掉前面物件了

參考:
1. http://blog.tugai.net/2009/07/22/jquery-fn-extend/
2.http://www.cnblogs.com/rhythmK/archive/2009/10/19/1585847.html
3.http://hzjavaeyer.group.javaeye.com/group/blog/232971
4.http://api.jquery.com/jQuery.extend/

2010年3月3日 星期三

網頁除錯工具 firebug

FireFox 提供了一個外掛的 plug-in 軟體:firebug 。可以透過它對網頁上的 javascript 進行除錯工作,甚至可支援 javascript 的單步執行除錯。在除錯過程中,也可以隨時顯示每個變數目前的數值狀況。相信對於網頁上複雜的 javascript 撰寫會有很大的幫助。


推薦幾個不錯的介紹網址:

http://blog.wu-boy.com/2010/01/05/1943/

http://caterpillar.onlyfun.net/Gossip/AjaxGossip/FireBug.html

http://getfirebug.com/enable

自己實際下載後,試著執行一段簡單的 code :

<script>
var a = "test";
console.log("a is %s ", a);
</script>

沒想到就出現 『主控台 panel is disabled』的訊息。


還好,原來是 firebug 預設就會關閉 主控台 的功能。只要去將主控台的下拉點選下去,並挑選 Enabled ,就可以正常執行了。


常用指令:
1. console.log();   將變數的值輸出到主控台
2. debugger;  開始 單步除錯

2010年3月2日 星期二

GridView 的 Sorting (排序) 、Paging(分頁) 與 DataSourceID 的關係

在 VS2005 提供了 GridView 控制項,一般的工具書都會介紹 GridView 控制項搭配 SqlDataSource 來介紹,一派輕鬆地告訴你,只要使用 GridView 的 DataSourceID ,之後如果要排序或分頁,只需將 GridView 的 AllowSorting 或 AllowPaging 設為 True,就可以自動完成排序或分頁的功能,不需要寫一行程式喔。

GridView 資料來源的取得,有兩種方式:一種是透過 DataSourceID, 另一種則是 DataSource。而這兩種方式,你只能選擇一種,不能太貪心。DataSourceID,他只能指定給 SqlDataSouce,AccessDataSource, ObjectDataSource, XmlDataSource 等使用。至於 DataSource,你可以給他 DataSet , DataView , DataTable...,或是任何有實作 IEnumerable, IListSource, IDataSource,  IHierarchicalDatasource介面的都可以。

可是,也許是我們太過於期待 GridView 不需寫程式的特色,所以會舉一反三地將另一種狀況也希望 GridView 幫我們完成。如果今天我的 GridView 資料來源是使用 DataSource 而不是 DataSourceID,那 GridView 是否也可以自動幫我們完成排序或分頁工作呢?

很不幸的,不可以,雖然你可以看到 GridView 標頭出現可供排序的超連結符號,但你壓下去會出現:由 GridView 'gvtest' 引發但尚未處理的事件 Sorting。















你也可以看到出現了分頁的頁碼超連結,但當你壓下去,會出現:由 GridView 'gvtest' 引發但尚未處理的事件 PageIndexChanging。















這也沒得商量餘地,只得乖乖去寫幾段控制分頁或排序的程式了。

針對排序的功能:

你需要去撰寫 gv_Sorting( ) 的功能。
擷取一段 code 以便日後參考:

protected void Page_Load(object sender, EventArgs e)
{
  if (!IsPostBack)
  {
    ViewState["SortExpression"] = "gp_orgcdname"; //設定預設的排序欄位
    ViewState["SortDirection"] = SortDirection.Ascending;//設定預設的排序方式    
  }
}


protected override void OnPreRender(EventArgs e)
{
  BindData();
  base.OnPreRender(e);
}


private void BindData()
{
  //取得資料來源
  DataView dv= ds.Select(new DataSourceSelectArguments() ) as DataView;
  if (dv != null)
  {
      //設定 排序方式
      dv.Sort = string.Format("{0} {1}", ViewState["SortExpression"].ToString(), (SortDirection)ViewState["SortDirection"]==SortDirection.Ascending?"ASC":"DESC");        
      gv.DataSource = dv;            
      gv.DataBind();        
  }
}

protected void gv_Sorting(object sender, GridViewSortEventArgs e)
{
  ViewState["SortExpression"] = e.SortExpression;

  if (ViewState["SortExpression"].ToString() == e.SortExpression)          
      ViewState["SortDirection"] = (SortDirection)ViewState["SortDirection"] == SortDirection.Ascending ? SortDirection.Descending : SortDirection.Ascending;
  else
      ViewState["SortDirection"] = SortDirection.Ascending;

}


針對分頁的功能:
則需要撰寫 gv_PageIndexChanging( )功能

protected void gv_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
  gv.PageIndex = e.NewPageIndex;
  gv.DataBind();
}

2010年3月1日 星期一

在 VS2005 整合 jQuery UI Tabs


想在 VS2005 專案裡面套用 jQuery UI 的 Tabs (頁籤)功能,於是到了 http://jqueryui.com/demos/tabs/ 去挑選了一個自己喜歡的樣式,並加入到自己的專案中。可是,當我放了一個 Button 控制項後,就開始哀號了,因為只要頁面一有 Post Back 發生,jQuery UI 就會重新載入。如上面所示,假如我已經切換到第二個頁籤(逾期未簽)後,然後點選該頁籤下的任何一個會觸發 Post Back 的動作(包括排序也一樣),jQuery UI  Tabs 就會重新跳回第一個頁籤。

所以,是不是應該偷偷放個什麼,好讓 Tabs 能夠記住目前的頁籤索引位置。

於是我在頁面上放了一個 hidden 欄位,並設定 runat="server" 。

<input type="hidden" id="hTag" runat="server" />

下一個問題,則是如何目前將頁籤的索引值寫入我的隱藏欄位 hTag ?我在 http://jqueryui.com/demos/tabs/ 的 Events 頁籤找到了 show 這個事件,測試了一下他所提供的 sample code,去攔 tabsshow 事件並加以利用。此外,抓取目前 Tabs 頁籤的方法為 .tabs('option', 'selected') ,於是將程式整理如下:

$(function(){

 // Tabs
 $('#tabs').tabs().css("width","840px");
 
 //hover states on the static widgets
 $('#dialog_link, ul#icons li').hover(
  function() { $(this).addClass('ui-state-hover'); }, 
  function() { $(this).removeClass('ui-state-hover'); }
 );
 
  $('#tabs').bind("tabsshow",function(event, ui) { GetIndex(); });
 
});

function GetIndex()
{// 將目前的 Tab Index 存入 hTag 暫存
    var $tabs = $('#tabs').tabs();
    var $tagIndex=$tabs.tabs('option', 'selected');
    $("input[id*=hTag]").val($tagIndex);   
}


程式到此,已經可以正確將目前 Tabs 頁籤切換時,將頁籤索引保存下來。但還有一個缺點,就是當頁面有 Post Back 發生時,還是沒辦法保留目前所在頁籤位置,會跳到預設的第一個。所以,需要在頁面一旦有 Post Back 時,將 Tabs 頁籤切換到目前所儲存的位置。而在 http://jqueryui.com/demos/tabs/  的 Methods 裡有提供一個 select 方法,可以切換 Tabs 頁籤,於是就可以撰寫一段程式去完成這動作。

function SyncTab()
{//如果目前的  hTag 有暫存資料,則將 Tab 與暫存資料同步   
    var $tagIndex=$("input[id*=hTag]").val();   
    
    if($tagIndex!='')
    {
        $('#tabs').tabs( 'select' , parseInt($tagIndex));
    }
}

這裡有個小地方需要注意,tabs('select', 數字參數 ) ,一定要記得傳數字參數進去,否則跳頁的效果會不正確。所以我用 parseInt( )來轉換為數字。

最後將 SyncTab() 函式放到 $(function(){ ... }) 裡面。

整個完整的 Code 如下:

<head>
<script language="javascript" type="text/javascript" src="../js/jquery.js"></script>
<script language="javascript" type="text/javascript" src="../js/jquery.url.min.js"></script>
<link type="text/css" href="../css/cupertino/jquery-ui-1.8rc2.custom.css" rel="stylesheet" /> 
<script language="javascript" type="text/javascript" src="../js/jquery-ui-tab.js"></script>


<script>
$(function(){

 // Tabs
 $('#tabs').tabs().css("width","840px");
 
 //hover states on the static widgets
 $('#dialog_link, ul#icons li').hover(
  function() { $(this).addClass('ui-state-hover'); }, 
  function() { $(this).removeClass('ui-state-hover'); }
 );
 
  $('#tabs').bind("tabsshow",function(event, ui) { GetIndex(); });
  
  //如果目前的  hTag 有暫存資料,則將 Tab 與暫存資料同步
  SyncTab();  
 
});

function GetIndex()
{// 將目前的 Tab Index 存入 hTag 暫存
    var $tabs = $('#tabs').tabs();
    var $tagIndex=$tabs.tabs('option', 'selected');
    $("input[id*=hTag]").val($tagIndex);   
}



function SyncTab()
{//如果目前的  hTag 有暫存資料,則將 Tab 與暫存資料同步   
    var $tagIndex=$("input[id*=hTag]").val();   
    
    if($tagIndex!='')
    {
        $('#tabs').tabs( 'select' , parseInt($tagIndex));
    }
}
</script>
</head>

<body>
<input type="hidden" id="hTag" runat="server" />

<div id="tabs">
 <ul>
 <li><a href="#tabs-1">逾期未填</a></li>
  <li><a href="#tabs-2">逾期未簽</a></li></ul>
 <div id="tabs-1"> Page1 Content
 </div>
 <div id="tabs-2"> Page2 Content
 </div>
</div>

</body>