December 14, 2009

ReportViewer控制項無法在頁面顯示的解決方法

小弟手邊有個專案需要用到ReportViewer,部署上正式機後卻無法顯示出ReportViewer控制項,如下圖
正式機的環境是Windows 2008,IIS 7

google了一下發現,原來是IIS 7讀web.config的方式有變,不再讀取<system.web>裡<httpHandlerss>的設定,而改讀<system.webServer>裡的<handlers>的設定

原本在IIS 6中,要在config裡的system.web設定
<system.web>
  <httpHandlers>
    <add path="Reserved.ReportViewerWebControl.axd" verb="*" type="Microsoft.Reporting.WebForms.HttpHandler, Microsoft.ReportViewer.WebForms, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" validate="false"/>
  </httpHandlers>
</system.web>

在IIS 7卻要設定在
<system.webServer>
  <handlers>
    <add name="ReportViewerWebControl" path="Reserved.ReportViewerWebControl.axd" verb="*" type="Microsoft.Reporting.WebForms.HttpHandler, Microsoft.ReportViewer.WebForms, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
  </handlers>
</system.webServer>

設定完後,ReportViewer就可以正常顯示了


備註
經亂馬客大的建議得知,只要將應用程式集區的Managed管線模式整合式改為傳統即可解決此問題

December 13, 2009

使用jQuery判斷RadioButton是否被選取

透過attr函式來判斷是否被選取
$("#<%= RadioButton.ClientID %>").attr("checked")

透過is函式來判斷是否被選取
$("#<%= RadioButton.ClientID %>").is(":checked")

November 16, 2009

如何在單一頁面設置多個Default Button

小弟前陣子執行的專案中,有個需求是這樣的
系統登入的頁面中,有可以輸入帳號密碼的登入區塊
也有可以輸入關鍵字的資料查詢區塊
甲方希望在登入區塊輸入帳號密碼後可以不用按登入按鈕,直接按Enter也可以進行登入程序,而在資料查詢區塊中輸入關鍵字後不用按搜尋按鈕,直接按Enter即可進行查詢

原本想用Form提供的屬性DefaultButton來解決這個問題,但Form的DefaultButton只能設訂給其中一個Button,而我有兩個Button要設定

後來發現,原來Panel也有DefaultButton的屬性,只要我們登入區塊放至在Panel A,而資料查詢區塊放至在Panel B再將Panel A的DefaultButton設為登入按鈕的ID,Panel B的DefaultButton設為搜尋按鈕的ID,即可達到上述的需求

以下是部份範例程式,供各位參考

MultiDefaultButton.aspx
<form id="form1" runat="server">
    <div>
        <asp:panel id="Panel_Login" runat="server" defaultbutton="Button_Login">
            帳號:<asp:TextBox ID="TextBox_Account" runat="server"></asp:TextBox>
            密碼:<asp:TextBox ID="TextBox_Password" runat="server"></asp:TextBox>
            <asp:Button ID="Button_Login" runat="server" Text="登入" 
                OnClick="Button_Login_Click" />
        </asp:panel>
    </div>
    <br />
    <asp:panel id="Panel_Search" runat="server" defaultbutton="Button_Search">
        關鍵字:<asp:TextBox ID="TextBox_Keyword" runat="server"></asp:TextBox>
        <asp:Button ID="Button_Search" runat="server" Text="搜尋" 
            OnClick="Button_Search_Click" />
    </asp:panel>
</form>
MultiDefaultButton.aspx.cs
protected void Button_Login_Click(object sender, EventArgs e)
{
    Response.Write(string.Format("您輸入的帳號為{0},密碼為{1}", this.TextBox_Account.Text, this.TextBox_Password.Text));
}

protected void Button_Search_Click(object sender, EventArgs e)
{
    Response.Write(string.Format("您輸入的關鍵字為{0}", this.TextBox_Keyword.Text));
}

執行結果
1. 輸入帳號密碼後按Enter

2. 輸入關鍵字後按Enter

July 11, 2009

DropDownList控制項的資料驗証 - 使用RequiredFieldValidator & jQuery Validation Plugin

在設計下拉式選單時,常需要將第一個選項設計成"請選擇xxx",在送出表單前會檢查使用者是否有選擇選單裡的其它選項,我們可以ASP.NET 內建的 RequiredFieldValidator 控制項或是jQuery的Validation Plugin來達到驗証的功能。

1. RequiredFieldValidator
<asp:DropDownList ID="DropDownList" runat="server" DataSourceID="ObjectDataSource" DataTextField="ApplicationName" DataValueField="ApplicationId">
 <asp:ListItem Value="-1">請選擇</asp:ListItem>
 <asp:ListItem Value="選項一之值">選項一</asp:ListItem>
 <asp:ListItem Value="選項二之值">選項二</asp:ListItem>
 <asp:ListItem Value="選項三之值">選項三</asp:ListItem>
</asp:DropDownList>

<asp:RequiredFieldValidator ID="RequiredFieldValidator" runat="server" ControlToValidate="DropDownList" Display="Dynamic" ErrorMessage="請選擇下拉式選單" SetFocusOnError="True" InitialValue="-1"></asp:RequiredFieldValidator>

由以上程式碼片段可以看到,我們設定 RequiredFieldValidator 的InitialValue屬性值與DropDownList的第一個選項"請選擇"之值相同註1。當表單送出時會自動檢查下拉式選單所選選項之值是否與 RequiredFieldValidator 相同,如果相同則表單停止送出。

2. jQuery Validation Plugin
(1) 將"請選擇"選項之值設為空字串
(2) 加入以下code snippet
<script language="javascript" type="text/javascript">
    $(function() {
        $("#<%= this.Form.ClientID %>").validate({
            rules: {
            <%= this.DropDownList.UniqueID %>: {required: true}
            },
            messages:{
            <%= this.DropDownList.UniqueID %>: { required: "請選擇下拉式項單"}
            }
        });
    });
</script>

備註
1.也可將"請選擇"選項之值設為空字串,拿掉 RequiredFieldValidator 的InitialValue一樣能執行驗証

July 9, 2009

當TextBox的ReadOnly屬性為true時,Postback後無法讀取TextBox之值

是的。

Postback之後請改用Request.Form[this.TextBox.UniqueID]取得TextBox之值。或是改用TextBox.Attributes.Add("readonly", "readonly")來設定TextBox為readonly而不直接設定TextBox的ReadOnly屬性


參考
http://west-wind.com/weblog/posts/3939.aspx
http://www.codeproject.com/KB/aspnet/Readonly.aspx
http://www.g9th.com/blog/post/2006/12/Readonly-property-of-Textbox-in-ASPNET.aspx

July 5, 2009

CalendarExtender中文顯示問題

CalendarExtender預設是英文介面。如果要顯示出中文介面,可以將ScriptManager控制項的EnableScriptGlobalizationEnableScriptLocalization兩個屬性設定為true,即可顯示出中文,如下:

不過Pete發現了一個地方好像不太對勁,原來是下方的日期居然是顯示Today字樣,而不是中文"今天"或"今日"。這是怎麼回事?原來在AjaxControlToolkit提供的Binary壓縮檔中,還提供了語系資源檔,而Pete忘了將中文語系資源檔(zh-CHT資料夾)一同放進bin裡,而造成中文顯示不出來的問題。

將中文語系檔加入後,一切就正常了。


July 4, 2009

列舉型別的Description屬性用法

列舉型別的Description屬性是個還不錯的功能,目前小弟將它應用在專案中,取代掉一些原本放在資料庫中較不易變動的列舉資料,以減少一些query與join。

有一列舉型別如下
        enum Family : int
        {
            [Description("爸爸")]
            Father = 0,
            [Description("媽媽")]
            Mother = 1,
            [Description("兄弟")]
            Brother = 2,
            [Description("姐妹")]
            Sister = 3,
            [Description("兒子")]
            Son = 4,
            [Description("女兒")]
            Daughter = 5
        }

經由以下函式可取得列舉值的Description屬性值
 public string GetDescription(Enum value)
 {
   FieldInfo fi = value.GetType().GetField(value.ToString());
   DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
   return attributes.Length > 0 ? attributes[0].Description : value.ToString();
 }
  1. 經由列舉值取得Description之值
    GetDescription(Family.Brother)
     
  2. 經由字串值取得Description之值
    GetDescription(((Family) Enum.Parse(typeof(Family), "Brother")))
     
  3. 經由列舉型別的基底型別數值取得Description之值
    GetDescription((Family) Enum.ToObject(typeof(Family), 2))
備註
1.使用時需引入System.ComponentModelSystem.Reflection
2.可將此函式改寫為Extension Methods增加使用上的方便性,或參考國外網友使用泛型來達到相同效果

其它參考
http://www.moggoly.me.uk/blog/post/Enum-description-values.aspx
http://blogs.freshlogicstudios.com/Posts/View.aspx?Id=388f7d39-0b90-43bc-b03a-c1f605dfb499

Object.ToString()與Convert.ToString()

當需將物件轉換成字串我們最常使用Object.ToString()來取得轉換後的結果。但當Object是null時,系統就會丟出NullReferenceException,因為我們不能將null轉換成字串。常見的情況發生於讀取資料庫欄位資料時,如果欄位設定為nullable,當我們在程式碼中嘗試用DataReader["ColumnName"].ToString()去讀出字串資料時,就有可能會出NullReferenceException。
解決的方法有幾個:
  1. 先對DataReader["ColumnName"]做null checking,再根據結果做ToString()或回傳空字串(或其它有意義的字串)。
     
  2. 永遠將欄位設為有預設值(如空字串或其它數值資料)而不要允許null欄位
     
  3. 使用Convert.ToString()來做轉換
ToString()預設是為沒有做null checking的,而Convert.ToString()會在轉換字串時先對要轉換的物件做null checking。我們可以由 .NET Reflector 這套工具看出,如果物件為null的話Convert.ToString()就會回傳空字串,如下:

        public static string ToString(object value, IFormatProvider provider)
        {
            IConvertible convertible = value as IConvertible;
            if (convertible != null)
            {
                return convertible.ToString(provider);
            }

            IFormattable formattable = value as IFormattable;

            if (formattable != null)
            {
                return formattable.ToString(null, provider);
            }

            if (value != null)
            {
                return value.ToString();
            }

            return string.Empty;
        }

以執行速度來說,根據Brad Abrams的測試,ToString()會比Convert.ToString()快些,由上面的程式碼可以知道為什麼。因為少了null checking。

結論
當不確定所轉換的物件是否為null時,可以用Convert.ToString()來做轉換,以避免系統拋出例外訊息;當確定物件不為null時,直接使用ToString()即可。

June 14, 2009

以jQuery驗証Email

jQuery官方的Validation Plugin是個相當好用的驗証工具。做會員註冊功能時常會需要做表單驗証的功能,尤其是驗証使用者所輸入的Email。
我們通常會對Email欄位做至少以下三項驗証:
  1. 檢查Email輸入欄位是否有填寫
  2. 檢查使用者填入的Email格式是否正確
  3. 檢查Email是否已被註冊過
透過Validation plugin,我們可以輕鬆地達到以上驗証。

1.加入jQueryValidation plugin
<script src="jquery-1.3.2.js" type="text/javascript"></script>
<script src="jquery.validate.js" type="text/javascript"></script>

2.在畫面上放置一個TextBox及Button
<form id="form1" runat="server">
    <div>
        <asp:TextBox ID="TextBox_Email" runat="server"></asp:TextBox>
    </div>
    <asp:Button ID="Button_Submit" runat="server" Text="送出" />
</form>

3.加入"檢查Email輸入欄位是否有填寫"功能

<script language="javascript" type="text/javascript"> 
    $(function() { 
        $("#<%= this.Form.ClientID %>").validate({ 
            rules: { 
            <%= this.TextBox_Email.UniqueID %>: { required: true} 
            }, 
            messages:{ 
            <%= this.TextBox_Email.UniqueID %>: { required: "請輸入Email"} 
            } 
        }); 
    }); 
</script>
在不輸入資料時按送出鈕後我們可以看到以下畫面


4.加入"檢查使用者填入的Email格式是否正確"功能

<script language="javascript" type="text/javascript">
    $(function() {
        $("#<%= this.Form.ClientID %>").validate({
            rules: {
            <%= this.TextBox_Email.UniqueID %>: { required: true, email: true}
            },
            messages:{
            <%= this.TextBox_Email.UniqueID %>: { required: "請輸入Email", email: "Email格式不正確"}
            }
        });
    });
</script>
我們可以輸入格式不正確的Email,可以看到以下畫面


5.加入"檢查Email是否已被註冊過"功能

Client端
<script language="javascript" type="text/javascript">
    $(function() {
        $("#<%= this.Form.ClientID %>").validate({
            rules: {
            <%= this.TextBox_Email.UniqueID %>: {
                required: true,
                email: true,
                remote: {
                    url: "Default.aspx",
                    type: "get",
                    data: {
                        email: function(){return $("#<%= this.TextBox_Email.UniqueID %>").val();}
                    }
                }}
            },
            messages: {
            <%= this.TextBox_Email.UniqueID %>: {
                required: "請輸入Email",
                email: "Email格式不正確",
                remote: "Email已被註冊"
                }
            }
        });
    });
</script>

Server端
        protected void Page_Load(object sender, EventArgs e)
        {
            if (Request.HttpMethod == "GET")
            {
                string email = Request.QueryString["email"];

                if (string.IsNullOrEmpty(email))
                {
                    return;
                }

                //IsEmailRegistered為true表示Email已被註冊,並回傳"false"表示未通過驗証
                Response.Write(IsEmailRegistered(email) ? "false" : "true");
                Response.End();
            }
        }

        private bool IsEmailRegistered(string email)
        {
            return true;
        }

當我們把IsEmailRegistered設為true時,在畫面上按送出鈕會看到以下畫面



備註
1.經測試,使用<%= this.TextBox_Email.UniqueID %>在有MasterPage的頁面中才能正常驗証表單
2.詳細的教學文件可參考官方教學網頁

May 31, 2009

使用Query Builder Methods做多欄位排序

有兩個table如下:

Category

SubCategory

CategorySubCategory存在Association (SubCategory.CategoryId與Category.CategoryId)

現在我們要針對SubCategory做多欄位排序,我們想先依SubCategory.CategoryId排序後,再對SubCategory.SubCategoryId做排序,該怎麼做呢?

方法1,使用Query Builder Methods + Lambda
MyAccountEntities db = new MyAccountEntities();

return db.SubCategory.Include("Category")
                     .OrderBy(c => c.Category.CategoryId)
                     .ThenBy(c => c.SubCategoryId)
                     .ToList();

方法2,使用Query Builder Methods + Entities SQL
MyAccountEntities db = new MyAccountEntities();

return db.SubCategory.Include("Category")
                     .OrderBy("it.Category.CategoryId, it.SubCategoryId")
                     .ToList();
it在這裡指的是SubCategory這個context,此為固定用法。

錯誤用法
Pete第一次研究如何做多欄排序時沒有發現有ThenBy這個好用的method,所以就下了以下的錯誤語法
MyAccountEntities db = new MyAccountEntities();

return db.SubCategory.Include("Category")
                     .OrderBy(c => c.Category.CategoryId)
                     .OrderBy(c => c.SubCategoryId)
                     .ToList();
中文語意上看起來好像也沒錯,我想先OrderBy Category.CategoryId,然後OrderBy SubCategory.SubCategoryId
這麼做也不會有錯誤訊息,但最後的結果是根據最後一個OrderBy method來排序。

May 24, 2009

Html.DropDownList的預設值沒有作用?

當在Controller內設定ViewData給View讀取時,如果ViewData的key name和View的DropDownList ID一樣時,DropDownList的預設選取功能就會失效。

例如:

Controller
ViewData["Category"] = new SelectList(repository.GetAllCategories(), "CategoryId", "CategoryName", id);

View
<%= Html.DropDownList("Category", ViewData["Category"] as SelectList)%>

各位測試後會發現沒有辦法設定DropDownList的預設值。解決方法就是不要將ViewData的key name設定成和DropDownList的ID一樣

在國外論壇上也有人提出類似問題

April 24, 2009

RTF檔案字串取代研究

當需要將字串代入Word檔案又不想在客戶端安裝Office時,我們會以RTF檔案格式將所要顯示的字串取代掉設定在RTF檔案裡的變數後,再讓客戶下載並將副檔名變更為*.doc。以下是可能的實作步驟:
  1. 將客戶提供的Word檔另存成RTF格式
  2. 在RTF檔案中設定要被取代為字串的變數
  3. 客戶端點選連結下載時將字串代入RTF檔案並將副檔名更改為*.doc
在RTF中,中文字會以16進位來儲存,而某些中文字的16進位字元的某兩個字元組合恰巧會是某些符號的16進位字元。如此,當我們做字串取代後,有可能會發生取代後的文字在顯示時出現亂碼,甚至是檔案無法開啟的情況。

要解決此問題,我們必須在取代RTF檔案內的變數前,就先將我們要代入的字串轉成16進位,並加入特殊字元的前置符號\'後再進行取代,如此才能正常顯示中文字。以下程式片段可將一字串轉換為16進位並加入特殊字元的前置符號。
Public Shared Function GetRtfCode(ByVal str As String) As String
  Dim sb As New StringBuilder()
  Dim Bytes() As Byte = Encoding.Default.GetBytes(str)
  For Each b As Byte In Bytes
    sb.Append("\'" & IIf(b < 16, "0" & Hex(b), Hex(b))) 
  Next
  Return sb.ToString().ToLower()End Function
參考

March 2, 2009

GridView加入流水號的方法 - 使用伺服器控制項(2)

在「GridView加入流水號的方法 - 使用伺服器控制項(1)」,大家測試時會發現,如果GridView有分頁,流水號會重新計算。
在某些情況下,可能需要將流水號累加,這時可以將覆寫的InitializeCell(ByVal cell As System.Web.UI.WebControls.DataControlFieldCell, ByVal cellType As System.Web.UI.WebControls.DataControlCellType, ByVal rowState As System.Web.UI.WebControls.DataControlRowState, ByVal rowIndex As Integer)修改為如下程式碼
Public Overrides Sub InitializeCell(ByVal cell As System.Web.UI.WebControls.DataControlFieldCell, ByVal cellType As System.Web.UI.WebControls.DataControlCellType, ByVal rowState As System.Web.UI.WebControls.DataControlRowState, ByVal rowIndex As Integer)
  MyBase.InitializeCell(cell, cellType, rowState, rowIndex)
  If cellType = DataControlCellType.DataCell Then
    cell.Text = (OwnerGridView.PageIndex * OwnerGridView.PageSize + rowIndex + 1).ToString()
  End If
End Sub Private ReadOnly Property OwnerGridView() As GridView   Get     Return DirectCast(Me.Control, GridView)   End Get End Property
若需同時支援累加和不累加流水號,可自行加入屬性做判斷。

February 28, 2009

註冊控制項為全域使用的方法

使用自訂伺服器控制項時,需要在頁面先以Register指示詞註冊控制項後,方能使用該控制項。

如果專案中有N頁會用到該控制項,就要註冊N次顯得有些麻煩。有沒有註冊一次就可以讓所有頁面使用的方式?

有。

請在Web.config中<system.web> -> <pages> -> <controls>加入如下節點

<add tagPrefix="MyTag" namespace="MyWorks.WebControls" assembly="MyWorks"/>

tagPrefix為控制項加入頁面時的前置詞,assembly為組件名稱,namespace為命名空間名稱。

GridView加入流水號的方法 - 使用伺服器控制項(1)

在「GridView加入流水號的方法 - 不使用Code Behind」中提到了不使用Code Behind方式在GridView中實作流水號的方法。

在專案中,為了GridView畫面的一致性,可能將每個GridView都加入流水號。然而每個使用流水號的GridView都要加入5行的程式碼來顯示流水號,不免有點不夠美觀。何不把流水號寫成一個自訂控制項?每次使用時只要加入1行程式碼註1,讓程式碼易讀又美觀。

以下步驟說明如何建立一個流水號伺服器控制項:

1.建立ASP.NET伺服器控制項專案SerialNumberField
2.將控制項命名為SerialNumberField
3.繼承DataControlField
4.覆寫CreateField(),如下
Protected Overrides Function CreateField() As System.Web.UI.WebControls.DataControlField
  Return New SerialNumberField()
End Function
5.覆寫InitializeCell(ByVal cell As System.Web.UI.WebControls.DataControlFieldCell, ByVal cellType As System.Web.UI.WebControls.DataControlCellType, ByVal rowState As System.Web.UI.WebControls.DataControlRowState, ByVal rowIndex As Integer),如下
Public Overrides Sub InitializeCell(ByVal cell As System.Web.UI.WebControls.DataControlFieldCell, ByVal cellType As System.Web.UI.WebControls.DataControlCellType, ByVal rowState As System.Web.UI.WebControls.DataControlRowState, ByVal rowIndex As Integer)

  MyBase.InitializeCell(cell, cellType, rowState, rowIndex)

  If cellType = DataControlCellType.DataCell Then
    cell.Text = (rowIndex + 1).ToString()
  End If
End Sub
6.建置專案

註1
若將註冊伺服器控制項的指示詞也算進去的話就會是2行。也可改以另一種方式註冊控制項,以省去在每個頁面皆註冊控制項的步驟,請參考「註冊控制項為全域使用的方法」。

如何使用SerialNumberField控制項?

1.將SerialNumberField.dll加入參考

2.於使用流水號的頁面中註冊控制項,如下
<%@ Register assembly="SerialNumberField" namespace="SerialNumberField" tagprefix="sn" %>
3.於GridView的<Columns></Columns>中加入SerialNumberField(如同BoundField一樣),如下
<sn:SerialNumberField />

列出列舉(Enumeration)內成員名稱及列舉值的方法

一列舉Family如下
Protected Enum Family As Integer
  Grandpa = 0
  Grandma = 1
  Father = 2
  Mother = 3
  Brother = 4
  Sister = 5
End Enum

以下示範如何列出此列舉內的列舉名稱及值
'列出列舉成員名稱
Me.Response.Write("列出列舉成員名稱<br />")
For Each str As String In [Enum].GetNames(GetType(Family))
  Me.Response.Write(str)
  Me.Response.Write("<br />")
Next

Me.Response.Write("<p></p>")

'列出列舉值
Me.Response.Write("列出列舉值<br />")
For Each value As Integer In [Enum].GetValues(GetType(Family))
  Me.Response.Write(value.ToString())
  Me.Response.Write("<br />")
Next

Me.Response.Write("<p></p>")

'經由列舉值取得列舉成員名稱
Me.Response.Write("經由列舉值取得列舉成員名稱<br />")
For Each value As Integer In [Enum].GetValues(GetType(Family))
  Me.Response.Write("值:" & value.ToString() & " 名稱:" & [Enum].GetName(GetType(Family), value))
  Me.Response.Write("<br />")
Next

顯示結果如下:

January 29, 2009

GridView的表尾合併範例

用GridView做顯示報表時,常常需要做表尾合併用來顯示如分數、金額、人數的總和或平均。本篇文章要示範如何在GridView做表尾合併。
在做合併功能前,請務必先將GridView的屬性ShowFooter設定為True,接著參考下圖:
根據上圖顯示,我們要將GridView的Footer顯示成兩個Cell,第一個Cell為五個欄位合併(流水號、姓名、國文、英文、數學),Cell內的文字內容為"總分平均";第二個Cell用來顯示總分欄位的平均值。接下來開始進行合併,我們將程式撰寫在GridView的RowCreated事件中,請參考下方code snippet:
    Protected Sub GridView_RowCreated(ByVal sender As Object, ByVal e As GridViewRowEventArgs) Handles GridView.RowCreated

        If Not (e.Row.RowType = DataControlRowType.Footer) Then
            Exit Sub
        End If

        Dim footer As TableCellCollection = e.Row.Cells

        '清除Footer原本的Cells
        footer.Clear()

        '第一個Cell
        Dim tc1 As New TableCell()
        tc1.Text = "總分平均"
        tc1.ColumnSpan = 5
        tc1.HorizontalAlign = HorizontalAlign.Right
        footer.Add(tc1)

        '第二個Cell
        footer.Add(New TableCell())
    End Sub

說明
1.footer.Clear()用來清除在GridView Footer中原本所存在的Cells,如果不以Clear()清除的話,等於是在原本已有的Cells上再加入新的Cell,則GridView會變成如下顯示:
2.ColumnSpan用來設定合併的欄位數,HorizontalAlign用來設定水平位置
3.完整範例可參考GridViewFooterMerge.zip

January 12, 2009

GridView的RowCommand事件

在GridView觸發RowCommand事件時,由System.Web.UI.WebControls.GridViewEditEventArgs可取得觸發事件的來源物件及其CommandName,如下code snippet
Protected Sub GridView1_RowCommand(ByVal sender As Object, ByVal e As GridViewCommandEventArgs) Handles GridView1.RowCommand
    Select Case e.CommandName
        Case "EditItem"
            '執行按下自訂編輯按鈕的動作
        Case "DeleteItem"
            '執行按下自訂刪除按鈕的動作
        Case Else
            Throw New Exception("沒這CommandName")
    End Select11
End Sub
經測試,CommandName是有幾個特定預設值的,如"Edit"、"Delete"、"Update"、"Cancel"、"New"、"Select"、"Page"。
其中"Edit"、"Delete"、"Update"、"Cancel"、"Page"還會觸發特定事件,如RowEditing、RowDeleting、RowUpdating。
所以如果是使用自訂按鈕做類似的動作處理時,請避免設定與系統預設相同的CommandName,以免造成不可預期的結果。

January 11, 2009

UpdatePanel裡出現__designer屬性的解決方案

被這個問題困擾了好一陣子了,Pete用VS2005把Web Control拉進UpdatePanel時,在Web Control的屬性都會莫名的多出__designer::wfdi屬性,而且VS2005會不認得UpdatePanel的屬性。

雖說compile還是能過,但於VS的aspx原始檔畫面會出現一堆紅色底線,畫面極不美觀,嚴重影響視力且格式化文件的排版功能會失效,有時Intellisense還會不能用!

 以下提供一個簡單的方法,Pete也成功的解決了這個問題:

 至C:\Documents and Settings\XXX\Application Data\Microsoft\VisualStudio\8.0下砍掉ReflectedSchemas資料夾後,重新開啟VS,一切問題就解決囉!

*XXX為預設登入電腦名稱,若在安裝作業系統時未變更電腦名稱則預設為Administrator 

*Pete的VS版本是Professional,其它版本的解決方式可參考以下網址: blogs.msdn.com/mikhailarkhipov/archive/2007/01/03/how-to-fix-intellisense-issues-after-upgrading-to-asp-net-ajax-1-0-rc.aspx

BoundField的DataFormatString無作用?

請將BoundField屬性HtmlEncode設為false

GridView加入流水號的方法 - 不使用Code Behind

有時想在GridView顯示流水號如下圖排列方式


可在GridView中加入一TemplateField並在其ItemTemplate裡加入<%#Container.DataItemIndex + 1%>,如以下片段

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False">
 <Columns>
  <asp:TemplateField HeaderText="流水號">
   <ItemTemplate>
    <%#Container.DataItemIndex + 1%>
   </ItemTemplate>
  </asp:TemplateField>
  <asp:BoundField HeaderText="其它資料" />
 </Columns>
</asp:GridView>

使用上述方式在GridView有開啟分頁功能時,在跳頁時會累加流水號。如一PageSize為5的GridView,其第一頁的流水號為1~5,第二頁的流水號則為6~10。

*如果不想讓流水號累加的話,可將<%#Container.DataItemIndex + 1%>改為<%#Container.DisplayIndex + 1%>
*若流水號想以0001~0005呈現的話,可改為<%#(Container.DataItemIndex + 1).ToString("0000")%>。

將數字轉為以千為單位並用逗號區分的方法

當我們有一數字65536想以65,536來顯示時,我們可以下列函數做處理
String.Format("{0:N0}", 65536)
上述方法可得到一字串65,536,其中{0:N0}的0表示要顯示的小數點位數
以上述範例來看,如果我們改為
String.Format("{0:N2}", 65536)
則得到的結果為65,536.00

如果要以上述所得字串轉回去純數值資料的話, 可以用
Integer.Parse("65,536", System.Globalization.NumberStyles.AllowThousands)
有時在GridView中想把顯示出的數字以千為區分時,我們可以在BoundField中,將其DataFormatString屬性設為{0:N0},並把HtmlEncode屬性設為false,即可得到前述結果。

補充
經hatelove大提醒得知如果要parse的字串含小數點,如"65,536.00",則無法使用System.Globalization.NumberStyles.AllowThousands須改用System.Globalization.NumberStyles.Number
以下是測試結果
System.Globalization.NumberStyles.AllowThousands僅適用於無小數點的數值字串,如"65,536";而System.Globalization.NumberStyles.Number則適用於無小數點和有小數點的數值字串,如"65,536"或"65,536.00"。

參考
為何System.Globalization.NumberStyles.Number可允許有小數點和無小數點的情況?大家可以參考MSDN。
http://msdn.microsoft.com/en-us/library/system.globalization.numberstyles.aspx

在說明表格Number欄位中有提到"Indicates that the AllowLeadingWhite, AllowTrailingWhite, AllowLeadingSign, AllowTrailingSign, AllowDecimalPoint, and AllowThousands styles are used. This is a composite number style. "
所以Number具有AllowThousands及AllowDecimalPoint的功能,可同時轉換有小數點及無小數點的情況。