ASP.NET_Custom Server Control的模組化開發練習
由於日常升級網頁表單會時常一直寫一樣的html code
為了節省時間通常可進行所謂的Custom Server Control的封裝
這樣也會使維護變得複雜,會讓其他程式開發者不曉得哪段是重點(變動頻率較高的程式段落)
本次就會以如下控件模組來設計一個可以重複使用的套版
新增好一個Web專案後
在自行新增加一個WebForm Server Control項目
(我比較習慣稱呼為Custom Server Control 關鍵字比較好搜尋)
Default 會產生的程式碼如下
RenderContents可以串HTML的內容
主要是在此事件中渲染到瀏覽器的
經改寫(大量Google 跟 Try & Error)
程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 | Imports System Imports System.Collections.Generic Imports System.ComponentModel Imports System.Drawing Imports System.Text Imports System.Web Imports System.Web.UI Imports System.Web.UI.WebControls #Region "Reference Link" ' Custom Web Server Controls ' https://dotblogs.com.tw/shadow/archive/2011/11/28/59816.aspx ' https://dotblogs.com.tw/jeff377/2008/10/04/5578 ' http://vito-note.blogspot.com/2012/10/custom-web-server-controls.html ' http://www.webapp.com.tw/EBook5/view.aspx?a=1&TreeNodeID=50&id=1151 ' https://www.codeproject.com/Articles/37814/How-to-Create-a-Date-Picker-Composite-Control-in-A ' creating-a-composite-server-control ' http://www.joe-stevens.com/2010/04/16/creating-a-composite-server-control-with-asp-net/ ' HOW TO: Register an Assembly in a WebForm to Use a Custom Control ' https://support.microsoft.com/en-hk/help/321749/how-to-register-an-assembly-in-a-webform-to-use-a-custom-control ' Delegates (Visual Basic) ' https://docs.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/delegates/index #End Region '請將下列此行複製貼至aspx檔案頂部 '<%@ Register assembly="Foci.NET.Web.ServerControl" namespace="Foci.NET.Web.ServerControl.CustomWebControl" tagprefix="FociWebControl" %> <Assembly: TagPrefix("CustomWebControl", "FociWebControl")> Namespace CustomWebControl <DefaultProperty("Text")> <ToolboxBitmap("C:\img\FociControl.bmp")> <Description("WisdomGrid 控制項")> <ToolboxData("<FociWebControl:TimePeriodCusControl runat=""server"" TopicLabel="" ""/>")> Public Class TimePeriodCusControl Inherits WebControls.WebControl Implements IPostBackEventHandler Dim sbYearList As New StringBuilder Dim sbMonthList As New StringBuilder Dim sbDayList As New StringBuilder #Region "Property" <Description("設置標題")> Public Property TopicLabel As String = "" <Description("獲取或設置下拉單選項_起始年")> Public Property DDLBeginYear As String = "" <Description("獲取或設置下拉單選項_結束年")> Public Property DDLEndYear As String = "" <Description("獲取或設置下拉單選項_起始月")> Public Property DDLBeginMonth As String = "" <Description("獲取或設置下拉單選項_結束月")> Public Property DDLEndMonth As String = "" <Description("獲取或設置下拉單選項_起始日")> Public Property DDLBeginDay As String = "" <Description("獲取或設置下拉單選項_結束日")> Public Property DDLEndDay As String = "" #End Region '外部註冊事件用的程式區塊,不要更動 '------------------------------------------------------------------------------------------------------------------------------------------------------------ <Category("Behavior")> Public Event Click As EventHandler Public Sub RaisePostBackEvent(eventArgument As String) Implements IPostBackEventHandler.RaisePostBackEvent Me.DDLBeginYear = Page.Request("ddlBeginYear") Me.DDLBeginMonth = Page.Request("ddlBeginMonth") Me.DDLBeginDay = Page.Request("ddlBeginDay") Me.DDLEndYear = Page.Request("ddlEndYear") Me.DDLEndMonth = Page.Request("ddlEndMonth") Me.DDLEndDay = Page.Request("ddlEndDay") If Not IsDateTimeFormatCheck() Then Page.ClientScript.RegisterStartupScript(Page.ClientScript.GetType(), "OpenSubPage", "<script language='javascript'>alert('日期格式有誤!(例如4月沒有31日)');</script>") Exit Sub End If OnClick(EventArgs.Empty) End Sub Private Sub OnClick(ByVal e As EventArgs) RaiseEvent Click(Me, e) End Sub '------------------------------------------------------------------------------------------------------------------------------------------------------------ Private Function IsDateTimeFormatCheck() As Boolean Dim dtBegin As DateTime = DateTime.ParseExact(DDLBeginYear & "/" & DDLBeginMonth, "yyyy/M", Nothing) Dim validBeginDays As Integer = DateTime.DaysInMonth(Convert.ToInt32(Year(dtBegin)), Convert.ToInt32(Month(dtBegin))) Dim dtEnd As DateTime = DateTime.ParseExact(DDLEndYear & "/" & DDLEndMonth, "yyyy/M", Nothing) Dim validEndDays As Integer = DateTime.DaysInMonth(Convert.ToInt32(Year(dtEnd)), Convert.ToInt32(Month(dtEnd))) If (Integer.Parse(DDLBeginDay) < 1 Or Integer.Parse(DDLBeginDay) > validBeginDays) Or (Integer.Parse(DDLEndDay) < 1 Or Integer.Parse(DDLEndDay) > validEndDays) Then 'Page.ClientScript.RegisterStartupScript(Page.ClientScript.GetType(), "OpenSubPage", "<script language='javascript'>alert('日期格式有誤!(例如4月沒有31日)');</script>") Return False Else Return True End If End Function ''' <summary> ''' 如何在ASP.NET下取得一般HTML標籤的值? ''' https://ithelp.ithome.com.tw/questions/10122409 ''' [ASP.NET]取得WebControl的Html字串 ''' https://dotblogs.com.tw/rainmaker/2013/04/08/101008 ''' calling server side event from html button control ''' https://stackoverflow.com/questions/7189037/calling-server-side-event-from-html-button-control ''' [asp.net,javascript]如何從前端利用__doPostBack還有LinkButton 回到後端code behind (UniqueID) ''' https://dotblogs.com.tw/kevinya/2012/05/25/72407 ''' HtmlButton.OnServerClick(EventArgs) Method ''' https://docs.microsoft.com/en-us/dotnet/api/system.web.ui.htmlcontrols.htmlbutton.onserverclick?redirectedfrom=MSDN&view=netframework-4.8#System_Web_UI_HtmlControls_HtmlButton_OnServerClick_System_EventArgs_ ''' *** [ASP.NET 控制項實作 Day6] 事件與 PostBack ''' https://ithelp.ithome.com.tw/articles/10011861 ''' How to call a server-side method from client-side JavaScript ''' https://decoding.wordpress.com/2008/11/14/aspnet-how-to-call-a-server-side-method-from-client-side-javascript/ ''' PDF Reference ''' http://www.aspalliance.com/cookbook/downloads/pdfs/0672325241_ch03.pdf ''' 引發 PreRender 事件,並註冊用戶端指令碼,以產生回傳。 ''' https://www.jasongaylord.com/blog/embed-javascript-in-custom-aspnet-server-controls ''' Embed JavaScript in Custom ASP.NET Server Controls ''' https://docs.microsoft.com/zh-tw/dotnet/api/system.web.ui.htmlcontrols.htmlbutton.onprerender?view=netframework-4.8 ''' </summary> ''' <param name="writer"></param> Protected Overrides Sub RenderContents(ByVal writer As HtmlTextWriter) Dim strHTML As String = "" If Page.IsPostBack = False Then 'Page.IsPostBack = False:頁面是第一次加載時候 InitControlSetting() Else 'Page.IsPostBack = true:頁面是重新加載或返回時 '.....do nothing End If '控件樣式 strHTML = strHTML & "<style type=""text/css"">" strHTML = strHTML & " body {" strHTML = strHTML & " margin: 0;" strHTML = strHTML & " }" strHTML = strHTML & " #table0 {" strHTML = strHTML & " background-color: yellow;" strHTML = strHTML & " width: 100%;" strHTML = strHTML & " table-layout: fixed; /*Table欄位寬度一致*/" strHTML = strHTML & " text-align: center; /*Table欄位內容置中*/" strHTML = strHTML & " }" strHTML = strHTML & " #table1 {" strHTML = strHTML & " /*background-color:yellow;*/" strHTML = strHTML & " width: 100%;" strHTML = strHTML & " table-layout: fixed; /*Table欄位寬度一致*/" strHTML = strHTML & " text-align: left; /*Table欄位內容置中*/" strHTML = strHTML & " }" strHTML = strHTML & " .auto-style1 {" strHTML = strHTML & " height: 26px;" strHTML = strHTML & " }" strHTML = strHTML & "</style>" '控件主體 strHTML = strHTML & "<table id=""table0"">" strHTML = strHTML & " <tr>" strHTML = strHTML & " <td> </td>" strHTML = strHTML & " <td>" strHTML = strHTML & " <span id=""Label1"" style=""color: blue; font-weight: bold;"">" strHTML = strHTML & " " & TopicLabel strHTML = strHTML & " </span>" strHTML = strHTML & " </td>" strHTML = strHTML & " <td> </td>" strHTML = strHTML & " </tr>" strHTML = strHTML & "</table>" strHTML = strHTML & "<table id=""table1"" style=""background-color: lightskyblue;"">" strHTML = strHTML & " <tr>" strHTML = strHTML & " <td class=""auto-style1"">" strHTML = strHTML & " <span id=""Label2"" style=""font-size: small;"">選擇日期:</span>" strHTML = strHTML & " </td>" strHTML = strHTML & " <td class=""auto-style1"">" strHTML = strHTML & " <select name=""ddlBeginYear"" id=""ddlBeginYear"" style=""width: 50px; height: 19px;"" >" strHTML = strHTML & " " & If(Page.IsPostBack = False, GetInitYearVals(), RestoreYear(Me.DDLBeginYear)) strHTML = strHTML & " </select>" strHTML = strHTML & " <span id=""Label3"" style=""font-size: xx-small;"">年</span>" strHTML = strHTML & " </td>" strHTML = strHTML & " <td class=""auto-style1"">" strHTML = strHTML & " <select name=""ddlBeginMonth"" id=""ddlBeginMonth"" style=""width: 40px; height: 19px;"" >" strHTML = strHTML & " " & If(Page.IsPostBack = False, GetInitMonthVals(), RestoreMonth(Me.DDLBeginMonth)) strHTML = strHTML & " </select>" strHTML = strHTML & " <span id=""Label4"" style=""font-size: xx-small;"">月</span>" strHTML = strHTML & " </td>" strHTML = strHTML & " <td class=""auto-style1"">" strHTML = strHTML & " <select name=""ddlBeginDay"" id=""ddlBeginDay"" style=""width: 40px; height: 19px;"">" strHTML = strHTML & " " & If(Page.IsPostBack = False, GetInitDayVals(), RestoreDay(Me.DDLBeginDay)) strHTML = strHTML & " </select>" strHTML = strHTML & " <span id=""Label5"" style=""font-size: xx-small;"">日</span>" strHTML = strHTML & " <span id=""Label6"" style=""font-size: xx-small;"">~</span>" strHTML = strHTML & " </td>" strHTML = strHTML & " <td class=""auto-style1"">" strHTML = strHTML & " <select name=""ddlEndYear"" id=""ddlEndYear"" style=""width: 50px; height: 19px;"" >" strHTML = strHTML & " " & If(Page.IsPostBack = False, GetInitYearVals(), RestoreYear(Me.DDLEndYear)) strHTML = strHTML & " </select>" strHTML = strHTML & " <span id=""Label7"" style=""font-size: xx-small;"">年</span>" strHTML = strHTML & " </td>" strHTML = strHTML & " <td class=""auto-style1"">" strHTML = strHTML & " <select name=""ddlEndMonth"" id=""ddlEndMonth"" style=""width: 40px; height: 19px;"" >" strHTML = strHTML & " " & If(Page.IsPostBack = False, GetInitMonthVals(), RestoreMonth(Me.DDLEndMonth)) strHTML = strHTML & " </select>" strHTML = strHTML & " <span id=""Label8"" style=""font-size: xx-small;"">月</span>" strHTML = strHTML & " </td>" strHTML = strHTML & " <td class=""auto-style1"">" strHTML = strHTML & " <select name=""ddlEndDay"" id=""ddlEndDay"" style=""width: 40px; height: 19px;"">" strHTML = strHTML & " " & If(Page.IsPostBack = False, GetInitDayVals(), RestoreDay(Me.DDLEndDay)) strHTML = strHTML & " </select>" strHTML = strHTML & " <span id=""Label9"" style=""font-size: xx-small;"">日</span>" strHTML = strHTML & " </td>" strHTML = strHTML & " <td class=""auto-style1"">" strHTML = strHTML & String.Format(" <input name={0} type='submit' value='查詢' /> ", Me.UniqueID) strHTML = strHTML & " </td>" strHTML = strHTML & " </tr>" strHTML = strHTML & "</table>" writer.Write(strHTML) End Sub Sub InitControlSetting() For idxYear As Integer = Year(Now()) To 2000 Step -1 If idxYear = Year(Now) Then sbYearList.Append("<option selected=""selected"" value=" & idxYear.ToString() & "> " & idxYear.ToString() & "</option>") Else sbYearList.Append("<option value=" & idxYear.ToString() & ">" & idxYear.ToString() & "</option>") End If Next For idxMonth As Integer = 1 To 12 sbMonthList.Append("<option value=" & idxMonth.ToString() & "> " & idxMonth.ToString() & "</option>") Next For idxDay As Integer = 1 To 31 sbDayList.Append("<option value=" & idxDay.ToString() & "> " & idxDay.ToString() & "</option>") Next End Sub Function RestoreYear(strYear As String) As String sbYearList.Clear() For idxYear As Integer = Year(Now()) To 2000 Step -1 If idxYear = Integer.Parse(strYear) Then sbYearList.Append("<option selected=""selected"" value=" & idxYear.ToString() & "> " & idxYear.ToString() & "</option>") Else sbYearList.Append("<option value=" & idxYear.ToString() & ">" & idxYear.ToString() & "</option>") End If Next Return sbYearList.ToString() End Function Function RestoreMonth(strMonth As String) As String sbMonthList.Clear() For idxMonth As Integer = 1 To 12 If idxMonth = Integer.Parse(strMonth) Then sbMonthList.Append("<option selected=""selected"" value=" & idxMonth.ToString() & "> " & idxMonth.ToString() & "</option>") Else sbMonthList.Append("<option value=" & idxMonth.ToString() & "> " & idxMonth.ToString() & "</option>") End If Next Return sbMonthList.ToString() End Function Function RestoreDay(strDay As String) As String sbDayList.Clear() For idxDay As Integer = 1 To 31 If idxDay = Integer.Parse(strDay) Then sbDayList.Append("<option selected=""selected"" value=" & idxDay.ToString() & "> " & idxDay.ToString() & "</option>") Else sbDayList.Append("<option value=" & idxDay.ToString() & "> " & idxDay.ToString() & "</option>") End If Next Return sbDayList.ToString() End Function Private Function GetInitYearVals() As String Return sbYearList.ToString() End Function Private Function GetInitMonthVals() As String Return sbMonthList.ToString() End Function Private Function GetInitDayVals() As String Return sbDayList.ToString() End Function End Class End Namespace |
大概講解一下
經過compile後會生成一個dll可以添加參考
要兩部加入參考
Step1.對專案右鍵Add Reference(一般)
Step2.預設ToolBox並不會有Foci.NET.Web.ServerControl的控件èRight Click è選擇項目
這裡會產生一段說明文字
是我在組件編輯的(利於版本確認)
可以自行依據任職單位和開發時間點撰寫
Step3.請在預配置的aspx(front-end)文件頂部複製貼上此行再拖曳
Step4.可以讓你設置標題
Step5.Button事件註冊
由於我在我自行設計的Custom Server Control中有添加一個Click的 EventHandler委派
是透過實作IPostBackEventHandler 這個Interface去RaiseEvent的
因此後續其他工程師就可以直接外部去使用
這裡主要遇到的一個測試問題就是當發生PostBack(第一次之後的閃爍)就會遺失年月日資料
因此要做判斷處裡來保留
Reference:
ASP.NET - Custom Controls
https://www.tutorialspoint.com/asp.net/asp.net_custom_controls.htm
Custom server control in asp net
https://www.youtube.com/watch?v=Yb8SqkP2WWo
Asp net custom server controls Part 112
https://www.youtube.com/watch?v=UZkc-4R5lCw
留言
張貼留言