CSS,製作精美網站

  • 893
  • 0
  • 2022-07-04

CSS,製作精美網站

30天學會HTML+CSS,製作精美網站 :: 2021 iThome 鐵人賽 https://ithelp.ithome.com.tw/users/20112053/ironman https://ithelp.ithome.com.tw/images/ironman/13th/fb.jpg 30天學會HTML+CSS,製作精美網站 :: 2021 iThome 鐵人賽 https://ithelp.ithome.com.tw/users/20112053/ironman zh-TW Wed, 08 Jun 2022 20:17:04 +0800 版本控制與結語-30天學會HTML+CSS,製作精美網站 https://ithelp.ithome.com.tw/articles/10281753?sc=rss.iron https://ithelp.ithome.com.tw/articles/10281753?sc=rss.iron 終於來到了最後一章節,也算是蠻重要的「版本控制」

版本控制的好處是讓你可以知道自己修改了什麼東西,方便管理自己的code,在多人一起開發一個專案時,更是不可或缺的工具。

<...]]>
終於來到了最後一章節,也算是蠻重要的「版本控制」

版本控制的好處是讓你可以知道自己修改了什麼東西,方便管理自己的code,在多人一起開發一個專案時,更是不可或缺的工具。

因為自己是用MAC環境,所以以下範是用MAC環境進行

在MAC上安裝git

Step1. 到git官網下載
https://ithelp.ithome.com.tw/upload/images/20211015/20112053xvLnNhTNJZ.png
Step2. 點擊後,會有幾種安裝方法,我自己是選Homebrew
https://ithelp.ithome.com.tw/upload/images/20211015/20112053EYupcYz9z4.png

沒安裝過homebrew的,到homebrew官網進行安裝
完成後在終端機輸入以下指令安裝git

brew install git

Step3. 查看是否安裝成功

git --version

成功的話會有版本
https://ithelp.ithome.com.tw/upload/images/20211015/20112053PNd1t5V9tb.png

在github建立Repositories

下載完git後,要將檔案上傳到遠端儲存庫 github
Step1. 進入網站後,登入 GitHub,進入 GitHub 首頁,點選右上角「+」後,再點選「New repository」
https://ithelp.ithome.com.tw/upload/images/20211015/20112053Ia7Aa1tPvv.png
Step2. 建立一個空白的Git儲存庫,輸入Repository名稱(Repository name),還有是否公開、忽略檔案等設定
https://ithelp.ithome.com.tw/upload/images/20211015/20112053Rc2676nlNE.png
建立後,會有幾種方式讓你將本機的專案上傳到 GitHub 的遠端儲存庫中
https://ithelp.ithome.com.tw/upload/images/20211015/201120538kfOOREyfJ.png
如果是已經有上傳到 GitHub 的遠端儲存庫中,點擊紅框處複製
https://ithelp.ithome.com.tw/upload/images/20211015/20112053F1EGGWkQT4.png
在終端機打上「git clone 連結」,就可以將專案從遠端儲存庫中拉下來到本機
https://ithelp.ithome.com.tw/upload/images/20211015/20112053jDcPw9nYd4.png
下載到本機後,打開隱藏檔案會看到「.github」及「.gitignore」兩個檔案
https://ithelp.ithome.com.tw/upload/images/20211015/20112053b0BeEGoqDD.png

本地端建立git

下載github遠端儲存庫後,在VSCode安裝 「Git History」可以查看提交紀錄、提交給遠端儲存庫等資訊,就可以對你的專案做控管了
https://ithelp.ithome.com.tw/upload/images/20211015/20112053dTDwWpn5H7.png
git history 常用的

  1. 查看提交紀錄
    https://ithelp.ithome.com.tw/upload/images/20211015/20112053g1GWMsfXXk.png
  2. 檔案有更動時會出現提示,也可以提交跟拉取等
    https://ithelp.ithome.com.tw/upload/images/20211015/20112053M9gHIO1Svu.png
  3. 檔案比對
    https://ithelp.ithome.com.tw/upload/images/20211015/20112053GcFfMa8AeG.png

在前面改造你的VSCode,大幅提升你的Coding效率 這篇文章有分享vscode套件,有興趣的可以往前閱讀

git常用指令

除了有GUI介面管理版本庫,還能透過指令,以下介紹幾個常用的指令

  • git init:建立新的本地端 Repository
  • git clone [Repository URL]:複製遠端的Repository檔案到本地端
  • git status: 查詢版本控制狀態
  • git add [檔案或資料夾]/ git add.(加入全部檔案): 把檔案加入版本控制(放入暫存區)
  • git commit:提交目前的異動
  • git commit -m "提交說明內容":提交目前的異動並透過 -m 參數設定提交說明內容
  • git push:將本地端Repository的commit發佈到遠端
  • git push origin [BRANCH_NAME]:發佈至遠端指定的分支
  • git branch:查看分支
  • git branch [BRANCH_NAME]:建立分支
  • git checkout [BRANCH_NAME]:切換分支
  • git branch -D [BRANCH_NAME]:強制刪除分支

結論

這30天除了介紹html及css的基本觀念外,還加上我自己在製作時遇到的問題或是常用的寫法,希望能讓閱讀文章的你能夠在製作上能夠快速達到你要的結果。
最重要的是不可或缺的版本控制,他能夠控管你的程式碼歷程,在團隊開發時,也能避免修改好的檔案被覆蓋⋯之類的悲劇發生。
切版沒有什麼訣竅,就是多練習及參考別人的寫法。想要找參考網站可以到我這邊文章「找尋你的設計靈感、素材及好工具」去尋找你的靈感唷~
只要打好基礎,學會必備的觀念和語法,就是正式踏出製作網頁的第一步,以上是我這30天的分享,希望有幫助到正在學習的你....

]]>
sunny 2021-10-15 08:58:46
網頁框架比一比-30天學會HTML+CSS,製作精美網站 https://ithelp.ithome.com.tw/articles/10281570?sc=rss.iron https://ithelp.ithome.com.tw/articles/10281570?sc=rss.iron 介紹完如何製作響應式網站後,當然也會想說有沒有更快速的框架可以使用,所以今天就要來介紹目前最多人使用的Tailwind及Bootstrap

什麼是Tailwind CSS? 介紹完如何製作響應式網站後,當然也會想說有沒有更快速的框架可以使用,所以今天就要來介紹目前最多人使用的Tailwind及Bootstrap

什麼是Tailwind CSS?

Tailwind CSS 最初由Adam Wathan 開發,於2017 年11 月1 日首次發布。他是一個功能優先的框架,提供超超多單一功能的class名稱,像是文字大小、字型、背景色、框線等想得到的樣式,使用上自由程度高,讓我們能夠客製化任何元件,快速刻板。

優點

CSS Utility

提供多種不同的Utility,運用各種不同的 Utility 拼成想要的樣子。
就像樂高積木一樣,只需要將積木的零件,拼成你想要的樣子。

不用為了命名 CSS 煩惱

在撰寫的時候,有時候會為了命名共用樣式的名稱或是class名稱所困擾。

一個輕量級的CSS框架

會依照使用者使用的Utility,包裝成檔案,沒有使用到的就不會在裡頭,減少讀取的負擔

缺點

HTML看起來很凌亂,一大串的class名稱

<div class="font-sans font-bold text-3xl text-center text-indigo-600"> ... </div>

配置門檻高,適合有經驗的人

如果想直接使用CDN,他功能沒有這麼完善,且官網也不建議使用此方法。所以就要用PostCSS插件的方式來安裝 Tailwind CSS,官網列出使用CDN需要注意事項
https://ithelp.ithome.com.tw/upload/images/20211014/20112053D3teyIRTVY.png
詳細安裝說明可以到Tailwind CSS官方查看詳細安裝步驟

在VS Code上寫Tailwind時也有很好的插件輔助
https://ithelp.ithome.com.tw/upload/images/20211014/201120532N1oqSgjCl.png

什麼是Bootstrap?

Bootstrap 於2010 年年中作為Twitter 內部設計工具的一個分支啟動,並於2011 年8 月19 日成為開源框架。他已經有預先設置好基本樣式,不需要重頭自己自訂樣式,只要複製code就就可以了,像是表格、按鈕、表單、麵包屑等元件。

優點

組件類型CSS框架

提供很多不同類型的組件,可以快速的切出網頁及元件樣式。

不需要引入大量的 jQuery套件

bootstrap裡面有很多常用的組件,就不需要引入各種不同的jQuery套件,也不用套件之間會有衝突

缺點

檔案很大

不管你有沒有使用到元件,他就是完整的樣式檔案,如果需要制定樣式,就需要覆蓋默認的屬性,導致大量無效樣式加載

元件都樣式都長得差不多,客製化門檻高

直接套用Bootstrap元件,如果都不修改的話,每個網站的樣式看起來就都會一樣,甚至一看畫面就會知道是套用Bootstrap

結論

tailwind自由度高,可以完全客製化,但是HTML會滿滿的code,看起來會很凌亂;Bootstrap有現成的組件,在製作後台或是不需要美化的網站,可以快速開發,且很容易上手。因此tailwind與Bootstrap各有優缺點,要使用什麼框架還是要依需求和偏好來做選擇。

]]>
sunny 2021-10-14 20:07:30 響應式網站注意細節-30天學會HTML+CSS,製作精美網站 https://ithelp.ithome.com.tw/articles/10281254?sc=rss.iron https://ithelp.ithome.com.tw/articles/10281254?sc=rss.iron 現在使用智慧型手機比率最高,手機畫面很小,所以在製作網頁時應注意以下細節

只顯示重要的資訊及減少欄位數量

在手機或平板上,不像電腦可以閱讀大量資訊內容,所以要適當...]]> 現在使用智慧型手機比率最高,手機畫面很小,所以在製作網頁時應注意以下細節

只顯示重要的資訊及減少欄位數量

在手機或平板上,不像電腦可以閱讀大量資訊內容,所以要適當的縮減欄位數量及重要資訊內容
範例:電腦版有兩個區塊左邊是文字右邊是圖片,在手機版時,隱藏了左邊欄位,並將文字與圖片重疊
https://ithelp.ithome.com.tw/upload/images/20211013/20112053j0jelf28iW.jpg
圖片來源

改變排版方式

範例:像是選單,在電腦版會展開所有選單按鈕,在手機版時會將選單收起來,點擊漢堡選單才會展開選單內容
https://ithelp.ithome.com.tw/upload/images/20211013/20112053QcF68UkjJf.jpg
圖片來源

字體大小及間距要縮小

因手機螢幕很小,適當將距離、留白及文字縮小,提高閱讀可讀性
範例:在手機版時,會修改文字大小、間距及排版
https://ithelp.ithome.com.tw/upload/images/20211013/20112053DfaROipAvE.jpg
圖片來源

以觸控螢幕為出發點

電腦是使用滑鼠,按鈕或連結不需要很大的範圍,但在行動裝置上的點擊是手指頭,所以在按鍵或連結要有適當的間距,才容易被點擊或是誤點的問題
Google與Apple制訂的設計規範,建議觸控區域最小尺寸為 44px,像是社群平台instagram 下方bar的按鈕,高度就是在44px,寬度欄位平均分配
https://ithelp.ithome.com.tw/upload/images/20211013/20112053Jq5Hi5TUBh.png

移除 safari input select預設樣式

在safari表單元件添加了各種預設樣式,有時候改了樣式,在safari都不會有效果,因此使用appearance的樣式可以移除系統預設樣式。

select{
	/*移除預設樣式*/
	-webkit-appearance: none;  /* Safari 和 Chrome,常用於iOS下移除內建樣式 */
  -moz-appearance: none;     /* FireFox */
  appearance: none;
}

https://ithelp.ithome.com.tw/upload/images/20211013/20112053DFymejXzfy.png
移除後,下拉選單的箭頭就不見,可以透過樣式添加自己想要的下拉選單箭頭

<select class="form-control">
  <option>2021/09</option>
  <option>2021/10</option>
</select>
select {
  width: 130px;
  padding:5px 25px 5px 8px;
  background-color: #fff;
  background-clip: padding-box;
  border-radius: 0.25rem;
  border-radius: 8px;
  border: 1px solid #ff786e;
	line-height: 1;
	/*將預設的select選擇框樣式清除*/
  appearance: none;
  -moz-appearance: none;
  -webkit-appearance: none;
	/*箭頭樣式及箭頭位置*/
  background: url(img/arr.png) no-repeat scroll 96% center #fff;
  background-size: 13px 8px;
  outline: 0;
}

https://ithelp.ithome.com.tw/upload/images/20211005/20112053xwxDC8Wsse.png

點擊Input輸入框畫面放大

當使用行動裝置時,點擊輸入框時畫面被放大,解決方式有以下兩種方法

使用meta tag 禁止畫面縮放

<head>設定,但使用這方法連畫面縮放功能也被禁止了

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />

CSS 設定

使用此方法還能保留畫面的縮放功能

input, textarea {
	font-size: initial;
}

另外google也提供PageSpeed Insights為你的網站打分數,給予改善的建議
以上是製作響應式網站需要注意的細節,希望對你在製作上能提供更好的設計與體驗給使用者

參考網站:
https://www.astralweb.com.tw/stop-zoom-in-on-input-focus-on-mobile-devices/

]]> sunny 2021-10-13 20:39:35
製作響應式網站-30天學會HTML+CSS,製作精美網站 https://ithelp.ithome.com.tw/articles/10280892?sc=rss.iron https://ithelp.ithome.com.tw/articles/10280892?sc=rss.iron 響應式網頁設計是什麼

響應式網頁設計(Responsive Web Design)簡稱RWD,是開發網頁設計中的一種方法,在不改變網站結構,隨著顯示螢幕的大小調整網站的外觀和佈...]]> 響應式網頁設計是什麼

響應式網頁設計(Responsive Web Design)簡稱RWD,是開發網頁設計中的一種方法,在不改變網站結構,隨著顯示螢幕的大小調整網站的外觀和佈局。

如何製作響應式

設定viewport

<meta name="viewport" content="width=device-width, initial-scale=1.0">

屬性:

  • width 設定畫面寬度 (數值/ device-weight)
  • height 設定畫面高度 (數值/ device-height)
  • initial-scale 設定畫面的初始縮放比例 (Min-0.25, Max-5)
  • minimum-scale 設定畫面的最小縮放比例 (Min-0.25, Max-5)
  • maximum-scale 設定畫面的最大縮放比例 (Min-0.25, Max-5)
  • user-scalable 設定是否允許使用者改變縮放比例 (1/0)

媒體查詢(Media Queries)

會使用@media(尺寸) CSS來設置,根據網頁畫面大小設定不同的樣式

media queries使用方法

在 HTML 引入
<html>
  <head>
    <title>title</title>
    <link rel="stylesheet" media="screen" href="css/style.css">
    <link rel="stylesheet" media="print" href="css/print.css">
  </head>
</html>
使用 @import
@import url("style.css") screen;
@import url("print.css") print;
在 CSS 內使用
@media screen {
  body { font-size: 16px; }
}
@media print {
  body { font-size: 14px; }
}

媒體類型(Media Type)

媒體類型是指在不同裝置及螢幕尺寸,使用哪一個CSS樣式

  • all:用於所有設備
  • print:印刷裝置,預覽列印或是印表機
  • screen:螢幕裝置,電腦螢幕、手機、平板
  • speech:音訊合成裝置

媒體特性(Media Feature)

  • width:寬度
  • height:高度
  • aspect-ratio:螢幕比例
  • orientation
    有portrait 為直向,landscape 為橫向

Media Queries邏輯

and

兩個都成立才會是true
範例:最小寬度要414px及最大寬度要767px,才會做裡面的樣式

@media (min-width: 414px) and (max-width:767) { ... }

or

只要滿足一個條件,就會是true

or要用「,」逗號表示,否則會報錯

範例:最大寬度要414px或是最小寬度要767px,滿足其中一個條就,就會做裡面的樣式

@media (max-width:414px) , (min-width:767) { ... }

not

對Media Queries進行反向操作
範例:寬度大於375就會做裡面的樣式

@media not screen and (max-width:375px){ ... }

only

用來指定某種裝置媒體才能套用某些樣式

not 和 only 後方必須先接 media type ( 像是 screen 或 print ),不然會沒有作用

響應式網站優點

  • 無需維護多個裝置且相同內容的網頁,減少維護時間成本
  • 單一網址,利於分享網頁
  • 單一連結,可以避免重覆的內容,有利增加搜尋引擎曝光度

結論

以上是媒體查詢製作響應式網站的使用方法,在設定樣式時盡可能的不要寫固定數值,像是px像素,改為%、vw...相對單位(在網頁常用單位-30天學會HTML+CSS,製作精美網站 ,有做過說明,有興趣的可以到此連結看看),或是使用max-width解決在手機版會跑版問題。

參考網站:
https://www.oxxostudio.tw/articles/201810/css-media-queries.html
https://developers.google.com/search/mobile-sites/mobile-seo/responsive-design?hl=zh-tw
https://codingdailyblog.wordpress.com/2017/07/20/html-viewport的設定與屬性/

]]> sunny 2021-10-12 19:11:25
網頁變形-30天學會HTML+CSS,製作精美網站 https://ithelp.ithome.com.tw/articles/10280398?sc=rss.iron https://ithelp.ithome.com.tw/articles/10280398?sc=rss.iron transform屬性是變形的意思,可運用在2D及3D變形,可以對網頁元素做旋轉、縮放、平移、傾斜、矩陣變形的效果。但不適用於「行內元素」

transform: none|transform-function;

transform-function轉換效果共有五種

  • 平移 translate
  • 縮放 scale
  • 旋轉 roate
  • 傾斜 skew
  • 矩陣變形 matrix

為了讓瀏覽器有良好的支援,需使用瀏覽器前綴前綴

-moz-     /* firefox瀏覽器 */
-webkit-  /* Safari, google瀏覽器 */
-o-       /* Opera瀏覽器(早期) */
-ms-      /* Internet Explorer  */

以下來各別介紹每個使用方法

transform

translate 平移

將元素或物件設定水平或垂直方向移動

單位:px或百分比,可以是正數及負數

寫法:

  • 合併:translate(x,y)
  • 單一方向:translateX(x)、translateY(y)
    範例:左邊是預設位置,右邊class="transform"設置了transform(50,100),當前位置向右移動50px,向下移動100px
<div class="box">
  transform
  <div class="transform block">
  </div>
</div>

.transform{
  transform: translate(50px,100px); 
	background-color: #3f51b5;
  width: 100px;
  height: 100px;
}

https://ithelp.ithome.com.tw/upload/images/20211011/20112053V0JtRpuR7i.png
單一邊設置,transformX(50),向右移動50px

.transform{
  transform: translateX(50px); 
}

https://ithelp.ithome.com.tw/upload/images/20211011/20112053Cqd5vS41RG.png

scale 縮放

將元素放大或縮小。預設為1,大於1代表放大;小於1代表縮小

單位:純數值倍率

寫法:

  • 單一方向:scaleX(x)、scaleY(y)
  • 合併:scale(x,y)

範例:左邊是預設寬度100px,高度100px,右邊class="transform"設置了scale(1.5),原本元素放大了1.5倍,寬度變150px

.transform{
  transform: scale(1.5);
	width: 100px;
  height: 100px;
}

https://ithelp.ithome.com.tw/upload/images/20211011/20112053dkIudIVnk3.png
右邊class="transform"設置了scale(0.5),原本元素縮小了0.5倍,寬度變50px

.transform{
  transform: scaleX(0.5);
}

https://ithelp.ithome.com.tw/upload/images/20211011/201120538NAEzOZPRY.png
單一邊設置,scaleX(1.5),X軸(水平軸)放大1.5倍,寬度150px,高度維持100px

.transform{
  transform: scaleX(1.5);
	width: 100px;
  height: 100px;
}

https://ithelp.ithome.com.tw/upload/images/20211011/20112053epfOwTai5b.png

roate 旋轉

將元素設定旋轉

單位:deg(度數)。正值表示順時針,負值表示逆時針。

範例:左邊是預設,右邊旋轉20度

.transform{
  transform: rotate(20deg);
}

https://ithelp.ithome.com.tw/upload/images/20211011/20112053oTQpyIHQ6z.png
rotate為-20度,會逆時針旋轉

.transform{
  transform: rotate(-20deg);
}

https://ithelp.ithome.com.tw/upload/images/20211011/2011205309VtpLpdFy.png

skew 傾斜

將元素傾斜

單位:deg。正數表示向左傾斜,負值表示向右傾斜

寫法:

  • 單一方向:skewX()、skewY()
  • 合併:skew(x,y)
    範例:單一邊傾斜
.transform{
  transform: skewX(60deg);
  
}

https://ithelp.ithome.com.tw/upload/images/20211011/20112053riwqxNOqxM.png
x,y軸一起設定傾斜


.transform{
 transform: skew(30deg, 30deg)
  
}

https://ithelp.ithome.com.tw/upload/images/20211011/20112053XfVNbIxhXX.png

matrix 矩陣變形

把6種變形函式組合成一個矩陣進行的變形組合

transform:matrix(scaleX(),skewY(),skewX(),scaleY(),translateX(),translateY())

transform

使用transform可以一次套用多個變形函式(旋轉、縮放...)

範例:一次設置角度、傾斜、平移

transform:rotate(20deg) skew(50deg) translateX(20px);

https://ithelp.ithome.com.tw/upload/images/20211011/20112053ICvffH8PWV.png

transform-origin 變形原點

變形時,預設的變形原點都是物件或DOM元素的中心點,使用transform-origin可以改變變型的基準點
範例:旋轉角度設置transform-origin 位置

<div class="box">
    <div class="transform1 block">
      roate:60deg <br/>
      left top
    </div>
  </div>
  <div class="box">
    <div class="transform2 block">
      roate:60deg <br/>
      center center
    </div>
  </div>
  <div class="box">
    <div class="transform3 block">
      roate:60deg <br/>
      right bottom
    </div>
  </div>
.block{
  background-color: #3f51b5;
  width: 100px;
  height: 100px;
  box-sizing: border-box;
  padding: 10px;
  color: #fff;
}
.transform1{
  transform-origin: left top;
  transform: rotate(60deg);
}
.transform2{
  transform-origin: center center;
  transform: rotate(60deg);
}
.transform3{
  transform-origin: right bottom;
  transform: rotate(60deg);
}

https://ithelp.ithome.com.tw/upload/images/20211011/20112053VB8e93Dn1x.png

]]> sunny 2021-10-11 11:59:23
網頁動起來-30天學會HTML+CSS,製作精美網站 https://ithelp.ithome.com.tw/articles/10279568?sc=rss.iron https://ithelp.ithome.com.tw/articles/10279568?sc=rss.iron 在設計網頁時通常會加一些動畫特效,吸引使用者的目光及添加與使用者的互動性。
過去製作動畫時以Flash為主,CSS3也可以建立動畫,不再只能用JavaScript或jQuery 才做...]]>
在設計網頁時通常會加一些動畫特效,吸引使用者的目光及添加與使用者的互動性。
過去製作動畫時以Flash為主,CSS3也可以建立動畫,不再只能用JavaScript或jQuery 才做得到了

transition 漸變

transition-duration漸變效果時間

  • time:可以設定秒(s)或毫秒(ms),如果有多個屬性要分開執行,要用逗號隔開

transition-property漸變效果屬性

transition-property: none|all|property;
  • none:不會產生漸變效果
  • all:所有屬性會有漸變效果
  • property:設定有漸變效果的名稱,有多個屬性用逗號隔開
<h1>test</h1>
h1{
	height:100px;
	background-color:yellow;
	transition-property:color,background,height;
	transition-duration:3s;
}
h1:hover{
	color:red;
	background-color:green;
	height:300px
}

transition-delay漸變時間延遲

transition-delay: time;
  • time:設定延遲時間,單位可以是秒(s)或毫秒(ms),

transition-timing-function漸變速度

transition-timing-function: value;
  • ease:預設值,低速開始,加快,結束減速
  • ease-in:低速開始
  • ease-out:低速結束
  • ease-in-out:低速開始,低速結束
  • linear:均速
  • cubic-bezier(x1,y1,x2,y2):利用貝茲曲線自定義速度模式

以下推薦兩個設定cubic-bezier不錯的網站給大家參考

  • 自訂曲線:建立曲線,創造動畫不同的執行速度
    https://ithelp.ithome.com.tw/upload/images/20211009/2011205303CNcO7hPx.png
  • Easing Functions:這網站列出很多已經建好的函式形式,可以直接套用
    https://ithelp.ithome.com.tw/upload/images/20211009/20112053xTXUM81dEZ.png

transition簡易寫法

順序為:

transition: property duration timing-function delay | initial | inherit
.box{
	width:100px;
	height:100px;
	background:blue;
	transition:width,height 3s;
	-moz-transition:width,height 3s; /* Firefox 4 */
	-webkit-transition:width,height 3s; /* Safari and Chrome */
	-o-transition:width,height 3s; /* Opera */
}
.box:hover{
	width:400px;
	height:300px;
}

animation 動畫

使用時要再加上前綴,讓屬性在每個瀏覽器能夠支援

-moz-     /* firefox瀏覽器 */
-webkit-  /* Safari, google瀏覽器 */
-o-       /* Opera瀏覽器(早期) */
-ms-      /* Internet Explorer  */

animation-name 動畫名稱

animation-name是設定@keyframes動畫名稱

animation-name: keyframe動畫名稱

要與animation-duration屬性搭配,不然動畫不會執行

animation-duration 動畫時間

animation-duration: time;
  • time:完成動畫所需完成時間。可以設定秒(s)或毫秒(ms),如果有多個屬性要分開執行,要用逗號隔開

animation-direction 動畫方向

animation-direction: normal|alternate;
  • normal:預設
  • reverse:反向
  • alternate:正向,再反向(奇數正常播放,偶數反向播放)
  • alternate-reverse:反向,再正向

animation-delay 動畫延遲時間

animation-delay: time;
  • time:可以設定秒(s)或毫秒(ms)

animation-duration 和 animation-delay前者是動畫持續時間,後者為動畫延遲時間

animation-timing-function

動畫的速度曲線

animation-timing-function: value
  • ease:預設值,低速開始,加快,結束減速
  • ease-in:低速開始
  • ease-out:低速結束
  • ease-in-out:低速開始,低速結束
  • linear:均速
  • cubic-bezier(x1,y1,x2,y2):利用貝茲曲線自定義速度模式

animation-iteration-count動畫次數

animation-iteration-count: number |infinite

number:播放次數,預設是1,0的不會執行

inifinite:無限次數執行

animation-play-state 動畫執行或暫停

animation-play-state: paused|running
  • running:預設,動畫是執行狀態
  • paused:動畫暫停

animation-fill-mode動畫延遲與完成

  • none:預設,無樣式
  • forwards:動畫完成後,保持最後關鍵影格樣式
  • backwards:動畫在延遲時,保持最初動畫關鍵影格
  • both:遵照forwards及backwards,動畫在延遲時,保持最初動畫關鍵影格樣式。動畫完成後,保持最後動畫關鍵影格樣式

animation簡易法

順序為:

animation: name duration timing-function delay iteration-count direction;
<div class="box"></div>
.box{
	width:100px;
	height:100px;
	background:orange;
	position:relative;
	animation:mymove 5s infinite;
	-webkit-animation:moveBox 5s infinite; /*Safari and Chrome*/
}

@keyframes movebox{
	from {left:0px;}
	to {left:200px;}
}
 /*Safari and Chrome*/
@-webkit-keyframes movebox{
	from {left:0px;}
	to {left:200px;}
}

@keyframes 關鍵影格

@keyframes animationname {
	keyframes-selector {
		css-styles;
	}
}
  • animationname:影格名稱
  • keyframes-selector:可以使用百分比(0%-100%)、from-to(from與0%相同、to與100%相同)
  • css-styles:CSS屬性

搭配frome-to來做動畫設定

.box{
	position:relative;
	animation:moveBox 5s infinite;
}
@keyframes moveBox{
	from {top:0px;}
	to {top:200px;}
}

搭配百分比來做動畫設定

.box{
	position:relative;
	animation:moveBox 5s infinite;
}
@keyframes moveBox{
	0% {background: red;}
  50% {background: green;}
  100% {background: blue;}
}

CSS動畫特效庫

除了自己寫動畫,網路上也有CSS 的動畫特效庫

Animation.css
https://ithelp.ithome.com.tw/upload/images/20211009/20112053SBpPxrXQHa.png
需要引入css檔案,安裝方式有兩種

方法一:CDN方式

<link href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" />

方法二:npm或yarn

npm

npm install animate.css --save

yarn

yarn add animate.css

下載完後再import

import "animate.css"

只要在標籤元素添加class名稱animate__animated以及任一動畫名稱如 animate__bounce(記得前綴 animate__!)就會有效果了

<h1 class="animate__animated animate__bounce">An animated element</h1>

Animista

裡面提供數十種的淡入、淡出、旋轉等效果,不需要額外引入JS,只要選好自己的樣式後,點選右上角的 {‧} 按鈕,檢視原始碼,把他複製到你的檔案裡面了
https://ithelp.ithome.com.tw/upload/images/20211009/20112053BsQ3DgYBnW.png
https://ithelp.ithome.com.tw/upload/images/20211009/20112053j2NIUrCI8M.png

結論

介紹了漸變與動畫,你一定會問他們兩者之間有什麼差別,transition是需要被觸發才會執行,像是滑鼠移入(hover)效果,animation則是直接就執行。。

]]>
sunny 2021-10-10 07:24:16
網頁編排Grid-30天學會HTML+CSS,製作精美網站 https://ithelp.ithome.com.tw/articles/10279569?sc=rss.iron https://ithelp.ithome.com.tw/articles/10279569?sc=rss.iron Grid是什麼

Grid是磚牆式版面,使用二維的排版方式,與flexbox不同的地方是Grid一次可以控制水平及垂直方向。Grid像是美工軟體,有許多參考線幫助你定位,要將元素...]]> Grid是什麼

Grid是磚牆式版面,使用二維的排版方式,與flexbox不同的地方是Grid一次可以控制水平及垂直方向。Grid像是美工軟體,有許多參考線幫助你定位,要將元素設定相同大小、間距的排列都可以使用Grid製作。
Grid是由父元素(Grid Container)和子元素(Grid items)組成。子元素之間的空隙,為格線間距(Grid gap)。
目前瀏覽器支援較新版本的瀏覽器,想看瀏覽器支援可以到 can i use 網站
https://ithelp.ithome.com.tw/upload/images/20211009/20112053S9GTmpGM8y.png

區塊宣告

display: grid/inline-grid
  • grid:類似display:block
  • inline-grid:類似display:inline-block

grid-template-columns & grid-template-rows

grid-template-columns:定義容器有多少欄;grid-template-rows:定義容器有多少列
要製作一個 4x3 的容器可以這樣寫,每個區塊的寬度為auto(適螢幕寬度大小來決定),高度為100px

<div class="grid-container">
  <div class="item1">1</div>
  <div class="item2">2</div>
  <div class="item3">3</div>  
  <div class="item4">4</div>
  <div class="item5">5</div>
  <div class="item6">6</div>
  <div class="item7">7</div>
  <div class="item8">8</div>
  <div class="item9">9</div>
  <div class="item10">10</div>
  <div class="item11">11</div>
  <div class="item12">12</div>
</div>
.grid-container {
  display: grid;
  grid-template-columns: auto auto auto auto;
  grid-template-rows: 100px 100px 100px;
  grid-gap: 10px;
  background-color: #2196F3;
  padding: 10px;
}

.grid-container > div {
  background-color: #d7ebfd;
  text-align: center;
  padding: 20px 0;
}

https://ithelp.ithome.com.tw/upload/images/20211009/20112053oR4W9OnXPB.png

使用單位

fr

fr為fraction比例的縮寫,會依照畫面寬度比例伸縮。

.grid-container {
  display: grid;
  grid-template-columns: 1fr 2fr 2fr 1fr;
}

https://ithelp.ithome.com.tw/upload/images/20211009/201120531AYsnOBGPD.png

max-content / min-content

  • max-content:取得項目最大的尺寸當作填充條件
  • min-content:取得項目最小的尺寸當作填充條件

minmax()

一個長度範圍。minmax(最小值, 最大值)
範例中,minmax(100px, 1fr)表示寬度不小於100px,不大於1fr。

.grid-container {
  display: grid;
  grid-template-columns: 1fr 2fr minmax(100px, 1fr) 1fr;
}

https://ithelp.ithome.com.tw/upload/images/20211009/20112053HwqL838p3r.jpg

auto

自動設定項目尺寸

長度單位

像是px, %...

repeat

可以不用重複寫一樣的設定

.grid-container {
  display: grid;
  grid-template-columns: repeat(5,1fr);
}

https://ithelp.ithome.com.tw/upload/images/20211009/201120532aArFXC12F.png

auto-fill / auto-fit

  • auto-fill:自動填滿重複的單元格數量
  • auto-fit:與auto-fill相同。如果沒有彈性項目,那個網格單元格就會被折疊起來
    這兩者差別在當網頁寬度特別寬,且沒有填滿時,auto-fill會有匿名的格子
    https://ithelp.ithome.com.tw/upload/images/20211009/20112053fN16tK4PJP.png
.grid-container {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
}

auto-fit會將後面表格合併成一個
https://ithelp.ithome.com.tw/upload/images/20211009/20112053nNDOXckoyS.png

.grid-container {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
}

grid-template-areas & grid-area

grid-template-areas用來定義每個單元格的名稱,可以使用grid-area指定名稱跟放置位置

<div class="grid-container">
  <div class="item1">header</div>
  <div class="item2">sider</div>
  <div class="item3">main</div>  
  <div class="item4">footer</div>
</div>

指定區域名稱,當不使用該區域時,可以使用點 . (點)來略過。

.grid-container {
  display: grid;
  grid-template-columns: repeat(3,1fr);
  grid-template-rows: 80px 300px 50px;
  grid-template-areas: "header header header"
  "sider main main"
  "sider footer ."
}
.item1{
  background-color: #00bcd4;
  grid-area: header;
}
.item2{
  background-color: #ffc107;
  grid-area: sider;
}
.item3{
  background-color: #cddc39;
  grid-area: main;
}
.item4{
  background-color: #607d8b;
  grid-area: footer;
}

https://ithelp.ithome.com.tw/upload/images/20211009/20112053ooUwBIYl1r.png

grid-auto-flow

row:預設值,由左至右,由上到下

.grid-container {
  display: grid;
  grid-template-columns: repeat(3, auto);
  grid-template-rows: repeat(2, auto);
  grid-auto-flow: row;
}

https://ithelp.ithome.com.tw/upload/images/20211009/20112053WzewbLCylR.png

column 由上到下,由左到右

.grid-container {
  display: grid;
  grid-template-columns: repeat(3, auto);
  grid-template-rows: repeat(2, auto);
  grid-auto-flow: column;
}

https://ithelp.ithome.com.tw/upload/images/20211009/20112053K5KaKXQLfk.png

dense 填補空缺

row dense

第三區塊比較大,如果止血grid-auto-flow:row,就會有空缺
https://ithelp.ithome.com.tw/upload/images/20211009/20112053F4Tdw5TGFi.png
將grid-auto-flow改為row dense,第四區塊就會去填補空缺

.grid-container {
  display: grid;
  grid-template-columns: repeat(3, auto);
  grid-template-rows: repeat(2, auto);
  grid-gap: 5px;
  background-color: #2196F3;
  padding: 10px;
  grid-auto-flow:row dense;
}
.item3 { 
  grid-column: auto / span 2; 
}

https://ithelp.ithome.com.tw/upload/images/20211009/20112053FvE8Teqw07.png

column dense

第二區塊起始位置從第三區塊開始,他前面就有一個空缺

.grid-container {
  display: grid;
  grid-template-columns: repeat(3, auto);
  grid-template-rows: repeat(2, auto);
  grid-gap: 5px;
  background-color: #2196F3;
  padding: 10px;
  grid-auto-flow:column;
}
.item2{ 
  grid-row-start:3; 
}

https://ithelp.ithome.com.tw/upload/images/20211009/20112053UEb4xiZ0rq.png
所以,在grid-auto-flow改為column dense;第三區塊就去補空缺位置
https://ithelp.ithome.com.tw/upload/images/20211009/20112053JzMHpjVY37.png

gap 子元素空隙寬度

grid-column-gap:水平欄位的間隔

https://ithelp.ithome.com.tw/upload/images/20211009/20112053dboOqgFhh9.png

grid-row-gap:垂直欄位的間隔

.grid-container {
  grid-row-gap:20px;
}

https://ithelp.ithome.com.tw/upload/images/20211009/20112053COspl3L55y.png

gap 結合上述兩種縮寫的方式

gap: row-gap column-gap

垂直間距:20px 水平間距:10px

.grid-container {
  gap: 20px 10px; 
}

https://ithelp.ithome.com.tw/upload/images/20211009/20112053nQzf1uDi16.png
垂直水平間距相同gap:10px;

.grid-container {
  gap: 10px; 
}

https://ithelp.ithome.com.tw/upload/images/20211009/20112053tD4hkPsVEj.png

內部容器

Grid line

grid-column

  • grid-column-start:水平方向開始起始格線位置
  • grid-column-end:水平方向結束的格線位置
  • auto:默認值
  • span n:物件所佔的空間數

grid-row

  • grid-row-start:垂直方向開始的格線位置
  • grid-row-end:垂直方向結束的格線位置
.item2{ 
  grid-column-start: 3; /* 起始位置從3開始 */
  grid-column-end: span 3; /* 跨三區塊 */
}

grid-column及grid-row,可以使用斜線 (/) 將起始位置/結束位置隔開,上面的code可以簡寫成:


.item2{ 
  grid-column: 3 / span 3;
}

https://ithelp.ithome.com.tw/upload/images/20211009/20112053AgYHdCf71I.png

對齊

方式與flexbox相同

justify-content

  • start:靠左對齊
  • end:靠右對齊
  • center:靠中間對齊
  • stretch:依照比例拉寬到滿版
  • space-around:內容間距都會平均分配

align-content

  • start:靠左對齊
  • end:靠右對齊
  • center:靠中間對齊
  • stretch:依照比例拉高到滿版
  • space-around:內容間距都會平均分配
  • space-between:平均分配內容,會對齊行頭及行尾
  • space-evenly:效果同 space-around 空白比space-around多

結論

介紹完grid的每個樣式功能,讓我們用一個完整個切版來做整理

步驟一:建立一個並將圖片插入html裡

<div class="box">
  <div class="item">
    <img src="img/img2.jpg" alt="">
  </div>
  <div class="item">
    <img src="img/img.jpg" alt="">
  </div>
  <div class="item">
    <img src="img/img3.jpg" alt="">
  </div>
  <div class="item">
    <img src="img/img4.jpg" alt="">
  </div>
  <div class="item">
    <img src="img/img5.jpg" alt="">
  </div>
  <div class="item">
    <img src="img/img6.jpg" alt="">
  </div>
  <div class="item">
    <img src="img/img7.jpg" alt="">
  </div>
  <div class="item">
    <img src="img/img.jpg" alt="">
  </div>
  <div class="item">
    <img src="img/img2.jpg" alt="">
  </div>
  <div class="item">
    <img src="img/img3.jpg" alt="">
  </div>
  <div class="item">
    <img src="img/img4.jpg" alt="">
  </div>
  <div class="item">
    <img src="img/img5.jpg" alt="">
  </div>
  <div class="item">
    <img src="img/img6.jpg" alt="">
  </div>
 </div>
.box{
  max-width: 1000px;
  margin: 0 auto;
  display: grid;
  gap: 10px;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}

gap設定留白距離
grid-template-columns設定repeat(重複次數),因為圖片寬度都一樣
auto-fit:讓元素依畫面寬度自動換行
mixmax(300px, 1fr),表示元素的寬度不會小於300px,並會符合畫面縮放
https://ithelp.ithome.com.tw/upload/images/20211009/20112053rXsPcJPBCx.png

步驟二:圖片尺寸不同,用object-fit屬性裁切圖片

.box img{
  height: 100%;
  width: 100%;
  object-fit: cover;
  object-position: center center;
}

https://ithelp.ithome.com.tw/upload/images/20211009/20112053aBmRssJyIS.png
步驟三:將第一張圖item設定big-box

設定grid-column水平範圍的寬度(黃色數字)及grid-row垂直範圍的高度(紫色數字),1/3 為開始線/終止線
https://ithelp.ithome.com.tw/upload/images/20211009/20112053Dyh4fOaQu8.jpg

<div class="box">
  <div class="item big-box">
    <img src="img/img2.jpg" alt="">
  </div>
	...
</div>
.big-box{
  grid-column: 1/3;
  grid-row: 1/3;
}

https://ithelp.ithome.com.tw/upload/images/20211009/20112053H1zORGrx4O.png
步驟四:隨螢幕裝置縮放將big-box grid-column屬性及row-column屬性設定auto

@media(max-width:414px){
  .big-box{
    grid-column: auto;
    grid-row: auto;
  }
}

https://ithelp.ithome.com.tw/upload/images/20211009/20112053YxsyKJFBpF.png
https://ithelp.ithome.com.tw/upload/images/20211009/2011205352wJacTVCK.png
這樣就完成啦~

完整的css樣式整理

.box{
  max-width: 1000px;
  margin: 0 auto;
  display: grid;
  gap: 10px;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}
.big-box{
  grid-column: 1/3;
  grid-row: 1/3;
}
.box img{
  height: 100%;
  width: 100%;
  object-fit: cover;
  object-position: center center;
}
@media(max-width:414px){
  .big-box{
    grid-column: auto;
    grid-row: auto;
  }
}

資料來源:
https://medium.com/enjoy-life-enjoy-coding/css-所以我說那個版能不能好切一點-grid-基本用法-cd763091cf70
https://developer.mozilla.org/zh-TW/docs/Web/CSS/CSS_Grid_Layout/Basic_Concepts_of_Grid_Layout

]]> sunny 2021-10-09 09:40:54
Flexbox-30天學會HTML+CSS,製作精美網站 https://ithelp.ithome.com.tw/articles/10279147?sc=rss.iron https://ithelp.ithome.com.tw/articles/10279147?sc=rss.iron 以前排版都會使用float、display屬性的block、inline來製作,現在有了Flexbox,幾乎可以解決各種排版需求。

Flexbox是什麼

flex...]]> 以前排版都會使用float、display屬性的block、inline來製作,現在有了Flexbox,幾乎可以解決各種排版需求。

Flexbox是什麼

flex 是Flexible Box的縮寫,中文為彈性布局,是由 Flex Containers (父元素)和 Flex Items (子元素)他組成,依據單一 橫向或垂直方向放置內容,可以解決過去複雜的版面配置問題,像是水平垂直置中。
https://ithelp.ithome.com.tw/upload/images/20211008/20112053gGHpANzHYH.png

彈性區塊宣告

display: flex/inline-flex
  • flex:區塊層級,類似display:block
  • inline-flex:行內層級,類似display:inline-block
    範例:分別將.box設置flex及inline-flex,文字的部分一個會換行,另一個不會
<div class="box">
    <div class="item">item</div>
    <div class="item">item</div>
    <div class="item">item</div>
  </div>
  <span>text</span><div class="flex">
    <div class="box">
      <div class="item">item</div>
      <div class="item">item</div>
      <div class="item">item</div>
    </div>
    <span>display:flex</span>
  </div>
  <div class="inline-flex">
    <div class="box">
      <div class="item">item</div>
      <div class="item">item</div>
      <div class="item">item</div>
    </div>
    <span>display:inline-flex</span>
  </div>
.box{
  width: 350px;
  padding: 15px 10px;
  background-color: #dee2e8;
}
.item{
  width: 100%;
  padding: 15px;
  text-align: center;
  background-color: #bdc2ca;
  margin: 0 5px;
}
.flex .box{
  display: flex;
}
.inline-flex .box{
  display: inline-flex;
}

https://ithelp.ithome.com.tw/upload/images/20211008/20112053hkfqCBDYwW.png

Flex Container

flex-direction

設定子元素排列方向,水平或是垂直

屬性

  • row:由左到右,由上到下,預設值
  • row-reverse:與row相反
  • column:由上到下,由左到右
  • column-reverse:與column相反
    https://ithelp.ithome.com.tw/upload/images/20211008/20112053xdgllbdUXX.png

flex-wrap

讓子元素排成一行或多行,當子元素超過父元素寬度時是否要換行。

屬性

  • nowrap:單行,預設值
  • wrap:多行
  • wrap-reverse:單行,反轉
    https://ithelp.ithome.com.tw/upload/images/20211008/20112053cG4UQ9MYD1.png

flex-flow

是flex-direction及flex-wrap的簡寫

flex-flow: flex-direction flex-wrap

justify-content

水平對齊方式

屬性

  • flex-start:預設值,靠左對齊,從行頭開始
  • flex-end:靠右對齊,從行尾開始
  • center:水平置中對齊
  • space-between:平均分配內容,會對齊行頭及行尾
  • space-around:內容間距都會平均分配
    https://ithelp.ithome.com.tw/upload/images/20211008/20112053jsqZ8gCU8w.png

align-items

垂直對齊方式

屬性

  • stretch:預設值,元素高度會填滿容器高度
  • flex-start:對齊父元素起始位置開始排列
  • flex-end:對齊父元素終點位置開始排列
  • center:垂直置中對齊
  • baseline:內容的基線作為對齊線
    https://ithelp.ithome.com.tw/upload/images/20211008/20112053uz0pkzIsy4.png

align-content

與align-items相似,只是align-content是處理多行,但父元素設定flex-wrap:nowrap,變成一行時會無效

屬性

  • flex-start:對齊最上面的 cross start
  • flex-end:對齊最下面的 cross end
  • center:垂直置中
  • stretch:元素高度會填滿容器高度
  • space-between:第一行與最後一行分別對齊最上方與最下方
  • space-around:平均分配間距
    https://ithelp.ithome.com.tw/upload/images/20211008/20112053EAyTcJsL90.png

Flex-item

order

可依照自己的規劃,由小到大排出區塊的順序

<div class="box">
      <div class="item item1">1</div>
      <div class="item item2">2</div>
      <div class="item item3">3</div>
      <div class="item item4">4</div>
    </div>
.box{
  display: flex;
  flex-wrap: wrap;
  width: 350px;
  padding: 15px 10px;
  background-color: #dee2e8;
  align-items: flex-start;
}
.item{
  width: 30px;
  padding: 15px;
  text-align: center;
  background-color: #bdc2ca;
  margin: 5px;
}
.item1{
  order:3;
}
.item2{
  order:1;
}
.item3{
  order:4;
}
.item4{
  order:2;
}

https://ithelp.ithome.com.tw/upload/images/20211008/20112053q340lZ3c3H.png

align-self

與align-items相同,用於覆寫已經套用 align-items 的屬性

範例:將2區塊個別設定align-self:flex-end
https://ithelp.ithome.com.tw/upload/images/20211008/20112053w6t27usFOJ.png

flex-grow

依照比例分配剩餘空間。

當區塊物件小於容器寬度時會留白,為了不要留白個別讓區塊放大預設為0,不會有彈性變化,不可為負值。

flex-grow:數值
<div class="box">
  <div class="item" style="background-color:red;"></div>
  <div class="item" style="background-color:green;"></div>
  <div class="item" style="background-color:blue;"></div>
</div>

寬度為350px,item寬度為100px,就會有多餘的空間50px

.box .item{
  width: 100px;
}

https://ithelp.ithome.com.tw/upload/images/20211008/20112053Kw8V0BDJbA.png
將紅色區塊改為flex-grow: 1,就會將剩餘空間的50px給紅色區塊
https://ithelp.ithome.com.tw/upload/images/20211008/20112053EO6L2aEMqH.png

.box div:nth-of-type(1) {flex-grow: 1;}
.box div:nth-of-type(2) {flex-grow: 3;}
.box div:nth-of-type(3) {flex-grow: 2;}

https://ithelp.ithome.com.tw/upload/images/20211008/20112053zPtGuZ3sNI.png

flex-shrink

當區塊物件大於容器寬度會超出範圍,會個別區塊做縮小預設值為1,不可為負數,數值0不會有彈性變化。

flex-shrink:數值
<div class="box">
  <div class="item siderbar" style="background-color:red;"></div>
  <div class="item content" style="background-color:green;"></div>
</div>

.box寬度為100%,當容器寬度不夠寬時,會縮小.content區塊的寬度,.siderbar寬度都會是100px,直到寬度不足時,才會按比例縮放

.siderbar{
  flex-basis: 100px;
}
.content{
  flex-grow: 1;
  flex-shrink: 0;
  flex-basis: 500px;
}

https://ithelp.ithome.com.tw/upload/images/20211008/20112053Jtl3AU54e3.png

flex-basis

設定區塊的大小,預設為auto,依據內容設置寬度,與width類似,但優先程度較高

flex-basis:數值/auto
<div class="box">
  <div style="background-color:red;"></div>
  <div style="background-color:green;"></div>
  <div style="background-color:blue;"></div>
</div>
.box {
  width: 350px;
  height: 100px;
  display: flex;
}
.box div{
  flex-grow: 0;
  flex-shrink: 0;
  flex-basis: 50px;
}
.box div:nth-of-type(2) {
	flex-basis: 100px;
}

https://ithelp.ithome.com.tw/upload/images/20211008/20112053axrJKaHTas.png

flex統一設定屬性

flex: none flex-grow flex-shrink flex-basis

參考資料:
https://www.oxxostudio.tw/articles/201501/css-flexbox.html
https://blog.camel2243.com/2019/11/14/css-搞懂-flex-grow-flex-shirk-及-flex-basis-三種屬性/

]]> sunny 2021-10-08 09:00:27
網頁定位-30天學會HTML+CSS,製作精美網站 https://ithelp.ithome.com.tw/articles/10278663?sc=rss.iron https://ithelp.ithome.com.tw/articles/10278663?sc=rss.iron 今天要來介紹的是定位(position),可以用來設定元素的擺放位置了

position 定位

static 預設值

正常排序,依照html的...]]> 今天要來介紹的是定位(position),可以用來設定元素的擺放位置了

position 定位

static 預設值

正常排序,依照html的code由上往下排列,對於top、right、bottom、left屬性及z-index屬性無效。

<div class="box">
    <div class="item orange"></div>
    <div class="item green"></div>
    <div class="item blue"></div>
</div>
.item{
  width: 120px;
  height: 100px;
}
.orange{
  background-color:#ff9800;
}
.green{
  background-color: #8bc34a;
}
.blue{
  background-color:#2196f3;
}

https://ithelp.ithome.com.tw/upload/images/20211007/20112053erofgLT9ne.png

relative 相對配置

相對於自己原本位置做偏移,但原來的位置會被留下來
用top、right、bottom、left設定位移量
範例:

.green{
  background-color: #8bc34a;
  position: relative;
  left: 30px;
}

https://ithelp.ithome.com.tw/upload/images/20211007/20112053T5ZtkEyZyM.png
我自己是會用在像是項目清單的icon做位置微調

<ul class="list">
    <li>
      <img src="img/icon.png" alt="">
      item1
    </li>
    <li>
      <img src="img/icon.png" alt="">
      item2
    </li>
    <li>
      <img src="img/icon.png" alt="">
      item3
    </li>
    <li>
      <img src="img/icon.png" alt="">
      item4
    </li>
  </ul>
.list{
  list-style: none;
  font-size: 20px;
  color: #666;
}
.list li{
  margin-bottom: 10px;
}
.list img{
  height: 25px;
}

https://ithelp.ithome.com.tw/upload/images/20211007/20112053cAt7CqSj7N.png
設定完後,想要圖片能夠垂直置中對齊文字,將img設定position: relative; top: 4px;,圖片就垂直置中文字了

.list img{
  height: 25px;
  position: relative;
  top: 4px;
}

https://ithelp.ithome.com.tw/upload/images/20211007/201120537xHrSl8oMl.png

absolute 絕對配置

定位方式是相對於瀏覽器左上角,視窗滾動時,區塊也會跟著滾動
用top、right、bottom、left設定位移量
範例:設定absolute後,原本的區塊位置會被下面的取代

.green{
  background-color: #8bc34a;
  position: absolute;
  left: 30px;
}

https://ithelp.ithome.com.tw/upload/images/20211007/201120536fmBtRcXjd.png
當我要製作item定位時,就會與relative一起使用,讓我們來看下面的範例
我要顯示這樣子的版面,讓文字浮在圖片上面,所以我將文字設定absolute
https://ithelp.ithome.com.tw/upload/images/20211007/20112053fmmDCTYUn1.png

<div class="list">
    <div class="item">
      <div class="img">
        <img src="img.jpg" alt="">
      </div>
      <div class="txt">
        item1
      </div>
    </div>
    <div class="item">
      <div class="img">
        <img src="img.jpg" alt="">
      </div>
      <div class="txt">
        item2
      </div>
    </div>
</div>
.item{
  width: 200px;
  margin-bottom: 10px;
  position: relative;
}
.list .img{
  height: 138px;
}
.list img{
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.list .txt{
  position:absolute;
  width: 100%;
  background-color: rgba(0,0,0,.5);
  bottom: 0;
  padding: 5px 10px;
  color: #fff;
  box-sizing: border-box;
}

但是卻變成這樣子,所有.item的.txt區塊都堆疊在下方
https://ithelp.ithome.com.tw/upload/images/20211007/20112053U5bubxuB8Z.png
所以在.item(父元素)加上position: relative;所有txt定位就會以父元素的bottom來定位,否則會以body的bottom

.item{
  width: 200px;
  margin-bottom: 10px;
  position: relative;
}

fixed 固定配置

定位方式是相對於瀏覽器左上角,視窗滾動時,區塊不會跟著滾動
用top、right、bottom、left設定位移量
範例:設定fixed,top:30px, left:30px,無論捲軸如何滾動區塊都會維持在設定的位置

.green{
  background-color: #8bc34a;
  position: fixed;
  top: 30px;
  left: 30px;
}

https://ithelp.ithome.com.tw/upload/images/20211007/20112053K8VUjYsdvB.png
通常會用在scrollTop或是側邊固定的預約/客服資訊
這這網站的預約資訊就固定在右邊,是方便使用者看完資訊後可以立即預約
https://ithelp.ithome.com.tw/upload/images/20211007/20112053pWCbFv0oRT.png
圖片來源
scrollTop按鈕當你滾動頁面,想要返回到最上層,點固定在右下角的按鈕就可以了
https://ithelp.ithome.com.tw/upload/images/20211007/20112053kSbDSTe5jD.png
圖片來源

sticky

sticky可以說是relative與fixed的結合,用在scroll事件的監聽上。
範例:在滑動時,綠色區塊距離父元素的距離達到sticky定位(top:0)時,就會固定到適當位置,固定後不管捲軸如何向下滾動,都會定位在top:0位置

<div class="box">
  <div class="item red"></div>
  <div class="item green"></div>
  <div class="item blue"></div>
  <div class="item red"></div>
  <div class="item blue"></div>
</div>
.green{
  background-color: #8bc34a;
  position: sticky;
  top: 0;
}

綠色區塊一開始的位置
https://ithelp.ithome.com.tw/upload/images/20211007/20112053X91CJ7QB7h.png
捲軸向下滑動,綠色區塊一樣固定在top:0的位置
https://ithelp.ithome.com.tw/upload/images/20211007/20112053zxRYBDPgdI.png
使用sticky需要注意的地方:

  • 需指定top、right、bottom、left其中一個值,sticky才會生效
  • 父元素不能是overflow:hidden或者overflow:auto屬性
  • 父元素的高度不能低於sticky元素的高度

通常會用在header區塊,當捲軸滾動時header固定在上方
像下圖這網站,他在滾動時他會固定在上方是使用sticky
https://ithelp.ithome.com.tw/upload/images/20211007/20112053KZiBufE6Dw.png
圖片來源
但也有人會使用fixed
https://ithelp.ithome.com.tw/upload/images/20211007/201120535uAJQAtv6e.png
圖片來源

z-index 堆疊順序

設定position屬性後,就可以設置z-index,數字越大,堆疊的順序越上層

<div class="box">
    <div class="item red"></div>
    <div class="item green"></div>
    <div class="item blue"></div>
  </div>
.item{
  width: 100px;
  height: 100px;
  padding: 15px;
  box-sizing: border-box;
  position: absolute;
  z-index: 4;
}
.red{
  background-color:#ff9800;
  z-index: 10;
}
.green{
  background-color: #8bc34a;
  width: 80px;
  height: 80px;
  z-index: 30;
}
.blue{
  background-color:#2196f3;
  width: 120px;
  height: 120px;
}

https://ithelp.ithome.com.tw/upload/images/20211007/201120535ZtC2YYN9b.png

結論

製作網頁要符合使用者習慣,加上手機瀏覽網站的人非常多,為了方便使用者操作,header通常都會隨著捲軸滾動固定在上方,側邊會有scrollTop固定在側邊,讓使用者可以快速回到網頁最頂端。
以上是定位的介紹,相信你對定位有基礎的了解了,在區塊設置css就能更上手了

]]> sunny 2021-10-07 08:21:02
網頁盒子-30天學會HTML+CSS,製作精美網站 https://ithelp.ithome.com.tw/articles/10278243?sc=rss.iron https://ithelp.ithome.com.tw/articles/10278243?sc=rss.iron Box Model定義

每個html的元素都是一個Box Model,由外而內為外邊距(Margin)、邊框(Border)、內邊距(Padding)、內容盒子(Content...]]> Box Model定義

每個html的元素都是一個Box Model,由外而內為外邊距(Margin)、邊框(Border)、內邊距(Padding)、內容盒子(Content Box)所組成。
https://ithelp.ithome.com.tw/upload/images/20211006/20112053d0RRbxkTlD.jpg

Margin 外邊距

與外層元素的間距。

寫法

margin四個邊寫在一起的寫法:

  • margin:上 右 下 左(順時針設定);
  • margin:上下 左右;
  • margin:上 左右 下;
  • margin: 四個邊同樣値;

各別寫

  • margin-top
  • margin-right
  • margin-bottom
  • margin-left

單位

可使用auto、%(百分比)、長度單位(px、em、rem...)

外邊距合併

外邊距合併指的是指當兩個元素垂直外邊距相遇時就會合併成一個外邊距,數字相同合併外,如果兩個數字不同會取最大的,讓我們來看以下常見的範例

上下兩元素外邊距合併

橘色區塊margin-bottom:30px; 綠色區塊margin-top:20px;

<div class="box">
    <div class="item orange">
      Lorem ipsum dolor sit amet, harum malorum ex mei
    </div>
    <div class="item green">
      Quo ea doming scripserit ullamcorper, audire percipit ex sit
    </div>

</div>
.orange{
  background-color:#ff9800;
  margin-bottom: 30px;
}
.green{
  background-color: #8bc34a;
  margin-top: 20px;
}

可能你會以為這樣的設定是margin-bottom:20px + margin-top:10px = 30px的距離
https://ithelp.ithome.com.tw/upload/images/20211006/20112053ZNXuE85CEo.jpg
但實際上是取得margin最大值或是相等的值
https://ithelp.ithome.com.tw/upload/images/20211006/20112053HNcrLwbgAk.jpg

外層元素裡面包另一個元素

元素合併是因為外層框沒有設置框線或是內距才會發生合併

.box{
  background-color:#efefef;
  margin:50px;
}
.item{
  background-color:#ff9800;
  margin:10px 0;
}

https://ithelp.ithome.com.tw/upload/images/20211006/20112053rEaRLWGelI.jpg
當你外層.box有設定邊框時,margin:10px 0;就會有效

.box{
  background-color:#efefef;
  margin:50px;
  border: 1px solid #666;
}

https://ithelp.ithome.com.tw/upload/images/20211006/20112053p7oL2loDmu.jpg

行內框(inline)、浮動框、絕對位置不會合併

內邊距(Padding)

邊界內元素與內容距離,寫法與margin相同,可各別設定四個邊「padding-top」、「padding-right」、「padding-bottom」、「padding-left」,也可以一次套用四個邊,順序為上、右、下、左(順時針)設定。

範例:設定box寬度為300px,內距20px

<div class="box">
  Lorem ipsum dolor sit amet, harum malorum ex mei. Quo ea doming scripserit ullamcorper, audire percipit ex sit
 </div>
.box{
  width: 300px;
  background-color: #efefef;
  padding: 20px;
}

但實際寬度會是340px(300px + 左内邊距 20px + 右内邊距 20px)
https://ithelp.ithome.com.tw/upload/images/20211006/20112053w9rLVK3Bzb.png
這樣就超過我一開始想要的寬度300px了,所以我就要把寬度扣掉padding的左右內距才會符合300px

.box{
  width: 260px; // 300 - 20(左內距) - 20(右內距)
  background-color: #efefef;
  padding: 20px;
}

但是每次只要有設定內距,就要把原本的寬度扣掉,這樣子太麻煩了。所以可以使用box-sizing屬性,設定border-box,就不會受padding影響,還是能保留他原本的寬度。但你會發現使用內邊距的話,內容空間會減少。

.box{
  width: 300px;
  background-color: #efefef;
  padding: 20px;
  box-sizing:border-box;
}

https://ithelp.ithome.com.tw/upload/images/20211006/20112053q9Mitc2nnU.png

box-sizing

  • content-box:預設值,實際寬高=所設定的數值+border+padding
  • border-box:實際寬高=所設定的數值(已包含border和padding)

邊框(Border)

border-width 邊框粗細

寫法

border-width四個邊寫在一起的寫法:

  • border-width:上 右 下 左(順時針設定);
  • border-width:上下 左右;
  • border-width: 四個邊同樣値;

各別寫

  • border-top-width
  • border-right-width
  • border-bottom-width
  • border-left-width

單位

可使用auto、%(百分比)、長度單位(px、em、rem...)、關鍵字(thin(細框線), medium(預設), thick(粗框線))

範例

設定四個邊的寬度都一樣

.box{
	border: 2px solid blue;
}

https://ithelp.ithome.com.tw/upload/images/20211006/20112053Obg3QujtkF.png
設定四個邊寬度

.box{
  border: 2px solid blue;
  border-width:3px 6px 10px 5px;
  width: 300px;
}

https://ithelp.ithome.com.tw/upload/images/20211006/20112053zc4J3l0TWH.png

border-style 邊框樣式

寫法

border-style四個邊寫在一起的寫法:

  • border-style:上 右 下 左(順時針設定);
  • border-style:上下 左右;
  • border-style: 四個邊同樣値;

各別寫

  • border-top-style
  • border-right-style
  • border-bottom-style
  • border-left-style

樣式

  • none:不顯示線條(預設)
  • solid:單實線
  • double:雙實線
  • dashed:虛線
  • dotted:點線
  • groove:立體凹線
  • ridge:立體凸線
  • inset:嵌入線(以內陰影模擬凹陷效果)
  • outset:浮出線(以外陰影模擬浮凸效果)
    https://ithelp.ithome.com.tw/upload/images/20211006/20112053rkZ88GAv5I.png

border-color 邊框顏色

寫法

border-color四個邊寫在一起的寫法:

  • border-color:上 右 下 左(順時針設定);
  • border-color:上下 左右;
  • border-color: 四個邊同樣値;

各別寫

  • border-top-color
  • border-right-color
  • border-bottom-color
  • border-left-color

範例

設定四個邊的顏色

.box{
	border: 2px solid blue;
  border-color: red green blue orange;
}

border-color單獨使用是不起作用的,必須使用border-style來設置邊框樣式

border 統一設定邊框屬性

順序為border-width border-style border-color

.border-solid{
  border: 4px solid #999;
}

border除了做圖片、區塊...的邊寬外,還能製作三角形,以下範例是製作正三角形

.triangle{
  height:0px; 
  width:0px;
  border-bottom: 50px solid blue;
  border-left: 50px solid transparent;
  border-right: 50px solid transparent;
}

https://ithelp.ithome.com.tw/upload/images/20211006/20112053EDQh1pi9EX.png
如果覺得自己寫三角形計算寬度很麻煩,還有三角形產生器 ,只要設定好方向、大小、顏色,就能夠讓輕鬆的產出三角形
https://ithelp.ithome.com.tw/upload/images/20211006/20112053XmFFWLMJJi.png

box-shadow 盒子陰影

屬性

  • h-shadow:水平陰影,正數向右延伸,負數向左
  • v-shadow:垂直陰影,正數向下延伸,負數向上
  • blur:模糊長度,數字越大越模糊
  • color:陰影顏色
  • inset:內陰影
box-shadow:h-shadow v-shadow blur color inset

範例

為區塊加上陰影

.box{
  padding: 15px;
  border: 1px solid #ccc;
  width: 300px;
  box-shadow: 0 0 8px #ccc;
}

https://ithelp.ithome.com.tw/upload/images/20211006/20112053gjvXkaMqEe.png

為圖片加上陰影

.box img{
  padding: 5px;
  border: 1px solid #ccc;
  width: 300px;
  box-shadow: 3px 3px 1px #ccc;
}

https://ithelp.ithome.com.tw/upload/images/20211006/20112053zy1qL80Gjg.png

設定內陰影

.box{
  padding: 15px;
  width: 300px;
  box-shadow: inset 0 0 15px #ccc;
}

https://ithelp.ithome.com.tw/upload/images/20211006/20112053TBi4Idmqef.png

外邊框outline

outline是緊鄰border外的邊線
https://ithelp.ithome.com.tw/upload/images/20211006/20112053ITfX2oipWz.jpg
緊鄰border外的邊線,屬性與border相同

  • outline-color同border-color
  • outline-width同border-width
  • outline-style同border-style
  • outline-offset:定義與border邊框的距離

範例

.box{
  padding: 15px;
  width: 300px;
  border: 3px solid #666;
  outline: 3px solid #ccc
}

https://ithelp.ithome.com.tw/upload/images/20211006/201120532spCYMDkQr.png

結論

我自己在設定CSS時,會在全域設定為box-sizing:border-box,這樣子就不用擔心寬度或高度會因為我設定了padding、框線...而受影響,或是還要再扣掉寬度才會符合我設定的尺寸。

相信你對Box Model有一定的了解了,對於區塊、圖片...,都可以得心應手的美化了。

]]> sunny 2021-10-06 09:57:18
網頁表單-30天學會HTML+CSS,製作精美網站 https://ithelp.ithome.com.tw/articles/10277732?sc=rss.iron https://ithelp.ithome.com.tw/articles/10277732?sc=rss.iron 表單在網頁上有不同呈現的功能,像是網路投票、註冊、購物、問券、搜尋等,用來收集瀏覽者的資訊,增加與使用者的互動。

<form>

<...]]>
表單在網頁上有不同呈現的功能,像是網路投票、註冊、購物、問券、搜尋等,用來收集瀏覽者的資訊,增加與使用者的互動。

<form>

包含表單元素的區域(input、textarea、select...),用來讓使用者輸入資料

<form action="送出目的地" method="資料傳送方式">
	<!-表單元素->
</form>

表單資料傳遞方式:
填好表單按送出按鈕後,透過get或post方傳送到伺服器(Web Server)

post

放在 HTTP 傳輸封包 body 中送出,安全性較高,因為已封包方式傳送,所以傳送資料大小沒有檔案限制。像是寫完信件,會將信件放到信封裡面,不會有人知道裡面寫什麼內容,安全性較高。

get

會將表單內的資料放在action請求的URL上面送出,安全性較差,且只有255個字元限制,適合用在搜尋等資料量少的表單。get傳送方式就像是明信片,容易被其他人看到內容,安全性較低。

表單元件

製作表單,會有輸入框、下拉選單、按鈕等元件組成。下面就會一一介紹每個元件功能

<input>

是讓使用者輸入的資料的元件,常用在搜尋(text)、密碼(password)、信箱(email)等。
通用屬性:

  • name:欄位名稱
  • value:指定初始值
  • placeholder:提醒使用者輸入內容的提示訊息

文字輸入(預設值)

姓名:<input type="text" name="username" placeholder="輸入您的名字">

https://ithelp.ithome.com.tw/upload/images/20211005/20112053NS1KrjRwMK.png

密碼

不會被明碼顯示在螢幕畫面中

<input type="password">

https://ithelp.ithome.com.tw/upload/images/20211005/20112053GIowECkEQD.png

多選核取方塊

name需要都是一樣,一個群組內,可以複選,預設選取可以使用checked

你喜歡的顏色<br>
<input type="checkbox" name="color" id="all" checked>全部
<input type="checkbox" name="color" id="blue">藍
<input type="checkbox" name="color" id="red">紅
<input type="checkbox" name="color" id="yellow">黃

https://ithelp.ithome.com.tw/upload/images/20211005/20112053IbuH52rD7T.png

單選按鈕

name需要都是一樣,一個群組內,只能單選,預設選取可以使用checked

性別<br>
<input type="radio" name="gender" id="noopen" checked>不公開
<input type="radio" name="gender" id="man">男
<input type="radio" name="gender" id="woman">女

https://ithelp.ithome.com.tw/upload/images/20211005/20112053CxmRXzPcwn.png

數字

只能輸入數字,選取input輸入框右邊可以點選上下箭頭符號,增減數字

<input type="number">

https://ithelp.ithome.com.tw/upload/images/20211005/20112053dwaCBANdRP.png

日期格式

  • type="date":輸入日期,格式為YYYY-MM-DD
  • type="dateTime":
  • type="time":輸入時間,格式為hh:mm:ss
  • type="week":第幾週,格式為YYYY-Www
  • type="month":輸入年份及月份,格式為YYYY-MM
  • type="datetime-local":本地與世界標準時間,格式為YYYY-MM-DDThh:mm:ss
 <input type="date">

https://ithelp.ithome.com.tw/upload/images/20211005/20112053pfq4rP2QlY.png

檔案上傳

<input type="file">

https://ithelp.ithome.com.tw/upload/images/20211005/20112053YkSLQSNNLe.png

<select>

用來建立下拉式選單 (dropdown menu),讓使用者可以從一堆選項中選擇出一個或多個選項

  • name:欄位名稱
  • value: 指定如果選了該選項,表單要傳送什麼值給遠端伺服器,如果沒設定 value,預設是送 的內容
  • selected: 預設選取的<option>
  • disabled: 不可選取<option>
<select>
    <option>請選擇你喜歡的顏色</option>
    <option value="red">red</option>
    <option selected>yellow</option>
    <option>green</option>
		<option disabled>blue</option>
</select>

https://ithelp.ithome.com.tw/upload/images/20211005/20112053OezDwmsWS5.png

<textarea>

多行文字輸入欄位

  • name:欄位名稱
  • rows:設定輸入框的高度是幾行文字 (lines),預設是 2
  • cols:設定輸入框的寬度是多少文字 (characters),預設是 20
<textarea name="mytext" rows="4" cols="30">內容內容內容內容內容</textarea>

https://ithelp.ithome.com.tw/upload/images/20211005/20112053FFi3tTu6wY.png

<label>

label可以將欄位名稱及表單元件做關聯。用for屬性值設定與表單元件id做關聯。或是直接把表單元件包在label裡面。

<div>
	方法一:
	<label for="emailAddress">Email address: </label>
	<input type="email" name="emailAddress" id="emailAddress">
</div>
<div>
	方法二:
	<label>
		Email address: 
		<input type="email" name="emailAddress">
	</label>
</div>

<button>

  • submit:送出,預設值
  • reset:重設
  • button:一般按鈕,需搭配javascript使用
<button type="button">我是按鈕</button>

https://ithelp.ithome.com.tw/upload/images/20211005/20112053o7hkkKBYOZ.png

改造表單元件樣式

表單元件像是輸入框、下拉選單...的樣式預設都醜醜的,透過css可以隨心所欲的將元件變得美美的,以下是我比較常用的表單樣式

設定文字顏色、邊框、間距、圓角

<select class="form-control">
		<option>choose area</option>
		<option>Taichung</option>
		<option>Taipei</option>
	</select>
	<input type="text" class="form-control" placeholder="input address">
.form-control{
	color:#333;
	border:1px solid #ccc;
	padding:10px 15px;
	margin-bottom:10px;
	border-radius:5px;
}

https://ithelp.ithome.com.tw/upload/images/20211005/201120532lkG3Ub4cu.png

設定placeholder屬性樣式

.form-control::placeholder {
  color: #ccc;
}

https://ithelp.ithome.com.tw/upload/images/20211005/20112053wxRoJP0bKk.png

移除input[number]的上下箭頭

/*chrome瀏覽器移除*/
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
  -webkit-appearance: none;
}
/*firefox瀏覽器移除*/
input[type="number"]{
  -moz-appearance: textfield;
}

https://ithelp.ithome.com.tw/upload/images/20211005/20112053lmYnTzPGNx.png

美化radio、checkbox預設樣式

<p>您的性别:</p>
<div class="select-item radio-item">
  <input type="radio" id="noopen" name="sex" checked>
  <label for="noopen"></label>不公開
</div>
<div class="select-item radio-item">
  <input type="radio" id="man" name="sex">
  <label for="man"></label>男
</div>
<div class="select-item radio-item">
  <input type="radio" id="woman" name="sex">
  <label for="woman"></label>女
</div>

<p>您的興趣:</p>
<div class="select-item checkbox-item">
  <input type="checkbox" id="noopen" name="sex" checked>
  <label for="noopen"></label>打羽球
</div>
<div class="select-item checkbox-item">
  <input type="checkbox" id="man" name="sex">
  <label for="man"></label>逛街
</div>
<div class="select-item checkbox-item">
  <input type="checkbox" id="woman" name="sex">
  <label for="woman"></label>跑步
</div>
.select-item {
  position: relative;
  display: inline-block;
  margin-right: 5px;
}
.select-item input {
  vertical-align: middle;
  width: 14px;
  height: 14px;
  appearance: none;
  -webkit-appearance: none;
  opacity: 0;
  outline: none;
  margin: 0 5px 0 0 ;
}
.select-item label {
  position: absolute;
  left: 3px;
  top: 3px;
  z-index: -1;
  width: 14px;
  height: 14px;
  border: 1px solid #409eff;
  border-radius: 50%;
}
.select-item input:checked + label {
  background-color: #409eff;
}
/*radio style*/
.radio-item input[type="radio"]:checked + label::after {
  content: "";
  position: absolute;
  left: calc(50% - 4px);
  top: calc(50% - 4px);
  width: 8px;
  height: 8px;
  background-color: #fff;
  border-radius: 50%;
}
/*checkbox style*/
.checkbox-item label{
  border-radius: 2px;
}
.checkbox-item input[type="checkbox"]:checked + label::after {
  content: "";
  position: absolute;
  left: 5px;
  top: 0px;
  width: 4px;
  height: 10px;
  border-right: 1px solid #fff;
  border-bottom: 1px solid #fff;
  transform: rotate(45deg);
}

https://ithelp.ithome.com.tw/upload/images/20211005/20112053ff1moGGPay.png

上傳圖片改為按鈕樣式

<div class="upload-box">
  <label for="file-upload" class="customer-upload">
    上傳圖片
  </label>
  <input id="file-upload" type="file"/>
</div>
.upload-box input[type="file"] {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  border: 0;
}
.upload-box .customer-upload {
  background-color:#ff9800;
  display: inline-block;
  padding: 5px 15px;
  cursor: pointer;
  color:#fff;
  border-radius:5px;
}

https://ithelp.ithome.com.tw/upload/images/20211005/20112053tPr1eFdpYv.png

自訂select箭頭樣式

<select class="form-control">
  <option>2021/09</option>
  <option>2021/10</option>
</select>
select {
  width: 130px;
  padding:5px 25px 5px 8px;
  background-color: #fff;
  background-clip: padding-box;
  border-radius: 0.25rem;
  border-radius: 8px;
  border: 1px solid #ff786e;
	line-height: 1;
	/*將預設的select選擇框樣式清除*/
  appearance: none;
  -moz-appearance: none;
  -webkit-appearance: none;
	/*箭頭樣式及箭頭位置*/
  background: url(img/arr.png) no-repeat scroll 96% center #fff;
  background-size: 13px 8px;
  outline: 0;
}

https://ithelp.ithome.com.tw/upload/images/20211005/20112053xwxDC8Wsse.png
參考資料:
https://medium.com/ui-ux練功坊/form表單中的get與post有什麼差別-d2a04845769a
https://medium.com/@small2883/表單結構-表單中的get-與-post區別-685b0bfe15ea
https://developer.mozilla.org/en-US/docs/Web/CSS/::placeholder
https://www.itread01.com/p/632603.html

]]>
sunny 2021-10-05 09:09:45
網頁表格-30天學會HTML+CSS,製作精美網站 https://ithelp.ithome.com.tw/articles/10277260?sc=rss.iron https://ithelp.ithome.com.tw/articles/10277260?sc=rss.iron 網頁需要製作時間表、收費表等,都可以使用表格製作。
只要了解表格相關的標籤,就能夠輕鬆做出表格了,這章節會讓你了解到製作表格的多種標籤及樣式設定,還有響應式網站在手機螢幕上的呈現及不...]]>
網頁需要製作時間表、收費表等,都可以使用表格製作。
只要了解表格相關的標籤,就能夠輕鬆做出表格了,這章節會讓你了解到製作表格的多種標籤及樣式設定,還有響應式網站在手機螢幕上的呈現及不使用table標籤製作表格。

表格標籤

<table>

所有的標格規劃<th><td>都會寫在這裡面

<thead> 表頭、 <tbody> 內容,、<tfoot>表尾

可寫可不寫,主要用來增強表格 HTML 的語意性,用來明確區分表格中的不同目的區塊

<thead>表頭內使用<th>,預設以粗體置中顯示;<tbody>本體內使用<td><tfoot>表尾,整份表格的註記

<tr>

「table row」縮寫,表格行,包含一至多個<th><td>

<th>

「table heaader」縮寫,表格標題

<td>

「table data」縮寫,儲存格

<caption>

表格的標題
https://ithelp.ithome.com.tw/upload/images/20211004/201120536YB6UPzuLf.png
上圖的範例結構寫法如下:

<table>
    <thead>
      <tr>
        <th>th</th>
        <th>th</th>
        <th>th</th>
        <th>th</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>td</td>
        <td>td</td>
        <td>td</td>
        <td>td</td>
      </tr>
      <tr>
        <td>td</td>
        <td>td</td>
        <td>td</td>
        <td>td</td>
      </tr>
      <tr>
        <td>td</td>
        <td>td</td>
        <td>td</td>
        <td>td</td>
      </tr>
    </tbody>
    <tfoot>
      <tr>
        <td>td</td>
        <td>td</td>
        <td>td</td>
        <td>td</td>
      </tr>
    </tfoot>
  </table>

合併儲存格

colspan(水平合併)

<tr><td colspan="n">內容</td></tr>

n為合併表格個數

rowspan(垂直合併)

<tr><th rowspan="n">內容</th></tr>

n為合併表格個數

<table>
  <thead>
    <tr>
      <th colspan="2">水平合併儲存格</th>
      <th>th</th>
      <th>th</th>
      <th>th</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td rowspan="2" colspan="2">水平垂直合併儲存格</td>
      <td>td</td>
      <td>td</td>
      <td rowspan="2">垂直合併儲存格</td>
    </tr>
    <tr>
      <td>td</td>
      <td>td</td>
    </tr>
  </tbody>
</table>

https://ithelp.ithome.com.tw/upload/images/20211004/20112053LZBKFhs7RN.png

表格樣式

caption-side顯示表格標題位置

caption-side:top/bottom
  • top(表格上方,預設值)
  • bottom(表格下方)
<table class="caption-top">
    <caption>表格標題預設為上方</caption>
    <thead>
      <tr>
        <th>姓名</th>
        <th>電話</th>
        <th>地址</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>王小明</td>
        <td>0988123456</td>
        <td>台中市</td>
      </tr>
      <tr>
        <td>許小美</td>
        <td>0912567890</td>
        <td>台北市</td>
      </tr>
    </tbody>
  </table>
  <table class="caption-bottom">
    <caption>表格標題設定在下方</caption>
    <thead>
      <tr>
        <th>姓名</th>
        <th>電話</th>
        <th>地址</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>王小明</td>
        <td>0988123456</td>
        <td>台中市</td>
      </tr>
      <tr>
        <td>許小美</td>
        <td>0912567890</td>
        <td>台北市</td>
      </tr>
    </tbody>
  </table>
.collapse{
  border-collapse: collapse;
}
table th, table td{
  border: 1px solid #ccc;
  padding: 5px 20px;
  
}
.caption-bottom{
  caption-side: bottom;
  margin-left: 20px;
}

https://ithelp.ithome.com.tw/upload/images/20211004/20112053TxKJYNlxJ0.png

border-collapse 属性

設置表格的邊框是否被合併為一個單一的邊框

  • separate:預設值。 邊框會被分開。
  • collapse:邊框會合併為一個單一的邊框
<table class="separate">
  <caption>separate</caption>
  <thead>
    <tr>
      <th>姓名</th>
      <th>電話</th>
      <th>地址</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>王小明</td>
      <td>0988123456</td>
      <td>台中市</td>
    </tr>
    <tr>
      <td>許小美</td>
      <td>0912567890</td>
      <td>台北市</td>
    </tr>
  </tbody>
</table>
<table class="collapse">
  <caption>collapse</caption>
  <thead>
    <tr>
      <th>姓名</th>
      <th>電話</th>
      <th>地址</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>王小明</td>
      <td>0988123456</td>
      <td>台中市</td>
    </tr>
    <tr>
      <td>許小美</td>
      <td>0912567890</td>
      <td>台北市</td>
    </tr>
  </tbody>
</table>
table th, table td{
  border: 1px solid #ccc;
  padding: 5px 20px;
  
}
.collapse{
  border-collapse: collapse;
}

https://ithelp.ithome.com.tw/upload/images/20211004/20112053DAAXdF6V6n.png

border 表格邊框

將表格框線給予樣式

表格文字對齊

  • text-align:left, center, right(水平對齊)
  • vertical-align:baseline, top, middle, bottom....(垂直對齊)

表格間距

表格與內容間距使用padding

表格顏色

  • 文字顏色:color
  • 背景色:background

綜合以上介紹的邊框、文字、滑入、對齊、間距、顏色,做一個範例

<table class="table-box">
  <thead>
    <tr>
      <th>姓名</th>
      <th>電話</th>
      <th>地址</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>王小明</td>
      <td>0988123456</td>
      <td>台中市</td>
    </tr>
    <tr>
      <td>許小美</td>
      <td>0912567890</td>
      <td>台北市</td>
    </tr>
    <tr>
      <td>王小明</td>
      <td>0988123456</td>
      <td>台中市</td>
    </tr>
    <tr>
      <td>許小美</td>
      <td>0912567890</td>
      <td>台北市信義區</td>
    </tr>
  </tbody>
</table>
.table-box{
  border-collapse: collapse;
}
.table-box th,
.table-box td{
  padding: 5px 20px;
  border:1px solid #ccc;
  text-align: center;
  width: 60px;
}
.table-box th{
  border-bottom: 0;
  background-color: #332f2d;
  color: #fff;
}
.table-box td{
  min-height: 30px;
  vertical-align: middle;
}
.table-box thead tr{
  border-bottom:3px solid #ffc107;
}
.table-box tbody tr:nth-child(2n+2){
  background-color: #efefef;
}
.table-box tbody tr:hover,
.table-box tbody tr:nth-child(2n+2):hover{
  background-color: #e1eaef;
}

https://ithelp.ithome.com.tw/upload/images/20211004/20112053Y3XocUM82p.png
滑入樣式為灰藍色
https://ithelp.ithome.com.tw/upload/images/20211004/20112053UrOHHP1TjE.png

表格應用

製作響應式表格

當顯示大量資料表格欄位多的時候,在手機上看到的表格會出現水平卷軸,但有時真的很難操作,因此在手機版的時候會用一筆資料一個區塊呈現,排版乾淨又容易閱讀。

首先在標籤加上data-th屬性,裡面的值就是的文字,在縮小畫面時,會將隱藏,設定display:block,這樣就會變一個區塊。

<table class="table rwd-table">
    <thead>
      <tr>
        <th scope="col">#</th>
        <th scope="col">First</th>
        <th scope="col">Last</th>
        <th scope="col">Handle</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <th data-th="#">1</th>
        <td data-th="first">Mark</td>
        <td data-th="Last">Otto</td>
        <td data-th="Handle">@mdo</td>
      </tr>
      <tr>
        <th data-th="#">2</th>
        <td data-th="first">Jacob</td>
        <td data-th="Last">Thornton</td>
        <td data-th="Handle">@fat</td>
      </tr>
      <tr>
        <th data-th="#">3</th>
        <td data-th="first">Larry the Bird</td>
        <td data-th="Last">Otto</td>
        <td data-th="Handle">@twitter</td>
      </tr>
    </tbody>
  </table>
.rwd-table {
  border: 1px solid #ccc;
  border-collapse: collapse;
  max-width: 450px;
}
.rwd-table th,
.rwd-table td {
  border: 1px solid #ccc;
  padding: 5px 10px;
  min-width: 30px;
}

@media screen and (max-width: 480px) {
  .rwd-table {
    width: 100%;
  }
  .rwd-table tr {
    border: 1px solid #ccc;
  }
  .rwd-table tr:nth-child(2n+2){
    background-color: #efefef;
  }
  .rwd-table th {
    display: none;
  }
  .rwd-table td {
    display: block;
    border: none;
    position: relative;
    padding-left: 80px;
  }
  .rwd-table td:before {
    content: attr(data-th) " ";
    position: absolute;
    left: 10px;
    top: 5px;
    font-weight: bold;
  }
}

結果顯示
電腦畫面:
https://ithelp.ithome.com.tw/upload/images/20211004/20112053BZw9cENyxs.png
手機畫面(這邊設定在寬度小於480px)
在樣式.rwd-table td:before這地方會用position: absolute;的原因是文字多時換行,讓內容對齊好看。顯示結果如下圖:
https://ithelp.ithome.com.tw/upload/images/20211004/20112053mn6e5VIncN.png
如果用沒有使用的話,標題與內容就會混在一起
https://ithelp.ithome.com.tw/upload/images/20211004/20112053ZtUHN8LZH6.png

div切表格

table ⇒ display:table
tr ⇒ display:table-row
th, td ⇒ display:table-cell

<div class="css-table">
    <div class="thead">
      <div class="tr">
        <div class="th">標題1</div>
        <div class="th">標題2</div>
      </div>
    </div>
    <div class="tbody">
      <div class="tr">
        <div class="td">內容1-1</div>
        <div class="td">內容1-2</div>
      </div>
      <div class="tr">
        <div class="td">內容2-1</div>
        <div class="td">內容2-2</div>
      </div>
      <div class="tr">
        <div class="td">內容3-1</div>
        <div class="td">內容3-2</div>
      </div>
    </div>
  </div>
.css-table{
  display: table;
  border-right: 1px solid #ccc;
  border-bottom: 1px solid #ccc;
}
.css-table .thead{
  display:table-header-group;
}
.css-table .tbody{
  display:table-row-group;
}
.css-table .tr{
  display:table-row;
}
.css-table .th, .css-table .td{
  display:table-cell;
  border: 1px solid #ccc;
  border-width: 1px 0 0 1px;
  padding: 5px 15px;
  height: 40px;
  vertical-align:middle;
}

https://ithelp.ithome.com.tw/upload/images/20211004/20112053nfpMoZTwHL.png

以上是表格的介紹與應用,相信你對表格有一定的了解,那我們明天見~

]]>
sunny 2021-10-04 09:59:33
剪裁與遮罩-30天學會HTML+CSS,製作精美網站 https://ithelp.ithome.com.tw/articles/10275826?sc=rss.iron https://ithelp.ithome.com.tw/articles/10275826?sc=rss.iron 有時候在製作區塊時,會希望用不規則的形狀呈現,以前會將圖片製作成不規則形狀,在放到html裡面,或是用很多元素堆疊呈現,但每次要修改圖片就要再重新做一次,很麻煩。現在可以用clip-path屬性...]]> 有時候在製作區塊時,會希望用不規則的形狀呈現,以前會將圖片製作成不規則形狀,在放到html裡面,或是用很多元素堆疊呈現,但每次要修改圖片就要再重新做一次,很麻煩。現在可以用clip-path屬性或mask屬性設定CSS,就可以輕鬆做出想要的形狀了。

遮罩和剪裁都是隱藏元素一部分,顯示可見區域,他們的區別是遮罩是使用圖像,剪裁是使用路徑

clip-path

Clip-path 屬性能讓你裁剪一個元素中可顯示區域。
瀏覽器支援,更多資訊請看Can i use
https://ithelp.ithome.com.tw/upload/images/20211003/20112053rzodl1u8Pk.png

裁切形狀

inset 內置矩形

clip-path:inset(<length-percentage> round 圓角尺寸)

length-percentage是舉行的四個邊頂點到被裁切元素的距離,順序為上右下左,與margin類似

.shape-box{
  width:100px;
  height: 100px;
  background-color: #2196f3;
  clip-path: inset(10px 20px 30px 40px round 5px 20px);
}

https://ithelp.ithome.com.tw/upload/images/20211003/20112053HAoiiGYGAj.png

circle 圓形

clip-path:circle(圓形半徑 at 圓形位置(X Y座標))

範例:半徑50%

.shape-box{
  width:100px;
  height: 100px;
  background-color: #2196f3;
  clip-path: circle(50%)
}

https://ithelp.ithome.com.tw/upload/images/20211003/201120535OzZSmmkY2.png
範例:半徑50%,位置x座標:100px、y座標:100px

.shape-box{
  width:100px;
  height: 100px;
  background-color: #2196f3;
  clip-path: circle(100% at 100px 100px);
}

https://ithelp.ithome.com.tw/upload/images/20211003/20112053UoJJbDq2Yw.png

ellipse 橢圓形

clip-path:ellipse(橢圓形半徑 at 橢圓形位置(X Y座標))
.shape-box{
  width:100px;
  height: 100px;
  background-color: #2196f3;
  clip-path: ellipse(25% 50% at 50% 50%);
}

https://ithelp.ithome.com.tw/upload/images/20211003/20112053SHwnw8jt1E.png

polygon 多邊形

三角形:設定三個點

.shape-box{
  width:100px;
  height: 100px;
  background-color: #2196f3;
  clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
}

https://ithelp.ithome.com.tw/upload/images/20211003/20112053rZ8D32WJJK.png
四角形:設定四個點,寬高分別為100px,因此設置舉行的數值順時針為(0 0, 0, 100% 100%, 0% 100%)

.shape-box{
  width:100px;
  height: 100px;
  background-color: #2196f3;
  clip-path: polygon(0 0, 100% 0, 100% 100%, 0% 100%);
}

https://ithelp.ithome.com.tw/upload/images/20211003/20112053ZLlyT193iC.png
設定多邊形的順序要同一個方向(順時針或逆時針)

裁剪路徑

透過SVG的<clipPath>來使用clip-path

除了用clip-path屬性寫出基礎圖形外,還可以匯入自己找的svg圖
下圖是我要製作遮罩的圖形及圖片
https://ithelp.ithome.com.tw/upload/images/20211003/20112053kCLdsPSnvy.png
先將圖片匯入至編輯器,複製圖片的svg至你要製作的html檔案裡面,會出現以下的code
https://ithelp.ithome.com.tw/upload/images/20211003/20112053A7VrH3NyN1.png
補上標籤,並給clipPath一個id名稱
https://ithelp.ithome.com.tw/upload/images/20211003/20112053YwuqasejX7.png
將你要裁切圖片放到html裡面,並給他class名稱,這邊是給clip-img

<div class="outer">
    <img src="img/img.jpg" alt="" class="clip-img">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 157 150.4">
      <defs>
        <clipPath id="clipImg">
          <path d="M333.6,237.4c-1-3.2-3.9-5.4-7.2-5.7l-45.3-4.1l-17.9-41.9c-1.3-3.1-4.3-5.1-7.7-5.1c-3.3,0-6.4,2-7.7,5.1l-17.9,41.9
	l-45.3,4.1c-3.3,0.3-6.1,2.6-7.2,5.7c-1,3.2-0.1,6.7,2.4,8.9l34.3,30L204,320.8c-0.7,3.3,0.5,6.7,3.2,8.6c1.5,1.1,3.2,1.6,4.9,1.6
	c1.5,0,3-0.4,4.3-1.2l39.1-23.4l39.1,23.4c2.9,1.7,6.5,1.6,9.2-0.4c2.7-2,4-5.3,3.2-8.6l-10.1-44.5l34.3-30
	C333.7,244.1,334.6,240.6,333.6,237.4z" />
        </clipPath>
      </defs> 
    </svg>
  </div>

在css設置clip-path屬性,路徑為你剛剛在svg設定的id名稱

.clip-img{
  -webkit-clip-path: url(#clipImg);
  clip-path: url(#clipImg);
}

這樣就完成了
https://ithelp.ithome.com.tw/upload/images/20211003/20112053DmtrTExkxS.png
如果覺得太複雜,也可以使用製作clip-path的產生器CSS clip-path maker 網站,可以在選取他右邊的圖形,或是拉畫面上的貝茲曲線,完成後可以複製下方的code貼到你的css
https://ithelp.ithome.com.tw/upload/images/20211003/20112053g0EwjMY7py.png

遮罩 Mask

遮罩與裁剪類似,也是隱藏元素某部分顯示可見區域,但遮罩不同的地方是能依據透明度和灰階數值裁剪邊緣,也能設定其他的遮罩屬性,像是定位、尺寸等方式。
瀏覽器支援,更多資訊請看Can i use
https://ithelp.ithome.com.tw/upload/images/20211003/201120530Yo0b1xhzc.png
Chrome 與 Safari 目前僅支援部分的 mask 功能,須額外添加-webkit-前綴。
mask 與 background 的屬性很類似,相信大家很容易上手的

mask-image

使用 url() 來設定遮罩圖片,遮罩必至少會有兩層,一張是要遮罩的形狀,一張是要被遮罩的圖
以下範例使用這兩張圖做遮罩
https://ithelp.ithome.com.tw/upload/images/20211003/20112053ZDfJxUiK17.jpg

<img src="img/img.jpg" alt="" class="mask-img">
.mask-img{
  mask-image: url('../img/icon.png');
  -webkit-mask-image: url('../img/icon.png');
  width: 400px;
  mask-repeat: no-repeat;
  -webkit-mask-repeat: no-repeat;
	
}

除了使用圖片做遮罩外,也可以使用漸層色來做遮罩,就會依照圖片的透明度或是灰階的數值來做遮罩
https://ithelp.ithome.com.tw/upload/images/20211003/201120539dk28i0Rs8.jpg

.mask-img{
  -webkit-mask: linear-gradient(#000, transparent);
  mask: linear-gradient(#000, transparent);
  width: 400px;
  mask-repeat: no-repeat;
  -webkit-mask-repeat: no-repeat;
  mask-size: contain;
}

mask-repeat

類似background-repeat

repeat

https://ithelp.ithome.com.tw/upload/images/20211003/20112053M63wrAE7hY.png

repeat-x

https://ithelp.ithome.com.tw/upload/images/20211003/20112053lcwN1EF009.png

repeat-y

https://ithelp.ithome.com.tw/upload/images/20211003/20112053HejmD58ncq.png

space

遮罩圖片會有間距,不會有裁切
https://ithelp.ithome.com.tw/upload/images/20211003/20112053obV8I2Sipc.png

round

遮罩圖片緊靠一起不會有間距,遮罩會變形,不會有裁切
https://ithelp.ithome.com.tw/upload/images/20211003/20112053NuReezpLWi.png

mask-position

類似background-position

mask-position:水平設定 垂直設定

數值:px、rem、%
關鍵字:水平設定:left、center、right;垂直設定:top、center、bottom
範例為水平垂直置中

.mask-img{
  mask-image: url('../img/icon.png');
  -webkit-mask-image: url('../img/icon.png');
  width: 400px;
  mask-repeat: no-repeat;
  -webkit-mask-repeat: no-repeat;
  mask-position: center center;
  -webkit-mask-position: center center;
}

https://ithelp.ithome.com.tw/upload/images/20211003/20112053MlgO3pOmdH.png

mask-size

類似background-size

  • 數值:px、rem、%
  • 關鍵字:
    • contain:圖片可以完整地被顯示
      https://ithelp.ithome.com.tw/upload/images/20211003/20112053WhZDYmhfXX.png

    • cover:圖片等比例放大,填滿區塊,但圖片會被裁切掉
      https://ithelp.ithome.com.tw/upload/images/20211003/20112053DXnGsrAuzF.png

結論

使用遮罩或剪裁,能夠有更多不一樣的變化呈現,clip-path屬性目前並非正規支援的效果,使用前還是要到Can i use確認一下瀏覽器支援程度,但在Chrome及Safari要記得加上-webkit-前綴。mask支援度比較好,只是在不同瀏覽器上會有些微的差異

參考資料:
https://www.w3cplus.com/css3/clipping-masking-css.html
https://orandigo.github.io/blog/2020/09/06/20200906-clip-path/
https://iter01.com/514881.html

]]>
sunny 2021-10-03 10:45:30
濾鏡-30天學會HTML+CSS,製作精美網站 https://ithelp.ithome.com.tw/articles/10275825?sc=rss.iron https://ithelp.ithome.com.tw/articles/10275825?sc=rss.iron 前一章節介紹過混合模式,相信對濾鏡也不會很陌生。「濾鏡」是什麼呢?他可以做出與Photoshop相同的濾鏡,CSS提供了十種濾鏡,可以用在圖片、文字...等地方,還能夠搭配滑鼠移入做出不一樣的效...]]> 前一章節介紹過混合模式,相信對濾鏡也不會很陌生。「濾鏡」是什麼呢?他可以做出與Photoshop相同的濾鏡,CSS提供了十種濾鏡,可以用在圖片、文字...等地方,還能夠搭配滑鼠移入做出不一樣的效果

濾鏡相關屬性:

  • backdrop-filter:只對背景有作用
  • filter:可用在圖片、文字...

支援瀏覽器,想看瀏覽器支援可以到 can i use 網站
https://ithelp.ithome.com.tw/upload/images/20211002/20112053OZxKFDVb14.png

grayscale灰階

以%為單位,初始值0%,最大值100%
https://ithelp.ithome.com.tw/upload/images/20211002/20112053aDOpIvq8vg.png

sepia懷舊

以%為單位,初始值0%,最大值100%
https://ithelp.ithome.com.tw/upload/images/20211002/20112053MSsm2TOwk8.png

saturate飽和

以%為單位,初始值100%,大於100%越鮮艷,小於100%彩度變低
https://ithelp.ithome.com.tw/upload/images/20211002/20112053f2iOlHXiqf.png

hue-rotate色相旋轉

以deg為單位,初始值0deg,最大值360deg
https://ithelp.ithome.com.tw/upload/images/20211002/20112053AiSqHNZEmE.png

invert負片

以%為單位,初始值0%,最大值100%
https://ithelp.ithome.com.tw/upload/images/20211002/20112053BAoX8ROTLL.png

opacity不透明

以%為單位,初始值100%,最小值0% ,值越小越透明
https://ithelp.ithome.com.tw/upload/images/20211002/20112053pmz73IVvr3.png
0%雖然看不見,但是他會存在在畫面上

brightness亮度

以%為單位,初始值100%,大於100%越亮,小於100%越暗
https://ithelp.ithome.com.tw/upload/images/20211002/201120537A5HYL7Hxz.png

contrast對比

以%為單位,初始值100%,大於100%對比越大,小於100%對比越小
https://ithelp.ithome.com.tw/upload/images/20211002/20112053EXRPlTTlBh.png

blur模糊

以px為單位,初始值0px,沒有最大值,數字越大越模糊
https://ithelp.ithome.com.tw/upload/images/20211002/20112053MAUr7QkejI.png

drop-shadow下拉陰影

與box-shadow設定值相同,但呈現方式不同

drop-shadow會按照目標原始的內容去產生陰影,box-shadow會按照區塊

比較常遇到的是icon *.png圖片需要做陰影,下圖是box-shadow及drop-shadow設定所呈現的樣式差異
https://ithelp.ithome.com.tw/upload/images/20211002/20112053R6VY41g0AE.png

應用

使用濾鏡樣式做滑鼠移入效果

再也不需要兩張圖了~~只需要準備一張彩色的圖片,使用濾鏡控制滑入前後的樣子,範例是使用灰階濾鏡

<img src="img.jpg" width="200" >
<img src="img.jpg" width="200" >
<img src="img.jpg" width="200" >
img {
    -webkit-filter: grayscale(100%); /* Chrome, Safari, Opera */
    filter:  grayscale(100%);
}
img:hover {
    -webkit-filter: grayscale(0%); /* Chrome, Safari, Opera */
    filter:  grayscale(0%);
}

https://ithelp.ithome.com.tw/upload/images/20211002/20112053MUqGLKVqJm.png

毛玻璃效果

<div class="filter-box">
    <div class="txt">
      orem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.
    </div>
</div>

使用filter做毛玻璃

在filter-box區塊設定一個::after偽元素,裡面放置背景圖相關設定及模糊濾鏡樣式

.filter-box {
  position: relative;
  overflow: hidden;
  z-index: 1;
  width: 100%;
  height: 50vh;
  
}
.filter-box::after{
  content: "";
  background-position: center center;
  background-size: cover;
  position: absolute;
  /* 圖片需超過外層的區塊 */
  top: -30px;
  bottom: -30px;
  left: -30px;
  right: -30px;
  background-image: url("img.jpg");
  filter: blur(8px);
  z-index: -1;
}
.txt{
  background-color: rgba(0,0,0,.3);
  width: 100%;
  height: 100%;
  margin: 0 auto;
  padding: 30px;
  color: #fff;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: center;
}

使用backdrop-filter設定

在filter-box設置背景圖相關設定及模糊濾鏡樣式,然後在文字區塊設定backdrop-filter,就完成了

.filter-box {
  position: relative;
  overflow: hidden;
  /* 加入 z-index,區塊內的文字才能正確顯示 */
  z-index: 1;
  width: 100%;
  height: 50vh;
  background-image: url("https://cdn.pixabay.com/photo/2021/01/19/18/45/field-5932123_1280.jpg");
  background-position: center center;
  background-size: cover;
  
}
.txt{
  background-color: rgba(0,0,0,.3);
  width: 100%;
  height: 100%;
  margin: 0 auto;
  padding: 30px;
  color: #fff;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: center;
  backdrop-filter: blur(5px);
}

https://ithelp.ithome.com.tw/upload/images/20211002/20112053iqv4Owg0QU.png
兩種方式都可以達到同樣效果,就CSS寫法不同而已

資料來源:
https://developer.mozilla.org/zh-CN/docs/Web/CSS/filter

]]>
sunny 2021-10-02 11:28:34
混合模式-30天學會HTML+CSS,製作精美網站 https://ithelp.ithome.com.tw/articles/10275667?sc=rss.iron https://ithelp.ithome.com.tw/articles/10275667?sc=rss.iron 「混合模式」是什麼呢?有用過photoshop的設計師對圖片混合模式肯定不陌生,是元素重疊部分的顏色、飽和度、亮度進行混合變成新的顏色。
混合模式相關屬性:

    「混合模式」是什麼呢?有用過photoshop的設計師對圖片混合模式肯定不陌生,是元素重疊部分的顏色、飽和度、亮度進行混合變成新的顏色。
    混合模式相關屬性:

    • background-blend-mode:混和多個背景圖,只對背景有作用
    • mix-blend-mode:混和文字及圖片

    瀏覽器支援度有限,想看瀏覽器支援可以到 Can i use 網站
    https://ithelp.ithome.com.tw/upload/images/20211001/201120535cezsh8RC4.png

    圖片來源

    有多達16種的效果,讓我們來看看效果吧~
    以下是html結構即要混合的圖片及背景圖元素,下面會依序左圖照片,中間背景色#333,右邊背景色#999,去做混合模式呈現
    https://ithelp.ithome.com.tw/upload/images/20211001/20112053z8lyOcXY9Z.png

    normal 正常

    預設值,不會有任何的改變
    https://ithelp.ithome.com.tw/upload/images/20211001/20112053hwQilmMO2q.png

    multiply 色彩增值

    將背景色與圖片顏色相加在一起,混合後會變成比原本更暗的顏色
    https://ithelp.ithome.com.tw/upload/images/20211001/20112053nT5nyJBL9l.png

    screen 濾色

    將背景色與圖片顏色的補值相乘,得到補色相乘的結果,會比原本的亮
    https://ithelp.ithome.com.tw/upload/images/20211001/2011205321Ah3Ymdp1.png

    overlay 覆蓋

    取決於背景色的值,顏色越暗越黑,顏色越淺越亮
    https://ithelp.ithome.com.tw/upload/images/20211001/20112053FjQMR09cs2.png

    darken 變暗

    兩張重疊的圖,都取最暗的顏色
    https://ithelp.ithome.com.tw/upload/images/20211001/20112053aT6gB31pLk.png

    lighten 變亮

    兩張重疊的圖,都取最亮的顏色
    https://ithelp.ithome.com.tw/upload/images/20211001/20112053Tw7KrehTVG.png

    color-dodge 加亮顏色

    重疊之處再加亮
    https://ithelp.ithome.com.tw/upload/images/20211001/20112053FDtgvH1XDi.png

    color-burn 加深顏色

    重疊之處再加深
    https://ithelp.ithome.com.tw/upload/images/20211001/20112053CaJrQe20ys.png

    hard-light 實光

    效果看起來像是前景被用強光投影到背景上
    https://ithelp.ithome.com.tw/upload/images/20211001/20112053BYHt1Qgu8f.png

    soft-light 柔光

    效果看起來像是前景被用漫射光投影到背景上
    https://ithelp.ithome.com.tw/upload/images/20211001/20112053cLvOg1UrJu.png

    difference 差異化

    將二張影像都轉換成負片效果
    https://ithelp.ithome.com.tw/upload/images/20211001/20112053Jb5e0JfClU.png

    exclusion 排除

    效果近似於差異化但對比度較低
    https://ithelp.ithome.com.tw/upload/images/20211001/20112053B1fiPMPTkq.png

    hue 色相

    用來源色的色相創造出另一個顏色,結合背景原來的飽和度及亮度
    https://ithelp.ithome.com.tw/upload/images/20211001/20112053h4gvmcmk00.png
    因灰色會看不到 所以改為紅色色調,左:background-color:#f91136; 右:background-color:#ff96a7;

    saturation 飽和度

    依來源圖片飽和度提升另一張圖的飽和度
    https://ithelp.ithome.com.tw/upload/images/20211001/20112053XVbyAgs8of.png
    因灰色會看不到 所以改為紅色色調,左:background-color:#f91136; 右:background-color:#ff96a7;

    color 顏色

    依來源圖片的色調、飽和度創造另一個顏色,結合背景色的亮度
    https://ithelp.ithome.com.tw/upload/images/20211001/201120539wYrbn27gu.png

    luminosity 明度

    依來源明度創造出另一個顏色,結合背景的色相及飽和度
    https://ithelp.ithome.com.tw/upload/images/20211001/201120535XTnUQDRCG.png

    結論

    混合模式是將兩張重疊的圖、背景色、文字混合呈現出另一個效果,也可以減少多張圖片在美工軟體編輯處理,相當方便。但使用時,要再確認使用的瀏覽器是否支援

    資料來源:
    https://www.minwt.com/webdesign-dev/css/12699.html
    https://www.minwt.com/ps/793.html

    ]]>
    sunny 2021-10-01 09:10:25 網頁圖片-30天學會HTML+CSS,製作精美網站 https://ithelp.ithome.com.tw/articles/10275076?sc=rss.iron https://ithelp.ithome.com.tw/articles/10275076?sc=rss.iron 圖片在網頁裡是不可或缺的元素,可以增加網站的豐富度及美感,但是也可能造成網站花太多時間載入,使用者體驗不佳,甚至影響到網站的排名。因此,圖片的解析度、檔案大小相當重要。以下就來介紹圖片用於網頁的...]]> 圖片在網頁裡是不可或缺的元素,可以增加網站的豐富度及美感,但是也可能造成網站花太多時間載入,使用者體驗不佳,甚至影響到網站的排名。因此,圖片的解析度、檔案大小相當重要。以下就來介紹圖片用於網頁的注意事項

    嵌入圖片<img>

    在html中插入圖片,是透過src屬性來嵌入圖片。

    <img src="圖片url" alt="替代文字" height="像素" width="像素" />
    

    src:設定圖片路徑

    圖片路徑分為:「相對路徑」與「絕對路徑」

    「相對路徑」:從網站根目錄資料夾到圖片路徑位置

    <img src="img/pic.jpg"  />
    

    「絕對路徑」:取得圖片完整的url

    <img src="http://xxxxx.com.tw/img.jpg"  />
    

    alt:圖片替代文字

    當圖片無法預覽時,取代圖片顯示在網頁上的文字

    <img src="img/pic.jpg" alt="我是圖片" />
    

    https://ithelp.ithome.com.tw/upload/images/20210930/20112053V130rr3ov4.png

    尺寸

    • width:圖片寬,可用px或%
    • height:圖片高,可用px或%

    title:自訂文字

    當滑鼠滑過時,會顯示的文字

    <img src="img/pic.jpg" title="顯示標題文字圖片" />
    

    滑鼠移到圖片上,會出現title屬性輸入的文字
    https://ithelp.ithome.com.tw/upload/images/20210930/20112053TXv22XX8UX.jpg

    網頁圖片你要知道的事

    標題 網頁 印刷
    尺寸 px像數 cm公分、mm公釐
    色彩模式 RGB CMYK
    解析度要求 72ppi 300dpi
    檔案格式 JPG, PNG, GIF TIFF, EPS, JPG, PNG
    • jpg:用於用在尺寸較大的照片大圖
    • png:保留圖片透明度
    • svg:向量檔,縮放不失真
    • gif:小圖動態圖片

    優化圖片

    通常影響網頁速度的原因都是在圖片讀取,導致使用者沒耐心直接離開網站,導致使用者體驗不佳,甚至網站的排名下降,四個小技巧改善圖片提升網站速度

    壓縮圖片檔案大小

    可以使用 tinypng 針對png與jpg圖檔 線上壓縮圖片工具,只需將要壓縮的圖片拖曳到網站上就可以進行壓縮,一次只能壓縮20張,每張檔案大小5MB內。
    https://ithelp.ithome.com.tw/upload/images/20210930/20112053mPhICSfcpk.png

    圖片尺寸為適當大小

    像是圖片使用尺寸大小500400,卻將圖片設置比他大的尺寸900800,再用css去設定圖片的寬度

    透過Lazy Loading延遲圖片仔入

    當網站圖片很多的時候,可以使用Lazy Loading,可以大幅提升網路載入的速度及流量的浪費。
    使用Lazy Loading是瀏覽器已經內建功能不需要任何Javascript、CSS,只需要在標籤加上loading 屬性

    <img src="img/pic.jpc" loading="lazy">
    
    • lazy:延遲載入畫面外的圖片
    • eager:不管元素在哪裡都會立即載入圖片

    CSS Sprite

    將多張icon小圖合併在一張大圖裡面,再將圖片放到背景圖(background-image),使用背景定位(background-position)方式顯示正確的icon。但CSS Sprite還是有使用上的優缺點,使用前還是自己評估。

    優點:減少網頁的http請求,也沒有圖片命名的困擾
    缺點:是要規劃好每張圖的精確位置

    響應式圖片-srcset 、sizes

    srcset、sizes屬性目的是瀏覽器會自動判斷螢幕寬度或解析度,自動載入不同大小的圖片

    srcset

    用來指定多張不同尺寸的圖片,當瀏覽器不支援時,就會用src的圖片

    <img srcset="圖片路徑 大小單位, 圖片路徑 大小單位" src="圖片路徑" />
    

    以實際圖片寬度 w 當單位

    <img srcset="pic-480.jpg 480w,
                 pic-767.jpg 767w,
                 pic-1280.jpg 1280w"
         src="pic.jpg"
    >
    

    <img>寬度為480時,載入pic-480.jpg,寬度為767時,載入pic-767.jpg...以此類推

    以螢幕解析度(pixel density) x 當單位

    <img srcset="pic-1x.jpg 1x,
                 pic-2x.jpg 2x,
                 pic-3x.jpg 3x"
         src="pic.jpg"
    >
    

    設備pixel density 是 1時,載入pic-1x.jpg,pixel density 是 2,載入pic-2x.jpg...以此類推

    sizes

    用來輔助srcset屬性,瀏覽器在不同的螢幕大小,該給什麼尺寸的圖片,所以圖片的排版寬度設定,還是要由CSS處理。單位可以使用px或vw

    <img srcset="圖片路徑 大小單位, 圖片路徑 大小單位" 
    		 size="media query條件 使用的圖片實際寬度, media query條件 使用的圖片實際寬度" 
    		 src="圖片路徑" />
    

    只有在 srcset 以 w 為單位時才可使用 sizes

    <img srcset="pic-480.jpg 480w,
                 pic-767.jpg 767w,
                 pic-1280.jpg 1280w"
    		 sizes="(max-width: 480px) 480px,
                (max-width: 767px) 767px,
    						900px"
         src="pic.jpg"
    >
    

    當螢幕寬度小於480px時,使用480px的圖片,螢幕寬度小於767px時,使用767px的圖片,如果都沒有指定 media query 條件時,就使用900px的圖片

    圖片樣式

    除了使用美美的照片外,將圖片調整到適當的大小,套用不同的樣式,像是圓角圖片、陰影、邊框...設定,可以讓整體版面看起來更加豐富,以下範例是常用的圖片樣式設定:

    圓角、圓形

    <img src="pic1.jpg" alt="" class="pic1">
    <img src="pic2.jpg" alt="" class="pic2">
    
    img{
      width: 100px;
      height: 100px;
      margin-right: 10px;
    }
    .pic1{
    	border-radius:20px;
    }
    .pic2{
    	border-radius:50%;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210930/20112053PAVUGzi0WX.png

    設定圖片陰影、邊框、內距

    <img src="pic1.jpg" alt="">
    <img src="pic2.jpg" alt="">
    
    img{
      width: 200px;
    	border:2px solid #ccc;
    	padding:8px;
    	box-shadow: 3px 3px 4px #ccc;
      margin-right: 10px;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210930/20112053CLzh3701lS.png

    響應式圖片

    假設有一張圖片500px,當你設定max-width:100%,你的瀏覽器寬度如果小於圖片寬500px,圖片就會顯示瀏覽器的寬度

    img{
    	max-width:100%;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210930/20112053niH8neyTXU.png
    當沒有設定max-width:100%時,在小螢幕,圖片不會自動縮放ㄝ就會有水平卷軸
    https://ithelp.ithome.com.tw/upload/images/20210930/20112053862TmQXEkS.png

    object-fit / object-position

    在「網頁顏色-30天學會HTML+CSS,製作精美網站」這篇有提到,當無法預期使用者上傳圖片尺寸時,高度大小不同會導致版面跑版,所以就要把圖片寫在背景圖、設定圖片位置及尺寸,讓他們看起來一致。

    這裡要來教你使用「object-fit」、「object-position」樣式,不用把圖片設為背景圖,也可以做到一樣的效果囉~

    object-fit

    • none:保持原先尺寸,預設值
    • contain:圖片可以完整地被顯示,會等比例縮放在指定範圍內
    • cover:圖片等比例放大,填滿區塊,但圖片會被裁切掉
    • fill:圖片填滿盒子,但不會按照原比例會變形
    <div>
    	<h2>object-fit: fill(默認):</h2>
    	<img class="fill" src="img.jpg">
    </div>
    <div>
    	<h2>object-fit: contain:</h2>
    	<img class="contain" src="img.jpg">
    </div>
    <div>
    	<h2>object-fit: cover:</h2>
    	<img class="cover" src="img.jpg">
    </div>
    
    .fill {object-fit: fill;}
    .contain {object-fit: contain;}
    .cover {object-fit: cover;}
    

    https://ithelp.ithome.com.tw/upload/images/20210930/20112053tnKQibetFb.png

    object-position

    與background-position類似,設定圖片XY軸位置,可以設定數值及關鍵字

    • 數值:px、rem、%
    • 關鍵字:水平設定:left、center、right;垂直設定:top、center、bottom
    <div>
    	<h2>object-position:20px top</h2>
    	<img class="top" src="https://cdn.pixabay.com/photo/2021/03/29/01/54/wallaby-6132753__480.jpg">
    </div>
    <div>
    	<h2>object-position:center center</h2>
    	<img class="center" src="https://cdn.pixabay.com/photo/2021/03/29/01/54/wallaby-6132753__480.jpg">
    </div>
    <div>
    	<h2>object-position:100% bottom</h2>
    	<img class="bottom" src="https://cdn.pixabay.com/photo/2021/03/29/01/54/wallaby-6132753__480.jpg">
    </div>
    
    .top {object-position: 20px top;}
    .center {object-position: center center;}
    .bottom {object-position: 100% bottom;}
    

    https://ithelp.ithome.com.tw/upload/images/20210930/20112053zY4VHGKH5Y.png
    就想像object-fit類似background-size,object-position類似background-position,是不是很簡單呢?

    結論

    圖片是網頁不可或缺的元素,可以用樣式做到很多的變化,像是邊框、陰影....,但是在使用上就要注意圖片檔案大小,避免使網站載入速度過慢,導致使用者沒耐心直接跳出。相信你已經對圖片使用了解了,以上是今天的介紹,那我們明天見~

    資料來源:
    https://www.fooish.com/html/image-img-tag.html
    https://www.zhangxinxu.com/wordpress/2015/03/css3-object-position-object-fit/
    https://developer.mozilla.org/zh-CN/docs/Web/CSS/object-position

    ]]>
    sunny 2021-09-30 09:17:04
    項目清單-30天學會HTML+CSS,製作精美網站 https://ithelp.ithome.com.tw/articles/10274440?sc=rss.iron https://ithelp.ithome.com.tw/articles/10274440?sc=rss.iron 項目清單分為條列式清(ol)單及編號清單(ul),兩者的差別在於是否有自動排序項目的功能,<ul>是黑點符號「●」,在不同的瀏覽器下可能呈現不同的效果,而 ...]]> 項目清單分為條列式清(ol)單及編號清單(ul),兩者的差別在於是否有自動排序項目的功能,<ul>是黑點符號「●」,在不同的瀏覽器下可能呈現不同的效果,而 <ol> 標籤則具有數字排序的功能,也就是預設在每個項目前會有數字顯示,從 1 開始依序排列。

    通常會用在需要將條列式的內容列出來,能提高文章的易讀性。

    ul條列式清單

    ul是「Unordered List」的縮寫,意思是「沒有指定順序的清單」。li是「List Item」的縮寫,意思是條列式項目。出現在網頁時,出現黑點。

    <ul>
      <li>item1</li>
      <li>item2</li>
      <li>item3</li>
    </ul>
    

    https://ithelp.ithome.com.tw/upload/images/20210929/20112053933c8Iq3Ml.png

    ol編號清單

    ol是「Ordered List」的縮寫,意思是「有確定順序的清單」。顯示在網頁時,會有數字編號。

    <ol>
      <li>item1</li>
      <li>item2</li>
      <li>item3</li>
    </ol>
    

    https://ithelp.ithome.com.tw/upload/images/20210929/20112053FsK8hDNZmj.png

    type屬性

    • 1:默認(1, 2, 3, 4, 5)
    • a:小寫字母 (a, b, c, d, e)
    • A:大寫字母(A, B, C, D, E)
    • i:小寫羅馬字母(i, ii, iii, iv)
    • I:大寫羅馬字母(I, II, III, IV)
    <ol type="I">
       <li>item1</li>
       <li>item2</li>
       <li>item3</li>
    </ol>
    <ol type="i">
       <li>item1</li>
       <li>item2</li>
       <li>item3</li>
    </ol>
    <ol type="a">
       <li>item1</li>
       <li>item2</li>
       <li>item3</li>
    </ol>
    <ol type="A">
       <li>item1</li>
       <li>item2</li>
       <li>item3</li>
    </ol>
    <ol type="1">
       <li>item1</li>
       <li>item2</li>
       <li>item3</li>
    </ol>
    

    https://ithelp.ithome.com.tw/upload/images/20210929/20112053U7GdVGV0vu.png

    指定排序

    start 指定數字排序,以下範例是以10為開始點, type不同也會有不一樣符號的顯示

    <ol start = 10>
       <li>第一個列表項
       <li>第二個列表項
       <li>第三個列表項
    </ol>
    

    https://ithelp.ithome.com.tw/upload/images/20210929/20112053yJZo9n3xIV.png
    指定順序與type一起使用,範例:

    <ol type="I" start="5">
      <li>列表項</li>
      <li>列表項</li>
      <li>列表項</li>
    </ol>
    

    https://ithelp.ithome.com.tw/upload/images/20210929/20112053bklPDEIUAV.png

    dl dt dd自定義列表

    <dl>裡面包含<dt><dd>
    <dt>是一個名詞用語,像是標題
    <dd>用來說明名詞用語,可以是圖片、連結、內容

    <dl>
     <dt>item1</dt>
     <dd>depiction1 ...</dd>
    	<dd>depiction1-1 ...</dd>
     <dt>item2</dt>
     <dd>depiction2 ...</dd>
    	<dd>depiction2-1 ...</dd>
    </dl>
    

    項目列表樣式

    list-style-type

    設定 ul li 或 ol li 的項目符號,像是無標示、空心圓圈、實心圓圈、大寫英文字母、小寫英文字母等,分為項目符號及編號符號

    項目符號

    • none:不顯示
    • disc:預設值,實心圓形
    • circle:空心圓點
    • square:實心方塊

    編號符號

    • decimal:阿拉伯數字(1、2...)
    • decimal-leading-zero:阿拉伯數字(01、02..)
    • lower-alpha / upper-alpha:小寫/大寫英文字母(a / A)
    • lower-roman / upper-roman:小寫/大寫羅馬數字(i / I)
    • lower-greek:小寫希臘字母
    <p>條列式:</p>
    <ul class="circle">
      <li>item1</li>
      <li>item2</li>
      <li>item3</li>
    </ul>
    
    <ul class="square">
      <li>item1</li>
      <li>item2</li>
      <li>item3</li>
    </ul>
    
    <p>編號:</p>
    <ol class="upper-roman">
      <li>item1</li>
      <li>item2</li>
      <li>item3</li>
    </ol>
    <!-- 也能使用html指定排序start -->
    <ol class="lower-alpha" start="5">
      <li>item1</li>
      <li>item2</li>
      <li>item3</li>
    </ol>
    
    .circle {list-style-type:circle;}
    .square {list-style-type:square;}
    .upper-roman {list-style-type:upper-roman;}
    .lower-alpha {list-style-type:lower-alpha;}
    

    https://ithelp.ithome.com.tw/upload/images/20210929/201120532IpJMFGDzq.png

    list-style-position

    • inside:項目符號在 <li></li> 標籤範圍之內
    • outside:項目符號在 <li></li> 標籤範圍之外,預設值。
      範例:circle是在項目符號內,outside是在項目符號外
    <ul class="circle">
      <li>item1</li>
      <li>item2</li>
      <li>item3</li>
    </ul>
    
    <ul class="square">
      <li>item1</li>
      <li>item2</li>
      <li>item3</li>
    </ul>
    
    ul{
    	background-color:#efefef;
    }
    li{
    	border:1px solid #ccc;
    }
    .circle {
    	list-style-type:circle;
    	list-style-position:inside;
    }
    .square {
    	list-style-type:square;
    	list-style-position:outside;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210929/201120538MzM29J7Kr.png

    list-style-image

    用圖片取代list-style-type原本的項目符號

    list-style-image:url(' 要顯示的圖片檔案位置 ');

    <ul class="circle">
      <li>item1</li>
      <li>item2</li>
      <li>item3</li>
    </ul>
    
    ul li {
        list-style-image:url('img/img.png');
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210929/201120534uPyWUVFtW.png
    除了使用list-style-image圖片取代項目符號之外,還有以下兩種方法也可以做到相同的效果,讓我們來看看

    方法一:使用圖片<img>

    先將圖片插入到裡面

    <ul class="square">
    	<li>
    		<img src="img/img.png" />
    		<span>item1</span>
    	</li>
    	<li>
    		<img src="img/img.png" />
    	</li>
    	<li>
    		<img src="img/img.png" />
    		<span>item3</span>
    	</li>
    </ul>
    

    https://ithelp.ithome.com.tw/upload/images/20210929/20112053Gc6SauwYAb.png
    之後再將項目符號點點隱藏

    ul{
    	list-style-type: none;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210929/20112053Je5vFhF4NM.png

    方法二:使用背景圖

    <ul class="square">
      	<li>
    		<span>item1</span>
    	</li>
    	<li>
    		<span>item2</span>
    	</li>
    	<li>
    		<span>item3</span>
    	</li>
    </ul>
    

    將項目符號隱藏,在將圖片設為背景圖、圖片不重複、圖片位置及內距padding-left,避免圖片及文字重疊

    li{
    	list-style-type: none;
    	margin:0;
    	padding:0 0 0 20px;
    	background-position: left center;
    	background-repeat:no-repeat;
    	background-image:url('img/img.png')
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210929/20112053DfLtXkzcxF.png
    以上兩種方法,呈現結果與使用list-style-image是一樣的

    list-style

    綜合所有項目清單樣式,該屬性值的順序是:

    list-style: list-style-type  list-style-position list-style-image
    
    ul
    {
        list-style:square url('img/img.png');
    }
    

    要製作一個畫面有很多種方法,有時候可以省去寫很多的code,依照自己的習慣選一種方式製作,可以提高工作效率,也可減少不必要的失誤。

    ]]>
    sunny 2021-09-29 09:51:10
    網頁超連結-30天學會HTML+CSS,製作精美網站 https://ithelp.ithome.com.tw/articles/10273744?sc=rss.iron https://ithelp.ithome.com.tw/articles/10273744?sc=rss.iron 超連結是建立網頁與網頁之間的關係,也可以連結到外部網站。a是Anchor的縮寫,中文翻譯為「錨」,點擊後跳到指定位置。連結可以是文字、圖片或檔案,當使用者滑過時,會出現手指的形狀,點擊後就會跳到...]]> 超連結是建立網頁與網頁之間的關係,也可以連結到外部網站。a是Anchor的縮寫,中文翻譯為「錨」,點擊後跳到指定位置。連結可以是文字、圖片或檔案,當使用者滑過時,會出現手指的形狀,點擊後就會跳到對應的相關頁面、檔案、電子信箱...。超連結預設顯示為藍色,閱讀過的超連結顯示為紫色。

    以下是超連結的語法:

    <a href="網址/路徑/檔名">連結名稱(可以是圖片、文字)</a>
    

    屬性

    href

    利用href設定連結目標,可以是絕對位置(外部連結)、相對位置(檔案路徑)、電話、信箱、id屬性

    絕對位置(外部連結)

    <a href="https://www.google.com/">google</a>
    

    相對位置(檔案路徑)

    資料夾路徑最好不要超過三層,會增加搜尋的困難度,對SEO也會有影響

    <a href="about.html">about</a>
    

    電話超連結

    至今大多數的人使用行動裝置佔大多數,在網頁上看到店家電話號碼,只要在按下號碼,就可以撥打,省去自行輸入電話號碼。

    在href屬性加上「tel」

    <!-市內電話寫法->
    <a href="tel:+886-2-12345678">1234-5678</a>
    <!-手機號碼寫法->
    <a href="tel:+886-988******">0988-***-***</a>
    
    

    還有另一個需要注意的是,在行動網頁瀏覽時,發現iPhone的safari會誤判數字為電話號碼,要取消這問題,只要在加上這下面這行就可以解決囉

    <meta name="format-detection" content="telephone=no">
    

    信箱超連結

    按下連結可直接寄電子郵件給對方。當使用者點擊後,會跳出使用者預設的電子郵件軟體,並在收件者欄位自動輸入指定的電子郵件帳號。

    在href屬性加上「matilto」

    <a href="mailto:test@yoursite.com">Send Email</a>
    

    id屬性-移動到某位置

    將連結設定要跳轉到id目標元素上,href屬性加上「#」字號,接著將區塊內容設定id名稱,就可以在網頁上隨心所欲的跳轉到對應位置了

    <body>
        <a href="#div1">go div1</a>
        <a href="#div2">go div2</a>
        <a href="#div3">go div3</a>
        <div id="div1">div1</div>
        <div id="div2">div2</div>
        <div id="div3">div3</div>
    </body>
    

    target

    開啟瀏覽器的方式

    • _self: 預設值,在目前瀏覽頁面顯示
    • _blank: 另開新視窗
    • _parent: 在上一層父視窗開啟
    • _top: 在瀏覽器的頂端顯示

    如果是外部連結,target建議設定為_blank另開視窗

    title

    文字描述,當滑鼠滑過時會出現的文字
    https://ithelp.ithome.com.tw/upload/images/20210928/20112053BEOxjFHFqq.png

    <a href="網站位址" title="連結文字敘述">連結名稱</a>
    

    樣式

    為了讓使用者可以辨識是否為超連結,會設定樣式,像是滑入做樣式改變、滑鼠游標會出現手指

    連結四種狀態

    • a:link - 正常,未訪問過,文字會顯示藍色
    • a:visited - 用戶已訪問過,文字會顯示紫色
    • a:hover - 滑鼠滑入
    • a:active - 被點擊的那一刻
    <a href="#">未被訪問的超連結</a>
    <a href="http://www.yahoo.com">滑入超連結</a>
    <a href="http://www.google.com">造訪超連結</a>
    <a href="http://www.active.com">點擊超連結</a>
    
    a:link{
      color:#333;
      text-decoration: none
    }
    /*已經被造訪過的超連結*/
    a:visited{
      color:#593588
    }
    /*滑鼠移過去的樣子*/
    a:hover{
      color:#1961ce;
    }
    /*點擊不放時的樣子*/
    a:active{
      color:#885f35;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210928/20112053lZ6tuctGmy.png
    超連結可以設定CSS多種樣式像是color、font-family、background...,上面的範例是只做文字顏色的改變,如何設定文字樣式可參考網頁文字-30天學會HTML+CSS,製作精美網站

    資料參考:
    http://coding.anyun.tw/2012/02/24/disable-mobile-safari-detect-telephone/

    ]]>
    sunny 2021-09-28 08:52:05
    網頁顏色-30天學會HTML+CSS,製作精美網站 https://ithelp.ithome.com.tw/articles/10273025?sc=rss.iron https://ithelp.ithome.com.tw/articles/10273025?sc=rss.iron 好的網站除了內容傳達之外,顏色是進入網站的第一印象,可以針對文字大小、框線、背景色...等做變化,是網站中不可或缺的樣式,現在讓我們來看看顏色及背景的使用技巧吧

    Color 顏色...]]> 好的網站除了內容傳達之外,顏色是進入網站的第一印象,可以針對文字大小、框線、背景色...等做變化,是網站中不可或缺的樣式,現在讓我們來看看顏色及背景的使用技巧吧

    Color 顏色

    色碼

    以井字號為首加上六個英文數字,如果六個連續相同數值,可以寫成三位數。
    例如:黑色#000000可簡寫成#000

    RGB

    RGB由紅色(Red)、綠色(Green)、藍色(Blue)組成,寫法為「rgb(紅色值、綠色值、藍色值)」。數值介於0-255之間,0代表最暗,數字越大越明亮。
    例如:rgb(255,255,255) ⇒ 白色 、 rgb(0,0,0) ⇒黑色

    如果要指定透明度,可用不透明度Alpha值,不透明度介於0-1之間,0為透明,1為不透明。寫法為「rgba(紅色值、綠色值、藍色值、不透明度)」。
    例如:rgba(255,255,255,0.5)

    顏色名稱

    直接寫顏色名稱。
    例如:紅色(red)、藍色(blue)

    <h1>使用16進制</h1>
    <h2>使用rgb</h2>
    <p>使用顏色名稱</p>
    
    /*使用十六進制*/
    h1{
    	color: #000000
    }
    /*使用rgb*/
    h2{
    	color: rgba(27,0,230)
    }
    /*使用顏色名稱*/
    p{
    	color: red;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210927/20112053U1Qv1sZcXm.png
    色彩配色以下是我自己常用的

    background 背景

    background-color背景色

    改變元素的背景顏色。樣式設定方式與顏色相同。
    範例:

    <div class="text">
      背景色區塊
    </div>
    
    .text{
      /* 色碼設定 */
    	background-color:#000; 
      /* RGB設定 */
    	/* background-color:rgb(0,0,0); */
      /* 顏色名稱設定 */
    	/* background-color:black;  */
    	color:#fff;
    	padding:5px 10px;
      width:120px;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210927/2011205337aCzeoL1a.png

    background-image背景圖

    • url:圖片的路徑
    • none:無背景圖
      範例:以多張圖片堆疊,使用多張圖時用逗號隔開,寫在前面的會在圖層上方
    .bg-single{
      background-image: url('./img/people.png'), url('./img/bg.png');
      width: 100%;
      height: 100vh;
      background-size: 45%, cover;
      background-position: 80% bottom,center bottom;
      background-repeat: no-repeat;
    }
    

    background-image(背景圖):前者為聖誕老公公,後者為背景圖
    background-size(背景圖片尺寸):聖誕老公公圖片寬度為45%,背景圖為填滿
    background-position(背景圖片位置):聖誕老公公位置在水平80%垂直在下方,背景圖為水平置中垂直在下方
    background-repeat為不重複
    background其他屬性稍後會在做詳細介紹
    以下範例是使用這兩張圖片做堆疊
    https://ithelp.ithome.com.tw/upload/images/20210927/20112053OD2ua5Zuk4.png
    結果:
    https://ithelp.ithome.com.tw/upload/images/20210927/20112053H8XmCTxxln.png

    background-repeat背景圖是否重複

    • repeat:水平、垂直重複
    • repeat-x:水平重複
    • repeat-y:垂直重複
    • no-repeat:不重複
    <div class="box box1">
      <div class="head">repeat:水平、垂直重複</div>
      <div class="body"></div>
    </div>
    <div class="box box2">
      <div class="head">repeat-x:水平重複</div>
      <div class="body"></div>
    </div>
    <div class="box box3">
      <div class="head">repeat-y:垂直重複</div>
      <div class="body"></div>
    </div>
    <div class="box box4">
      <div class="head">no-repeat:不重複</div>
      <div class="body"></div>
    </div>
    
    .box{
      width: calc(25% - 50px);
      border: 1px solid #efefef;
      margin: 10px;
      padding: 10px;
    }
    .box .body{
      margin-top: 10px;
      height: 150px;
      background-image: url('../img/pig.png');
    }
    .box1 .body{
      background-repeat: repeat;
    }
    .box2 .body{
      background-repeat: repeat-x;
    }
    .box3 .body{
      background-repeat: repeat-y;
    }
    .box4 .body{
      background-repeat: no-repeat;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210927/20112053mfUJkLcM8U.png

    background-position背景圖位置

    background-position:水平設定 垂直設定
    
    • 數值:px、rem、%
    • 關鍵字:水平設定:left、center、right;垂直設定:top、center、bottom
    <div class="box box1">
        <div class="head">水平:left 垂直:top</div>
        <div class="body"></div>
      </div>
      <div class="box box2">
        <div class="head">水平:left center</div>
        <div class="body"></div>
      </div>
      <div class="box box3">
        <div class="head">水平:left 垂直:bottom</div>
        <div class="body"></div>
      </div>
      <div class="box box4">
        <div class="head">水平:center 垂直:top</div>
        <div class="body"></div>
      </div>
      <div class="box box5">
        <div class="head">水平:center center</div>
        <div class="body"></div>
      </div>
      <div class="box box6">
        <div class="head">水平:center 垂直:bottom</div>
        <div class="body"></div>
      </div>
      <div class="box box7">
        <div class="head">水平:right 垂直:top</div>
        <div class="body"></div>
      </div>
      <div class="box box8">
        <div class="head">水平:right center</div>
        <div class="body"></div>
      </div>
      <div class="box box9">
        <div class="head">水平:right 垂直:bottom</div>
        <div class="body"></div>
      </div>
      <div class="box box10">
        <div class="head">水平:30% 垂直:80%</div>
        <div class="body"></div>
      </div>
    
    .box{
      width: calc(100% / 3 - 50px);
      border: 1px solid #efefef;
      margin: 10px;
      padding: 10px;
    }
    .box .body{
      background-color: #efefef;
      background-repeat: no-repeat;
      margin-top: 10px;
      height: 90px;
      background-image: url('../img/pig.png');
    }
    .box1 .body{
      background-position: left top;
    }
    .box2 .body{
      background-position: left center;
    }
    .box3 .body{
      background-position: left bottom;
    }
    .box4 .body{
      background-position: center top;
    }
    .box5 .body{
      background-position: center center;
    }
    .box6 .body{
      background-position: center bottom;
    }
    .box7 .body{
      background-position: right top;
    }
    .box8 .body{
      background-position: right center;
    }
    .box9 .body{
      background-position: right bottom;
    }
    .box10 .body{
      background-position: 30% 80%;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210927/20112053SH53y9HfaG.png
    以上範例是針對不同的設定,背景圖的位置
    我自己比較常用的地方是有圖片的列表資訊,有時候客戶上傳圖片尺寸不一樣,導致圖片高度不一致,所以會設定高度,將圖片填滿在框框裡面,不管客戶上傳各式的尺寸,版面看起來也都會一致。
    以下這是設置圖片,在class="img"沒設置高度,所以圖片尺寸不同就會導致跑版

    <div class="box box1">
        <div class="img">
          <img src="img/img1.jpg" alt="">
        </div>
        <div class="body"> Fusce consectetur rhoncus malesuada. Cras ut condimentum mauris, sed interdum mi. Sed et sagittis tellus.</div>
      </div>
      <div class="box box2">
        <div class="img">
          <img src="img/img2.jpg" alt="">
        </div>
        <div class="body"> Fusce consectetur rhoncus malesuada. Cras ut condimentum mauris, sed interdum mi. Sed et sagittis tellus.</div>
      </div>
      <div class="box box3">
        <div class="img">
          <img src="img/img3.jpg" alt="">
        </div>
        <div class="body"> Fusce consectetur rhoncus malesuada. Cras ut condimentum mauris, sed interdum mi. Sed et sagittis tellus.</div>
      </div>
      <div class="box box4">
        <div class="img">
          <img src="img/img4.jpg" alt="">
        </div>
        <div class="body"> Fusce consectetur rhoncus malesuada. Cras ut condimentum mauris, sed interdum mi. Sed et sagittis tellus.</div>
      </div>
      <div class="box box5">
        <div class="img">
          <img src="img/img5.jpg" alt="">
        </div>
        <div class="body"> Fusce consectetur rhoncus malesuada. Cras ut condimentum mauris, sed interdum mi. Sed et sagittis tellus.</div>
      </div>
      <div class="box box6">
        <div class="img">
          <img src="img/img6.jpg" alt="">
        </div>
        <div class="body"> Fusce consectetur rhoncus malesuada. Cras ut condimentum mauris, sed interdum mi. Sed et sagittis tellus.</div>
      </div>
    
    .box{
      width: calc(100% / 3 - 50px);
      border: 1px solid #efefef;
      margin: 10px;
      padding: 10px;
    }
    .box .img img{
      width: 100%;
    }
    .box .img{
      margin-bottom: 10px;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210927/20112053OVFlyjoPV6.png

    .box{
      width: calc(100% / 3 - 50px);
      border: 1px solid #efefef;
      margin: 10px;
      padding: 10px;
    }
    .box .img{
      background-position: center center;
      background-repeat: no-repeat;
      background-size: cover;
      height: 150px;
      margin-bottom: 10px;
    }
    .box1 .img{
      background-image: url('../img/img1.jpg');
    }
    .box2 .img{
      background-image: url('../img/img2.jpg');
    }
    .box3 .img{
      background-image: url('../img/img3.jpg');
    }
    .box4 .img{
      background-image: url('../img/img4.jpg');
    }
    .box5 .img{
      background-image: url('../img/img5.jpg');
    }
    .box6 .img{
      background-image: url('../img/img6.jpg');
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210927/20112053tW0OgH3DHE.png

    background-size背景圖大小

    • 數值:px、rem、%
    • 關鍵字:
      • contain:圖片可以完整地被顯示,會等比例縮放在指定範圍內
      • cover:圖片等比例放大,填滿區塊,但圖片會被裁切掉
    <div class="box box1">
      background-size: cover;
      <div class="img"></div>
    </div>
    <div class="box box2">
      background-size: contain;
      <div class="img"></div>
    </div>
    
    .box{
      width: calc(100% / 3 - 50px);
      border: 1px solid #efefef;
      margin: 10px;
      padding: 10px;
    }
    .box .img{
      margin-top: 10px;
      height: 300px;
      background-repeat: no-repeat;
      background-color: #efefef;
      background-image: url('../img/img.jpg');
    }
    .box1 .img{
      background-size: cover;
    }
    .box2 .img{
      background-size: contain;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210927/20112053zcdOCvAzYF.png

    background-attachment背景圖是否隨內容滾動

    • scroll:背景會跟隨頁面滾動,預設值
    • fixed:背景不會跟隨頁面滾動
    <div class="box box1"></div>
    <div class="box box2"></div>
    
    .box{
      width: 100%;
      height: 600px;
      background-size: cover;
      background-repeat: no-repeat;
      
    }
    .box1{
      background-attachment: fixed;
      background-image: url('img1.jpg');
    }
    .box2{
      background-image: url('img2.jpg');
    }
    

    將第一張背景圖樣式設定為fixed,不會隨畫面滾動,下方背景圖向上滾動就會有滾動視差
    https://ithelp.ithome.com.tw/upload/images/20210927/20112053zWhGJS29M6.png
    https://ithelp.ithome.com.tw/upload/images/20210927/201120537SreWNltLd.png

    background統一設定背景相關屬性

    backgorund: [color] [image] [position] [size] [repeat] [attatchment] [origin] [clip]

    需要注意的是,如果background-size與background-position同時存在時,要用斜線隔開

    .box{
    	background: #000 url(img/bg.png) no-repeat center bottom/cover;
    }
    

    linear-gradient 漸層

    線性漸層

    background:linear-gradient(方向, 顏色1 位置, 顏色2 位置);
    

    方向

    用英文或角度表示,預設是由上往下
    https://ithelp.ithome.com.tw/upload/images/20210927/201120534fXxmUdepD.jpg
    範例:
    由上而下 to bottom,下面這五種寫法,產生出來的結果會是一樣的

    .box{
      width: 200px;
      height: 200px;
      background:linear-gradient(rgba(240,249,255,1), rgba(161,219,255,1));
      /* background:linear-gradient(to bottom, rgba(240,249,255,1), rgba(161,219,255,1)); */
      /* background:linear-gradient(180deg,rgba(240,249,255,1), rgba(161,219,255,1)); */
      /* background:linear-gradient(to top, rgba(161,219,255,1), rgba(240,249,255,1)); */
      /* background:linear-gradient(to bottom, rgba(240,249,255,1) 0%, rgba(161,219,255,1) 100%); */
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210927/201120534kISljBj98.png

    顏色位置

    多種漸層色

    起點顏色到終點顏色0%-100%,至少會有兩個顏色,如果中間會再有第三個顏色,用百分比設置第三個顏色位置。

    .box {
      width: 200px;
      height: 200px;
      background: -moz-linear-gradient(top, rgba(180, 227, 145, 1) 0%, rgba(97, 196, 25, 1) 50%, rgba(180, 227, 145, 1) 100%);
      background: -webkit-linear-gradient(top, rgba(180, 227, 145, 1) 0%, rgba(97, 196, 25, 1) 50%, rgba(180, 227, 145, 1) 100%);
      background: linear-gradient(to bottom, rgba(180, 227, 145, 1) 0%, rgba(97, 196, 25, 1) 50%, rgba(180, 227, 145, 1) 100%);
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210927/20112053qOVYMX1ZRS.png

    顏色重疊
    .box {
      width: 200px;
      height: 200px;
      background: -moz-linear-gradient(-45deg, rgba(109,179,242,1) 50%, rgba(30,105,222,1) 50%);
      background: -webkit-linear-gradient(-45deg, rgba(109,179,242,1) 50%,rgba(30,105,222,1) 50%);
      background: linear-gradient(135deg, rgba(109,179,242,1) 50%,rgba(30,105,222,1) 50%);
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210927/20112053opG7iTsgj3.png

    放射狀漸層

    background:radial-gradient(形狀 長度 at 位置, 顏色1 位置, 顏色2 位置);
    

    形狀

    有圓形(circle)及橢圓形(ellipse),圓形設定尺寸時,只需要給一個數值;橢圓形需給x軸與y軸的尺寸
    範例:圓形,漸層半徑80px

        background:radial-gradient(circle 80px,#FFB76B,#D83900);
    

    https://ithelp.ithome.com.tw/upload/images/20210927/20112053a7bAzZodsb.png

    範例:橢圓形,漸層半徑水平200px,垂直100px

        background:radial-gradient(ellipse at 200px 100px,#FFB76B,#D83900);
    

    https://ithelp.ithome.com.tw/upload/images/20210927/20112053kKFqe03KoH.png

    長度

    可使用關鍵字或是設定尺寸

    • closest-side:接近方塊邊
    • farthest-side:最遠方塊邊
    • closest-corner:最近方塊角
    • farthest-corner:最遠方塊角 ( 預設值 )
        <div class="box closest-side">最近邊</div>
        <div class="box farthest-side">最遠邊</div>
        <div class="box closest-corner">最近角</div>
        <div class="box farthest-corner">最遠角 ( 預設值 )</div>
    
    .box{
      width: 250px;
      height: 100px;
      margin-bottom: 5px;
      padding: 10px;
      color: #fff;
    }
    .closest-side{
      background:radial-gradient(circle closest-side at center,rgba(109,179,242,1),rgba(30,105,222,1));
    }
    .farthest-side{
      background:radial-gradient(circle farthest-side at center,rgba(109,179,242,1),rgba(30,105,222,1));
    }
    .closest-corner{
      background:radial-gradient(circle closest-corner at left,rgba(109,179,242,1),rgba(30,105,222,1));
    }
    .farthest-corner {
      background:radial-gradient(circle farthest-corner at left,rgba(109,179,242,1),rgba(30,105,222,1));
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210927/20112053czmyBfpo1X.jpg

    這是我常用的漸層產生器網站 Colorzilla Gradients ,設定好顏色之後,就可以複製旁邊的語法
    https://ithelp.ithome.com.tw/upload/images/20210927/20112053KEJHGV3J7y.png

    相信你對顏色、背景圖及漸層背景使用有一定的了解,依據網站主視覺顏色傳達形象,來營造出網頁整體的視覺風格。

    參考資料:
    https://www.oxxostudio.tw/articles/202008/css-gradient.html

    ]]>
    sunny 2021-09-27 11:41:35 網頁文字-30天學會HTML+CSS,製作精美網站 https://ithelp.ithome.com.tw/articles/10272379?sc=rss.iron https://ithelp.ithome.com.tw/articles/10272379?sc=rss.iron 網站通常是透過文字的編排,呈現資訊給使用者,標籤用得好,對於SEO排名也會有些幫助,今天要來介紹網頁文字標籤及樣式的使用

    網頁標題

    <h1&g...]]> 網站通常是透過文字的編排,呈現資訊給使用者,標籤用得好,對於SEO排名也會有些幫助,今天要來介紹網頁文字標籤及樣式的使用

    網頁標題

    <h1>~<h6>

    H是「Heading」的縮寫,中文為「標題」。<h1><h2> ... <h6>作為標題、副標題、小標題使用,它們也代表不同的重要程度<h1>為最重要到<h6>最不重要,<h1>字體最大依序到<h6>字體最小。標題有助於搜尋引擎更演算法更加理解文章內容

    但需要注意的是,一個頁面只會有一個<h1>,用於該頁面主要的標題。其他的依序從<h2>使用。

    <h1>我是h1文字</h1>
    <h2>我是h2文字</h2>
    <h3>我是h3文字</h3>
    <h4>我是h4文字</h4>
    <h5>我是h5文字</h5>
    <h6>我是h6文字</h6>
    

    https://ithelp.ithome.com.tw/upload/images/20210926/20112053c690CAXU9C.jpg

    網頁內文

    <p>(段落)

    P是「paragraph」的縮寫,中文為「段落」。
    用來放文字的段落,讓段落與段落間有間隔,有明顯的分段,才不會都擠在一起,不易閱讀。

    <br/>(斷行元素)

    內容換行

    <span>

    用來包文字,方便做CSS樣式設定,沒有語意。

    <strong><b>粗體

    都是粗體,那有什麼差別呢?
    <b>是「bold」縮寫,單純粗體,視覺上好看,沒有特別意義
    <strong>重要的內容

    <i><em>斜體

    <i>是「italic」縮寫,單純斜體,沒有特別意思。
    <em>是「emphasized」縮寫,強調內容

    <p>This is <strong>strong</strong>.</p>
    <p>This is <em>em</em>.</p>
    <p>
      Lorem Ipsum has been the industry's standard dummy text ever since the 1500s<br />
      When an unknown printer took a galley of type and scrambled it to make a type specimen book.
    </p>
    

    https://ithelp.ithome.com.tw/upload/images/20210926/20112053brQpDFYB3z.png

    容易閱讀行數、字數?
    段落文字太多,不易閱讀,看久了會疲乏,因此每個段落控制在3~5行,一行字數控制在35~40個字

    CSS

    文字

    文字在網頁中是重要的元素,利用文字大小、粗細、間距等排版及顏色的搭配,能提高使用者閱讀的舒適度。

    font-size 設定文字大小

    瀏覽器預設字型大小都是16px

    • 相對單位:rem、em、 %
    • 絕對單位:px
    • 關鍵字:xx-small、x-small、small、medium、large、x-large、xx-large,標準大小是medium

    font-family 設定文字字型

    可以設定想要的網頁字體,一次可設定多組不同的字體用逗號「,」隔開,但是要注意的是,使用者電腦需要安裝對應字體才會正常顯示,建議設定字體時設定英文名稱,因某些瀏覽器無法識別中文。套用順序由左至右,電腦中沒有第一順位的字體,就會往第二個字體尋找。

    body{
        font-family: "Microsoft JhengHei", Helvetica, Arial, sans-serif;
    }
    

    網站排版建議不要超過3種字體,會造成視覺上的干擾,導致畫面凌亂的感覺,無法凸顯主題。
    在設計過程中,字型選擇不多或是怕使用者電腦上沒有字體,導致頁面無法正常顯示。
    而「 google fonts」免費字體,解決了多數設計師在網頁上使用特殊字體的困擾了

    font-weight 設定文字粗細

    - normal - 預設值。
    - bold - 粗體字型。
    - bolder - 更粗的字型,不過用起來跟 bold 似乎沒什麼差異。
    - lighter - 細體,不過與 normal 沒什麼差異。
    - 數字 - 可以設定 100、200、300、400、500、600、700、800、900。

    font-style 設定文字樣式

    - normal - 文字正常显示
    - italic - 斜體字顯示
    - oblique - 文字向一邊傾斜(和斜體非常類似,但不太支持)

    font:

    結合上述所描述的font樣式,順序為

    font: font-style font-weight font-size font-family;
    

    line-height 行高

    - 數值(無單位):會依照字型大小比例設定
    - 數值(有單位):以px、em、%...等單位做設定

    line-height:數值
    

    調整上下文字距離,通常網頁行高建議使用1.5~1.9之間。但要注意的是,行高小於文字高度,會導致兩行重疊在一起。

    letter-spacing 文字左右間距

    增加或減小文字之間的間隔。負數為減少整體會比較擁擠,正數則相反。
    - 數值:以px、em、%...等單位做設定

    letter-spacing:數值(允許負數)
    
    .txt1{
      letter-spacing:2px;
    }
    .txt2{
      letter-spacing:-2px; //負數文字會很擁擠
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210926/20112053lnDTgq7KY9.png

    text-align 文字水平對齊

    - left 靠左
    - right 靠右
    - center 置中
    - justify左右對齊
    https://ithelp.ithome.com.tw/upload/images/20210926/20112053GJtMhhsYS0.png

    text-shadow 文字陰影

     text-shadow: 水平偏移 垂直偏移 模糊量 顏色;
    
    .title{
      color: #0d4e82;
      text-shadow: 2px 2px 2px #c9d6e0;
      font-size: 30px;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210926/20112053XGzFx9rbK1.png

    text-decoration

    - none:預設值,無任何效果
    - underline:文字增加底線
    - overline:文字增加上線
    - line-through:文字增加刪除線
    https://ithelp.ithome.com.tw/upload/images/20210926/20112053iT5U6STnA9.png

    text-overflow

    為了讓網頁列表內容看起來整齊,常需要設定字數超過「...」顯示

    <p class="info">
      Lorem Ipsum has been the industry's standard dummy text ever since the 1500s.
    </p>
    
    .info{
    	overflow : hidden;
      text-overflow : ellipsis;
      white-space : nowrap;
      width : 240px;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210926/20112053EHTw8XuMfF.png
    文字超出兩行或者多行顯示省略號

    .info {
        overflow: hidden;
        text-overflow: ellipsis;
        display: -webkit-box;
        -webkit-line-clamp: 2; //超出多行修改數字2就是兩行、3就是三行...以此類推
        -webkit-box-orient: vertical;
    		width : 240px;
    }
    

    -webkit-line-clamp: 2; 超過兩行...
    https://ithelp.ithome.com.tw/upload/images/20210926/20112053OaWqKip0DG.png
    -webkit-line-clamp: 3; 超過三行...
    https://ithelp.ithome.com.tw/upload/images/20210926/20112053nfZFzzPgcS.png

    結論

    確認網站的目的及使用者目標,透過文字的編排傳遞資訊,設定適當的行高、字體大小⋯等美化,讓使用者加深對網站的印象。

    ]]>
    sunny 2021-09-26 09:47:09 網頁命名規則-30天學會HTML+CSS,製作精美網站 https://ithelp.ithome.com.tw/articles/10271686?sc=rss.iron https://ithelp.ithome.com.tw/articles/10271686?sc=rss.iron 在撰寫HTML及CSS時,好的命名要具備可讀性,一眼就能知道這區塊的作用是什麼,也方便日後的維護管理,今天就要來介紹三種CSS的命名規則

    OOCSS(Object Oriente...]]> 在撰寫HTML及CSS時,好的命名要具備可讀性,一眼就能知道這區塊的作用是什麼,也方便日後的維護管理,今天就要來介紹三種CSS的命名規則

    OOCSS(Object Oriented CSS)

    有兩個原則,分別是分離結構與樣式及容器與內容分離

    分離結構與樣式 Separate structure and skin

    像是元素的大小與顏色,bootstrap就是用這個方式寫的,以button為例

    <button type="button" class="btn btn-primary btn-sm">Primary</button>
    <button type="button" class="btn btn-warning btn-lg">Warning</button>
    <button type="button" class="btn btn-success">Success</button>
    
    • class="btn"為預設按鈕樣式
    • btn-primary為主色樣式、btn-success 為成功的樣式、btn-warning 為警告樣式...
      用名稱判斷就可以大約知道這是什麼功能
    • btn-sm為小按鈕、btn-lg為大按鈕

    容器與內容分離 Separate container and content

    容器是包住內容元件的框、內容就是元件,以下面例子來說.news-box就是你的容器,.img-box、.title、.txt...就是你的元件

    <div class="news-box">
        <a class="item">
          <div class="img-box">
            <img src="img.jpg" />
          </div>
          <div class="content">
            <h3 class="title">title</h3>
            <p class="txt">It is a long established fact that a reader will be distracted.</p>
          </div>
        </a>
      </div>
    

    在css都會這樣子寫

    .news-box .item{
      border: 1px solid #efefef;
      display: block;
      width: 300px;
    }
    .news-box .content{
      padding: 10px;
    }
    .news-box .title{
    	font-size:18px;
    	margin: 0;
    }
    .news-box .txt{
    	color:#999;
      margin: 0;
    }
    
    <div class="active-box">
    	<a class="item">
    		<div class="img-box">
    			<img src="img.jpg" />
    		</div>
    		<div class="content">
    			<h3 class="title">title</h3>
    			<p class="txt">content</p>
    		</div>
    	</a>
    </div>
    
    .active-box .item{
      border: 1px solid #efefef;
      display: block;
      width: 300px;
    }
    .active-box .content{
      padding: 10px;
    }
    .active-box .title{
    	font-size:18px;
    	margin: 0;
    }
    .active-box .txt{
    	color:#999;
      margin: 0;
    }
    

    所以我們可以將元件抽離出來,這樣子就可以減少很多重複撰寫的地方了

    .item{
      border: 1px solid #efefef;
      display: block;
      width: 300px;
    }
     .content{
      padding: 10px;
    }
     .title{
    	font-size:18px;
    	margin: 0;
    }
    .txt{
    	color:#999;
      margin: 0;
    }
    

    SMACSS(Scalable & Modular Architecture for CSS)

    除了有類似OOCSS分離的概念外、命名規則,還將CSS分成五種結構,分別為Base、Layout、Module、State、Theme,下面分別介紹五個結構功能

    Base 網頁的基本樣式

    不會使用到任何class與id,像是CSS Reset

    body{ 
    	margin: 0; 
    	padding: 0; 
    }
    a{
    	text-decoration: none;
    }
    img{
    	max-width:100%
    }
    

    Layout 網頁的佈局

    • 主要區塊可以使用id命名像是#header, #menu, #footer...,
    • 次要layout使用class命名
    • 使用 l-layout- 為佈局樣式前綴
    #header{....}
    .l-grid{.....}
    

    Module 模組

    • 可重複使用的元件
    • 會使用class命名
    • 模組名稱與元素名稱中間使用dash分隔,像是.card-item、.card-header、.card-body

    以下是以bootstrap card為例,從名稱也可以知道每個區塊的意義是什麼

    <div class="card" style="width: 18rem;">
      <img src="..." class="card-img-top" alt="...">
      <div class="card-body">
        <h5 class="card-title">Card title</h5>
        <p class="card-text">card's content.</p>
      </div>
    </div>
    

    State 元件狀態

    • 與layout、module搭配
    • 使用者觸發後改變的狀態,可使用is-為狀態前綴,像是.is-active或 tab-item acitve

    以下以bootstrap tabs為例,第一個選起來的tab加入active class名稱

    <nav class="nav nav-pills nav-fill">
      <a class="nav-link active" aria-current="page" href="#">Active</a>
      <a class="nav-link" href="#">Much longer nav link</a>
      <a class="nav-link" href="#">Link</a>
    </nav>
    

    https://ithelp.ithome.com.tw/upload/images/20210925/20112053qrp21Rf43n.png

    Theme

    • 針對整個網站的主視覺變化
    • theme-為主題前綴

    BEM(Block,Element,Modifier)

    Block 區塊

    頁面獨立區塊可重複使用
    下圖在header區塊的menu、logo、search...都是獨立的一個區塊
    https://ithelp.ithome.com.tw/upload/images/20210925/20112053MLqOi7k2E4.png
    那也能重複使用區塊,通常會出現在列表
    https://ithelp.ithome.com.tw/upload/images/20210925/20112053isIcOTNoKH.png

    Element 元素

    區塊內的元件,像是標題、內文、圖片...,用底線_ _(雙底線)來連接區塊及元件

    Modifier 修飾子

    與SMACSS的state類似,用中線 - - (雙中線)來連結元素狀態
    https://ithelp.ithome.com.tw/upload/images/20210925/20112053HtmL2uzRco.png

    <div class="tab-box">
    	<div class="tab-box__item">tab1</div>
    	<div class="tab-box__item">tab2</div>
    	<div class="tab-box__item tab-box--active">tab3</div>
    	<div class="tab-box__item">tab4</div>
    </div>
    

    tab-box區塊裡,有多個tab-box__item元件,tab-box—active選取狀態

    結論

    介紹完OOCSS、SMACSS、BEM三種命名,主要都是為了讓css更簡潔不用重複寫類似的樣式,讓樣式重複使用率提高,除了方便維護外,也能大幅減少CSS檔案大小。

    資料來源:
    https://medium.com/@NYBOSLV/oocss-smacss-bem命名規則-91fb01ce74d5
    https://cythilya.github.io/2018/05/22/bem/
    https://en.bem.info/methodology/key-concepts/

    ]]>
    sunny 2021-09-25 11:14:31 網頁常用單位-30天學會HTML+CSS,製作精美網站 https://ithelp.ithome.com.tw/articles/10271050?sc=rss.iron https://ithelp.ithome.com.tw/articles/10271050?sc=rss.iron 設置CSS樣式大小時,會使用到各種不同的單位,尤其現在都製作響應式網站,用錯單位,就會針對不同尺寸調整大小相當耗時,以下介紹網頁常用各種網頁單位,讓你使用的更加得心應手。

    絕對單...]]> 設置CSS樣式大小時,會使用到各種不同的單位,尤其現在都製作響應式網站,用錯單位,就會針對不同尺寸調整大小相當耗時,以下介紹網頁常用各種網頁單位,讓你使用的更加得心應手。

    絕對單位

    px(像素)

    網頁最常使用的單位,你設定多少就是多少,不會受到其他元素影響。
    假設你設定10px無論你在電腦版或手機版看都會顯示10px。缺點就是缺乏彈性,在響應式網頁,隨著螢幕寬度變化,就要做個別的調整,因此建議用在不用隨裝置調整的地方。

    下面範例你設定字體大小多大就顯示多大,不會受其他因素影響。

    <div style="font-size:20px;">font-size:20px
      <div style="font-size:18px;">font-size:18px
        <div style="font-size:16px;">font-size:16px
          <div style="font-size:15px;">font-size:15px
          </div>
        </div>
      </div>
    </div>
    

    https://ithelp.ithome.com.tw/upload/images/20210924/20112053wCrzsPb0al.png

    相對單位

    相對單位受父元素的影響,大小會隨著當作基準的數值改變。

    em

    父元素的大小為基準單位。
    假設預設文字大小為15px,子元素會乘上父元素的值,導致越內層的文字越來越大。到最後網站就崩壞了QQ

    <div style="font-size:15px;">font-size:15px
      <div style="font-size:1.1em;">font-size:1.1em*15
        <div style="font-size:1.1em;">font-size:1.1em*1.1em*15
          <div style="font-size:1.1em%;">font-size:1.1em*1.1em*1.1em*15
          </div>
        </div>
      </div>
    </div>
    

    https://ithelp.ithome.com.tw/upload/images/20210924/20112053dL0FmhE75C.png

    rem

    rem是「root」+「em」,以根元素當作基礎的單位。
    假設預設文字大小為15px,子元素會乘上根元素的值,只會受根元素大小影響

    <div style="font-size:15px;">font-size:15px
      <div style="font-size:1.1rem;">font-size:1.1rem*15
        <div style="font-size:1.1rem;">font-size:1.1rem*15
          <div style="font-size:1.4rem;">font-size:1.4rem*15
          </div>
        </div>
      </div>
    </div>
    

    https://ithelp.ithome.com.tw/upload/images/20210924/20112053G2t79E9ybb.png

    %(百分比)

    父元素當作基準。
    下面範例預設大小是15px,因為%是繼承父元素,所以就會越來越大,與em顯示方式相似。

    <div style="font-size:15px;">font-size:15px
      <div style="font-size:110%;">font-size:110%*15
        <div style="font-size:110%;">font-size:110%*110%*15
          <div style="font-size:110%;">font-size:110%*110%*110%*15
          </div>
        </div>
      </div>
    </div>
    

    https://ithelp.ithome.com.tw/upload/images/20210924/20112053FXpvAQog15.png

    視窗單位

    以下vw、vh、vmin、vmax四個單位是視窗單位也是相對單位。因為他們是針對視窗大小來決定。1單位類似1%。

    vw / vh

    vw是「viewport width」的縮寫;vh是「viewpoint height」的縮寫。以視窗(Viewport)瀏覽器實際顯示的寬度和高度為基準的比例單位。
    假設瀏覽器寬度為1400px,設定50vw的寬度就是1400的50%,也就是700px,會隨著螢幕寬度而變動,因此很適合用在響應式網頁。

    vmin / vmax

    當前視窗的vw及vh的最小值或最大值。
    假設瀏覽器寬度為1040px,高度為750px,1vmin=750/100px=7.5px,1vmax=1040/100px=10.4px。
    寬度為600px,高度為1000px,1vmin=600/100=6px,1vmax=1000/100=10px

    資料來源:
    https://www.oxxostudio.tw/articles/201809/css-font-size.html

    ]]>
    sunny 2021-09-24 10:06:57 偽類與偽元素-30天學會HTML+CSS,製作精美網站 https://ithelp.ithome.com.tw/articles/10270286?sc=rss.iron https://ithelp.ithome.com.tw/articles/10270286?sc=rss.iron 昨天介紹了各種選擇器,今天介紹偽類及偽元素樣式設定,可以讓畫面有更多的樣式變化,也減少html code的撰寫。讓我來為你一一介紹各種屬性使用方式吧~

    偽類選擇器

    昨天介紹了各種選擇器,今天介紹偽類及偽元素樣式設定,可以讓畫面有更多的樣式變化,也減少html code的撰寫。讓我來為你一一介紹各種屬性使用方式吧~

    偽類選擇器

    偽類選取器是特殊的效果加到特定選擇器上,已經存在的東西,是以單冒號「:」作為開頭,偽類分為狀態偽類、結構性偽類、語言偽類、表單偽類、目標偽類

    狀態偽類

    是標籤常見的

    • :link:未訪問過的連結
    • :visited:已訪問過的連結
    • :hover:滑鼠滑入
    • :focus:選取具有焦點的輸入元素
    • :active:被點擊的那一刻

    結構性偽類

    :root根元素

    在html中根元素是html元素,也可以寫body或html

    /*使用根元素*/
    :root{
        background:#efefef;
    }
    /*使用html*/
    html{
        background:#efefef;
    }
    /*使用body*/
    body{
        background:#efefef;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210923/20112053CgKbQuVRVS.png

    :first-child 選擇第一個子元素

    針對ul元素裡的第一個li元素

    <ul>
        <li>item1</li>
        <li>item2</li>
        <li>item3</li>
        <li>item4</li>
    </ul>
    
    ul li:first-child{
    	background-color:#d1e1ff;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210923/20112053DPOKjv7wf4.png

    :last-child 選擇最後一個子元素

    針對ul元素裡的最後一個li元素

    <ul>
        <li>item1</li>
        <li>item2</li>
        <li>item3</li>
        <li>item4</li>
    </ul>
    
    ul li:last-child{
    	background-color:#d1e1ff;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210923/20112053BL41zQFt42.png

    :nth-child(n)

    用來定位父元素裡的一個或多個特定的子元素。
    n是參數,可以是是整數(1,2,3….)、表達式(2n+2)、關鍵詞(odd, even)。
    通常會用在列表,間隔填色或是item的間距設定

    <ul>
        <li>item1</li>
        <li>item2</li>
        <li>item3</li>
        <li>item4</li>
        <li>item5</li>
        <li>item6</li>
        <li>item7</li>
        <li>item8</li>
        <li>item9</li>
    </ul>
    

    選擇ul元素裡的第七個li元素

    ul li:nth-child(7){
    	background-color:#d1e1ff;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210923/20112053fuQkAKw5Jx.png
    選擇ul元素裡的三倍數

    ul li:nth-child(3n){
    	background-color:#ffe893;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210923/20112053WL57nag0Jc.png
    選擇ul元素裡的奇數

    ul li:nth-child(odd){
    	background-color:#b1ffab;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210923/20112053aGekstXxWf.png
    選擇ul元素裡的偶數

    ul li:nth-child(even){
    	background-color:#b1ffab;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210923/20112053DedbDXeDXr.png

    :nth-last-child(n)

    在父元素裡倒數第n個位置或特定某元素。用法與:nth-child同,方向不同而已。

    :first-of-type

    指定元素的類型的第一個元素。

    <div>
      <p>item1</p>
      <p>item2</p>
      <p>item3</p>
      <p>item4</p>
    </div>
    <ul>
      <li>item1</li>
      <li>item2</li>
      <li>item3</li>
      <li>item4</li>
    </ul>
    
    /*選擇p元素的第一個*/
    p:first-of-type{
    	background:#efefef;
    }
    /*選擇li元素的第一個*/
    li:first-of-type{
    	background:#b1ffab;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210923/20112053k8QouubeaR.png

    • :last-of-type
      指定元素的類型的最後一個元素。與:first-of-type相反。
    <div>
      <p>item1</p>
      <p>item2</p>
      <p>item3</p>
      <p>item4</p>
    </div>
    <ul>
      <li>item1</li>
      <li>item2</li>
      <li>item3</li>
      <li>item4</li>
    </ul>
    
    /*選擇p元素的最後一個*/
    p:last-of-type{
    	background:#efefef;
    }
    /*選擇li元素的最後一個*/
    li:last-of-type{
    	background:#b1ffab;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210923/20112053x27bQSO9cR.png

    :nth-of-type(n)

    指定父元素內中的某種類型的子元素,n可以是整數、關鍵詞、表達式

    <div>
      <p>item1</p>
      <p>item2</p>
      <p>item3</p>
      <p>item4</p>
    </div>
    <ul>
      <li>item1</li>
      <li>item2</li>
      <li>item3</li>
      <li>item4</li>
    </ul>
    
    /*選擇p元素的2的倍數*/
    p:nth-of-type(2n){
    	background:#efefef;
    }
    /*選擇li元素的奇數行*/
    li:nth-of-type(odd){
    	background:#b1ffab;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210923/20112053q69VPjPaO8.png

    :nth-last-of-type(n) 選擇

    在父元素裡倒數第n個位置或特定某類型元素。與:nth-of-type相反。

    :only-child

    在父元素裡只有一個子元素
    範例:box2裡面只有一個span子元素,所以背景色會是綠色

    <div class="box1">
      <p>item</p>
      <span>content</span>
    </div>
    <div class="box2">
      <span>content2</span>
    </div>
    
    span:only-child{
    	background:#b1ffab;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210923/20112053VjknDYygF3.png

    :only-of-type

    在父元素內只有一個類型的子元素
    範例:box2裡面只有一個p元素,所以box2背景色為藍色

    <div class="box1">
      <p>item</p>
      <p>item2</p>
    </div>
    <hr>
    <div class="box2">
      <p>item</p>
    </div>
    
    p:only-of-type{
    	background:#bfdbff;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210923/20112053NuQyXXLg3P.png

    :empty

    用來設定沒有任何元素的內容,連一個空白都不行
    範例:在表格資料沒有內容時

    <table border="1">
      <tr>
        <td>100</td>
        <td>200</td>
        <td>300</td>
      </tr>
      <tr>
        <td>400</td>
        <td></td>
        <td>600</td>
      </tr>
    </table>
    
    table{
    	border-collapse:collapse;
    }
    table td{
    	padding:5px 10px
    }
    table td:empty{
    	background-color:#efefef
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210923/20112053HIM5YC2MaH.png

    語言偽類

    :lang

    選擇指定語言的元素
    範例:lang屬性為"tw"的元素

    <p lang="en">English lang</p>
    <p lang="tw">中文語言區塊</p>
    
    p:lang(tw){ 
    	background:#efefef;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210923/20112053GCfmeTjaEZ.png

    表單偽類

    :checked

    常用在表單的單選與複選,下面以radio自訂樣式

    radio:
    <div class="select-item radio-item">
      <input type="radio" id="man" name="sex" checked>
      <label for="man"></label>男
    </div>
    <div class="select-item radio-item">
      <input type="radio" id="woman" name="sex">
      <label for="woman"></label>女
    </div>
    
    .select-item {
      position: relative;
      display: inline-block;
      margin-right: 5px;
    }
    .select-item input {
      vertical-align: middle;
      width: 14px;
      height: 14px;
      appearance: none;
      -webkit-appearance: none;
      opacity: 0;
      outline: none;
      margin: 0 5px 0 0 ;
    }
    .select-item label {
      position: absolute;
      left: 3px;
      top: 3px;
      z-index: -1;
      width: 14px;
      height: 14px;
      border: 1px solid #409eff;
      border-radius: 50%;
    }
    .select-item input:checked + label {
      background-color: #409eff;
    }
    .select-item input[type="radio"]:checked + label::after {
      content: "";
      position: absolute;
      left: calc(50% - 4px);
      top: calc(50% - 4px);
      width: 8px;
      height: 8px;
      background-color: #fff;
      border-radius: 50%;
    }
    

    :disabled/:enabled

    不可用/可用,常用在輸入框

     enabled: <input type="text"  /><br>
     disabled: <input type="text" disabled="disabled"  />
    
    input[type="text"]:enabled{
    	background:#fff;
    	border:1px solid #d4d9de;
    }
    input[type="text"]:disabled{
    	background:#d4d9de;
        border:1px solid #d4d9de;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210923/201120539CYGABZbAL.png

    否定偽類

    :not:某元素之外的元素,範例樣式指的是.not區塊內不是p的元素

    <div class="not">
        <div>div</div>
        <p>paragraph</p>
        <p>paragraph</p>
    </div>
    
    .not div:not(p) {
        background-color: #efefef;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210923/20112053jRJAdZAeSu.png

    偽元素選擇器

    偽元素不是真正的網頁元素,是透過CSS樣式創造新的假元素,以兩個冒號「::」作為開頭,偽元素有

    ::before

    元素之前加入內容,有content屬性,才會顯示在畫面上

    <span>內容</span>
    
    ```css
    div::before{
        content:"我是 before,";
        color:blue;
    }
    ```
    

    https://ithelp.ithome.com.tw/upload/images/20210923/20112053D19vWWts2M.png

    ::after

    元素之後加入內容,有content屬性,才會顯示在畫面上

    <span>內容</span>
    
    ```css
    div::after{
        content:",我是 after。";
        color:blue;
    }
    ```
    

    https://ithelp.ithome.com.tw/upload/images/20210923/20112053EZZ1HJ0Frr.png

    ::first-line:

    p元素的第一行

    ```css
    p::first-line{
      color:green;
    }
    ```
    

    https://ithelp.ithome.com.tw/upload/images/20210923/20112053RBaZiDty0U.png

    ::first-letter:

    元素的第一個字

    p::first-letter{
      font-weight:bold;
      font-size:38px;
      color:green;
      margin-right:5px
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210923/20112053wQW9tfLrgs.png

    ::selection

    選取文字反白後

    p::selection{
      color:#fff;
      background:#ccc;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210923/20112053ZBg3oK41zd.png

    偽元素運用

    偽元素內放字串

    <div class="tips">提示訊息!</div>
    
    .tips::before {
      content: 'tips:';
      color: red;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210923/20112053UFURQW4PCx.png

    偽元素內放圖片

    • url
      範例:是將li前面放置小圖
    <ul>
        <li>item1</li>
        <li>item2</li>
        <li>item3</li>
    </ul>
    
    ul{
    	list-style:none;
    }
    li::before{
    	content:url(img.gif);
        display:inline-block;
        margin-right:5px;
    }
    
    • 背景圖
      範例:在li前面放置小圖,以背景圖方式設定
    ul{
    	list-style:none;
    }
    li::before{
    	content:"";
        display:inline-block;
        margin-right:5px;
        background-image:url(img.gif);
        width:16px;
        height:16px;
        
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210923/201120534iwa1quMG4.png

    偽元素內放attr

    <div id="checked" class="text">選擇div的id:</div>
    
    .text::after {
      content: '#' attr(id);
      color: red;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210923/20112053R3JDMdQmRI.png

    ]]>
    sunny 2021-09-23 10:13:43
    網頁選擇器-30天學會HTML+CSS,製作精美網站 https://ithelp.ithome.com.tw/articles/10269585?sc=rss.iron https://ithelp.ithome.com.tw/articles/10269585?sc=rss.iron 在寫網頁樣式時,最重要的就是選擇器的使用,寫得好容易理解,修改沒煩惱,也可以讓網頁快速呈現效果。以下會介紹css有哪些選擇器及使用方法

    通用選取器

    樣式套用在所有...]]> 在寫網頁樣式時,最重要的就是選擇器的使用,寫得好容易理解,修改沒煩惱,也可以讓網頁快速呈現效果。以下會介紹css有哪些選擇器及使用方法

    通用選取器

    樣式套用在所有元素上

    *{...}
    

    範例:將所有元素的文字顏色套用藍色

    <h1>title</h1>
    <h2>sub title</h2>
    <p>content</p>
    
    *{
    	color:blue;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210922/201120531AjASQ1TXT.png

    標籤選擇器

    使用html標籤做選擇器,將檔案裡面有使用到的標籤直接修改樣式,適合用來定義全站通用的樣式。通常都會建議設定樣式時給予class名稱。

    element{...}
    

    範例:設定<ul>不要項目標籤,當所有頁面裡有使用到<ul>就都不會有項目符號,除非另外各別做設定,範例中我將一個<ul>class名稱設定為"hastype",並給予它disc的樣式。

    <ul>
    	<li>item1</li>
    	<li>item2</li>
    	<li>item3</li>
    </ul>
    <ul>
    	<li>item1</li>
    	<li>item2</li>
    	<li>item3</li>
    </ul>
    <ul class="hastype">
    	<li>item1</li>
    	<li>item2</li>
    	<li>item3</li>
    </ul>
    
    ul{
    	list-style-type: none;
    }
    .hastype{
    	list-style-type: disc;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210922/20112053n8ExhQLM9i.png

    class選擇器

    在網頁中,會有兩個地方以上使用到相同的樣式時,就可以使用class選擇器。

    class選擇器會使用「.」加上名稱,通常也會建議html標籤給有意義的名稱,避免針對標籤做樣式修改時,只要有使用到的地方就會被套用樣式。

    .classname{....}
    

    範例:我要設定class="box"裡面的<p>標籤字體大小為14px、顏色為#999,但如果我指針對<p>標籤做設定,所有使用到<p>標籤的樣式都會被套用

    <div class="box">
    	<h2 class="title">title</h2>
    	<p>content2</p>
    </div>
    <ul>
    	<li><p>item1</p></li>
    	<li><p>item2</p></li>
    	<li><p>item3</p></li>
    </ul>
    
    .title{
    	margin-bottom:5px;
    	font-size:18px;
    }
    p{
    	font-size:14px;
    	color:#999;
    	margin: 0;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210922/20112053xUv0GVkVfP.png
    所以要將樣式改為 .box p{...},box名稱區塊下層的<p>標籤

    .box > p{
    	font-size:14px;
    	color:#999;
    	margin: 0;
    }
    

    id選擇器

    在一個頁面裡,id名稱不可以重複,是唯一值,就像身分證一樣不會重複。id選擇器使用「#」加上名稱,比較常用在javascript動態網頁來控制html組件,用法與class選擇器相同,只是「.」改為「#」。

    #idname{....}
    

    群組選擇器

    同時設定多個選取器樣式,並用「,」逗號隔開,這樣可以避免重複寫相同的css樣式

    element,element{...}
    

    範例:將.box head及.list li背景色設為#efefef

    <div class="box">
    	<div class="head">head</div>
    	<div class="body">
    		<p>content</p>
    	</div>
    </div>
    
    <ul class="list">
    	<li>item1</li>
    	<li>item2</li>
    	<li>item3</li>
    </ul>
    
    .box .head, .list li{
    	background-color:#efefef;
    }
    p{
    	margin:0;
    }
    .list li{
    	margin-bottom:5px;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210922/201120531IGQXLxxZi.png

    組合選擇器

    後代選擇器

    E F,選取E元素內的F元素,以「半形空格」隔開兩個元素

    E F{...}
    

    範例:選取元素內的元素

    <ul class="list">
    	<li>item1</li>
    	<li>item2</li>
    	<li>item3</li>
    </ul>
    
    .list li{
    	color: #333;
    }
    

    子選擇器( > )

    與後代選擇器不同,子選擇器只選取向下一層的子元素,選取E元素下一層的F元素,以「>」隔開兩個元素

    E > F{...}
    

    範例:將box名稱的下一層元素文字設定為藍色

    <div class="box">
    	<p>content</p>
    	<ul class="list">
    		<li><p>item1</p></li>
    		<li><p>item2</p></li>
    		<li><p>item3</p></li>
    	</ul>
    </div>
    
    .box > p{
    		color:blue;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210922/20112053JdL6WvAL9U.png
    如果只針對box名稱內的元素,所有使用元素的都會變藍色文字

    <div class="box">
    	<p>content</p>
    	<ul class="list">
    		<li><p>item1</p></li>
    		<li><p>item2</p></li>
    		<li><p>item3</p></li>
    	</ul>
    </div>
    ```css
    .box  p{
        color:blue;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210922/20112053HSEdO1ETKn.png

    相鄰選擇器( + )

    只會選取E元素相鄰的第一個F元素

    E + F{....}
    

    我自己比較常用到的地方是做選單的樣式,設定元素與元素中間有線條做分隔

    <nav class="navbar-box">
    		<a href="#">menu</a>
    		<a href="#">menu</a>
    		<a href="#">menu</a>
    		<a href="#">menu</a>
    		<a href="#">menu</a>
    		<a href="#">menu</a>
    </nav>
    
    .navbar-box{
    	display:inline-block;
    }
    .navbar-box a{
    	color:#333;
    	text-decoration: none;
    	padding:0 10px;
    }
    .navbar-box a+a{
    	border-left: 1px solid #ccc;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210922/201120534bBxZpLymY.png

    間接選擇器( ~ )

    設置E元素之後的F元素

    E ~ F{...}
    

    範例:將red-after名稱之後的都設為紅色文字

    <ul>
    	<li>item1</li>
    	<li>item2</li>
    	<li class="red-after">item3</li>
    	<li>item4</li>
    	<li>item5</li>
    </ul>
    
    .red-after ~ li{
    	color: red;
    }
    

    https://ithelp.ithome.com.tw/upload/images/20210922/20112053HqHlLu9Vvr.png
    參考資料:
    https://medium.com/ui-ux練功坊/css選擇器介紹-1-ec19bc5b33a
    https://injerry.pixnet.net/blog/post/38847966

    ]]> sunny 2021-09-22 09:28:28
    語意標籤-30天學會HTML+CSS,製作精美網站 https://ithelp.ithome.com.tw/articles/10268897?sc=rss.iron https://ithelp.ithome.com.tw/articles/10268897?sc=rss.iron 在HTML5中新增了語意標籤,取代以前只能用<div>劃分區塊,可以更清楚知道網頁區塊設計目的,也有有利SEO的搜尋。下圖是網站標籤的結構,依序跟大家說明每...]]> 在HTML5中新增了語意標籤,取代以前只能用<div>劃分區塊,可以更清楚知道網頁區塊設計目的,也有有利SEO的搜尋。下圖是網站標籤的結構,依序跟大家說明每個標籤的意義
    https://ithelp.ithome.com.tw/upload/images/20210921/201120531lmsb2etmf.png

    <header>網頁頁首

    通常會放置logo、選單、搜尋框、註冊按鈕等元素。下面用三個網站不同排版的範例:
    https://ithelp.ithome.com.tw/upload/images/20210921/20112053juVUuIGcVh.png

    圖片來源(https://syoss-selfcoloring.jp/ )

    https://ithelp.ithome.com.tw/upload/images/20210921/201120533VA6hSUngY.png

    圖片來源(https://fabric-tokyo.com/ )

    https://ithelp.ithome.com.tw/upload/images/20210921/20112053jk7d1bwP2G.png

    圖片來源(https://www.lacoste.jp/ )

    <nav>導覽列選單

    用來連結到網站其他的頁面。通常會放在標籤內,或是獨立一區塊。以下兩個範例都是選單獨立成一塊
    https://ithelp.ithome.com.tw/upload/images/20210921/201120536ZnDPR6xw0.png

    圖片來源(https://www.kyoto-tower.jp/)

    https://ithelp.ithome.com.tw/upload/images/20210921/20112053QGIA1yOGd5.png

    圖片來源(https://otent-nankai.jp/)

    <main>網頁主要的內容

    這頁面的主要資訊內容,也就是除了<header><nav><aside><footer>區塊以外的內容,且一個網頁只能有一個<main>標籤

    <aside>非主要的內容

    與主要內容無關的額外資訊,像是側邊欄、廣告、推薦文章....。範例旁邊是與內容無關的資訊
    https://ithelp.ithome.com.tw/upload/images/20210921/20112053FH3qkYvVct.png

    圖片來源(https://digitalist-web.jp/article/business/rKzdJ)

    <article>文章

    獨立的區塊包含一篇完整的內容,通常會有一個標題,像是新聞、部落格網站的文章

    <section>群組或區塊

    製作一個區塊的內容,用於章節段落的區分,會有標題及內容。
    https://ithelp.ithome.com.tw/upload/images/20210921/201120531HNO3zCg6t.png

    圖片來源(https://digitalist-web.jp/)

    <article>不同的是,<section>不一定是獨立內容,但一定會有標題。

    <footer>網頁頁尾

    通常會放置版權聲明、相關連結、聯絡方式。以下三是三個不同footer排版的範例
    https://ithelp.ithome.com.tw/upload/images/20210921/201120536I14FseUNx.png

    圖片來源(https://digitalist-web.jp/)

    https://ithelp.ithome.com.tw/upload/images/20210921/20112053m2c5xMzoEF.png

    圖片來源(https://pu-ca.jp/)

    https://ithelp.ithome.com.tw/upload/images/20210921/20112053TqGMFJj6Rw.png

    圖片來源(https://www.mag2.co.jp/)

    <div>無特定意義的區塊

    沒有任何意義的區塊,當想要組成群組,但不知道要放哪個區塊

    介紹完每個標籤的意義後,以下用https://www.teinei.co.jp/ 網站來做整個網站的區塊切割範例說明
    https://ithelp.ithome.com.tw/upload/images/20210921/20112053acaAqbsOrG.jpg

    ]]>
    sunny 2021-09-21 09:49:11
    認識網頁元素 HTML、CSS https://ithelp.ithome.com.tw/articles/10268240?sc=rss.iron https://ithelp.ithome.com.tw/articles/10268240?sc=rss.iron 看完了前幾天製作網頁,所需要的素材、使用編輯器及製作網站的流程後後,今天要來介紹HTML、CSS的基本結構,跨出製作網站的第一步了

    HTML

    HTML是什麼?<...]]> 看完了前幾天製作網頁,所需要的素材、使用編輯器及製作網站的流程後後,今天要來介紹HTML、CSS的基本結構,跨出製作網站的第一步了

    HTML

    HTML是什麼?

    HTML是Hypertext Markup Language的縮寫,中文全名為「超文字標示語言」。HTML是告訴瀏覽器顯示什麼內容,像是標題、內容、表格、表單、圖片、文字、連結等。

    HTML組成

    https://ithelp.ithome.com.tw/upload/images/20210920/20112053Na2oxbRZ9w.png
    每個標籤都會有開始與結束,在標籤中間可以放置自己要呈現的內容,可利用屬性定義的名稱給予樣式。每個標籤也會對應不同的屬性及值。
    但需要注意的是每個頁面,id名稱是唯一值,不可以重複,就像身分證號碼一樣,一個號碼對應一個人的身份。class可以重複的被使用。且id與class的名稱大小寫是不同的,不能互相使用。EX:header、Header這兩個代表不一樣的class名稱。

    HTML架構

    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8">
        <title>My test page</title>
      </head>
      <body>
        <img src="images/firefox-icon.png" alt="My test image">
      </body>
    </html>
    

    <!doctype html>

    DOCTYPE 即是Document type(簡稱為DTDs),中文是「檔案類型」。說明網頁是用HTML哪個版本,像是HTML 4.01、XHTML 1.0、XHTML 1.1、HTML 5等版本。HTML5為網頁的最新版本,幾乎所有瀏覽器、手機都已經有支援。

    <html></html>

    識別是一個html文件

    <head>

    顯示網頁的資訊,包含標題、頁面說明、外部連結等。但不會顯示在瀏覽器畫面中。

    <meta>

    • <meta charter=UTF-8>
      meta charter是用來指定網頁是什麼編碼。大多數的網頁編碼為「UTF-8」,如果網頁沒有指定正確的編碼時,文字會變成亂碼。
    • <meta name="description" content="....">
      description是用來描述你的網頁內容,只有在搜尋結果中,才能看到文字
      以apple官網為例,他在meta的描述裡面所寫的文字,會顯示在搜尋的描述上
      https://ithelp.ithome.com.tw/upload/images/20210920/20112053cd5YoTDNGb.png
      https://ithelp.ithome.com.tw/upload/images/20210920/20112053PMQMQfOqzy.png
    • <meta name="keywords" content="....">
      keywords是用來描述你的網頁內容有哪些關鍵字詞
    • <meta name="viewport" content="width=device-width, initial-scale=1.0">
      viewport是用來描述行動版網頁的 viewport 資訊

    <title>

    設定網頁標題,會顯示在瀏覽器的標籤上、加入我的最愛的標題、網頁搜尋結果

    <body>

    放置網頁在瀏覽器上要呈現的內容

    在html裡面標籤沒有大小寫區別,但有的版本必須要小寫,因此建議統一以小寫為主。

    註解 <!-- 和 -->

    單行與多行註解都是使用<!-- 和 -→

    <!--
    	多行註解
    	多行註解
    	多行註解
    -->
    <!--單行註解-->
    

    CSS

    CSS是什麼?

    CSS是Cascading style Sheets的縮寫,中文全名為「層疊樣式表單」。是用來美化HTML外觀的語言。像是文字顏色、大小、位置、邊框等。

    如何在HTML中使用CSS

    行內樣式 Inline Styles

    直接在HTML Tag上寫style樣式,

    <p style="color:#f00;font-size:18px;">我是內容</p>
    

    內嵌樣式 Embeded Styles

    在HTML 的標籤裡面使用style

    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
      <style>
        .text{
          color:#f00;
          font-size:18px;
        }
      </style>
    </head>
    <body>
      <p class="text">我是內容</p>
    </body>
    

    外部樣式 External Styesheets

    在HTML 的<head>標籤裡用link方式引入CSS檔案

    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
      <link rel="stylesheet" href="css/style.css">
    </head>
    

    引入方式有三種方法,行內樣式及嵌入樣式不易管理,且行內優先順序也會比較高,想部分調整可以使用此方法.但建議使用外部樣式方法,方便管理及維護

    CSS組成

    CSS是由選擇器(selector)、屬性(property)和值(value)組成
    https://ithelp.ithome.com.tw/upload/images/20210920/20112053R4EshM2VYs.png

    • 選擇器:設定要改變哪一個元素外觀
    • 屬性:要改變什麼
    • 值 :如何改變
      以範例來說,要改變「.text這個class名稱」的外觀,要改變他的「顏色」,要改成「紅色」
      要設定多個選取器時,要用逗號(,)隔開;屬性與值之間用冒號(:)隔開;同時設定多個屬性與值時,要用分號(;)隔開,最後用大括號{ }括起來。

    這邊要注意的是,設定選取器樣式時,建議給他們一個class或id名稱,不要直接設定html標籤,因為在HTML裡面使用到所設定的標籤,樣式就直接被套用,修改也會變得複雜。

    CSS Reset 與 CSS normalize

    為什麼會有CSS Reset及CSS normalize呢?

    因多數瀏覽器使用的 HTML都會有自己的預設樣式,導致在每個瀏覽器上看都會有一點差異。所以為了讓每個瀏覽器樣式統一,才會有Reset及normalize的需求。

    CSS Reset 與 CSS normalize該到底該用哪一個呢?

    • CSS Reset

      • 將瀏覽器默認樣式完全清空
      • 沒有彈性,需要什麼樣式要在自己做設定
      • 常見的CSS Reset:Eric Meyer Reset CSSHTML5 Reset Stylesheet
    • CSS normalize

      • 只會刪除瀏覽器的不一致,保留瀏覽器默認樣式
      • code會有大量註解,讓你知道每個樣式處理什麼問題
      • normalize.css 被使用在Bootstrap、Tailwind、Foundation等framework
        不論用哪一套都有人使用,針對你需求去做選擇。

    前綴詞使用

    撰寫CSS時,都會遇到不同瀏覽器之間的相容性問題,為了確保每個瀏覽器都支援所寫的CSS ,必須依照不同的瀏覽器加上專屬於它們的前綴,以確保CSS可以被正常執行。

    • webkit-:chrome、Safari
    • moz-:Firefox
    • -o- :Opera
    • -ms-: Internet Explorer、Microsoft Edge

    不確定CSS支援程度可以到 Can I sue 查詢

    結論

    想像一個網頁就像一間房子,HTML就像是未裝修的房子,然後CSS是鋪上磁磚、油漆、將傢俱擺放到適合的位置並裝飾美美的,讓整體看起來舒適。
    以上是HTML及CSS的介紹,相信你對HTML及CSS有基本的認識了

    ]]>
    sunny 2021-09-20 11:21:33 改造你的VSCode,大幅提升你的Coding效率 https://ithelp.ithome.com.tw/articles/10267465?sc=rss.iron https://ithelp.ithome.com.tw/articles/10267465?sc=rss.iron 工欲善其事,必先利其器,插件是Coding效率提升的利器

    今天要來介紹的主角是Visual Studio Code(簡稱VSCode),它是一款微...]]> 工欲善其事,必先利其器,插件是Coding效率提升的利器

    今天要來介紹的主角是Visual Studio Code(簡稱VSCode),它是一款微軟開發的原始碼編輯器,幾乎支援了所有的程式語言,為開發者提供好用的工具來提升效率,撰寫高質量的程式碼,那就讓我來推薦給大家自己使用過的好用工具吧~

    環境設定

    在終端機使用指令開啟VS Code

    按下 command+Shift+P 來呼叫 命令選擇區,輸入shell command,選擇「Shell Command: Install code command in PATH」
    https://ithelp.ithome.com.tw/upload/images/20210919/20112053l55ePJs75b.png
    安裝完重啟後,在要打開的資料夾右鍵,開啟終端機,並輸入code .,就會幫你開啟專案在 VS Code 上囉~
    p.s因為我是裝iTerm2所以設定終端機為iTerm2
    https://ithelp.ithome.com.tw/upload/images/20210919/20112053iv5KFNd84t.png
    https://ithelp.ithome.com.tw/upload/images/20210919/20112053sHjqIuYFUH.png

    教你如何設定在Finder目前資料夾開啟終端機

    1.開啟「系統偏好設定」
    2.點擊「鍵盤」
    https://ithelp.ithome.com.tw/upload/images/20210919/20112053yIBDavxadC.png
    3.開啟後選擇上方「快速鍵」→左側「服務」→找到檔案與資料夾勾選「新增位於檔案夾位置的終端機視窗」(系統預設)或是「New iTerm2 Window Here」(自行安裝)
    https://ithelp.ithome.com.tw/upload/images/20210919/20112053EOOloekX8M.png
    4.之後再到你要開啟的資料夾點選右鍵,再輸入「code .」就可以開啟囉~
    https://ithelp.ithome.com.tw/upload/images/20210919/20112053cUPS4KJ0NE.png
    https://ithelp.ithome.com.tw/upload/images/20210919/20112053Aqc5lZmEcu.png

    外觀

    設定完之後我們就要來講美化VSCode的介面,讓你在操作上能夠更方便

    One Dark Pro

    自訂VS Code外觀樣式
    先安裝好One Dark Pro主題後,點擊Preferences>Color Theme
    https://ithelp.ithome.com.tw/upload/images/20210919/20112053UcogwB6Lbu.png
    在選擇剛剛安裝的One Dark Pro主題
    https://ithelp.ithome.com.tw/upload/images/20210919/20112053g8gw9mPGgD.png

    vscode-icons

    vscode本身沒有圖示,安裝後可以幫你把檔案與資料夾icon美化
    使用前:
    https://ithelp.ithome.com.tw/upload/images/20210919/20112053QxEw5dvv1C.png
    使用後:
    https://ithelp.ithome.com.tw/upload/images/20210919/20112053wQSTaUzH1z.png

    好用套件

    TODO Highlight

    當你寫程式碼過程中,突然想到有地方需要補充,但又不想停下手邊的工作,打斷思路,這功能超好用,只要使用TODO/FIXME關鍵字,就會把註解高亮起來
    https://ithelp.ithome.com.tw/upload/images/20210919/201120536HXodTSKB3.png
    但是檔案很多就會散落在各個檔案裡面,這時候還可以搭配Todo Tree,會統整整個專案,依照檔案結構來產生樹狀的列表,相當方便
    https://ithelp.ithome.com.tw/upload/images/20210919/20112053VE4aj9lCZn.png

    AutoFileName

    提示檔案位置。有時候我們打相對位置,不確定名稱或路徑時,都需要打開資料夾去確認,但是用了這套件後,就會出現提示。
    https://ithelp.ithome.com.tw/upload/images/20210919/20112053fM4IFjZ9NZ.png

    Auto Close Tag

    當你打html tag標籤時,會幫你把右括號或結束標籤補上
    https://raw.githubusercontent.com/formulahendry/vscode-auto-close-tag/0c784ff156da350cce8374a7f04759cab7e2aaff/images/usage.gif
    圖片來源

    Auto Rename Tag

    修改html tag時,會自動修改對應的標籤
    https://github.com/formulahendry/vscode-auto-rename-tag/raw/HEAD/images/usage.gif
    圖片來源

    Bracket Pair Colorizer

    當程式碼多的時候,會變得很難閱讀,甚至有時候還會誤刪或漏掉,導致要找很久,使用這個套件,就會自動將成對的括弧加上顏色,無論是在html、css、js點選括號時,會將對應的括號選起來,閱讀程式碼很方便。
    https://ithelp.ithome.com.tw/upload/images/20210919/201120535pmzeSWukz.png

    indent-rainbow

    將程式碼縮排的部分增加顏色,方便閱讀程式碼
    https://ithelp.ithome.com.tw/upload/images/20210919/20112053MrlgSI04I2.png

    Sass/SCSS 相關

    Live Sass Compile

    即時編譯SASS/SCSS成CSS,不需要使用https://ithelp.ithome.com.tw/upload/images/20210919/20112053YvJa90vKFN.png官方直譯器與終端機,也可以自訂輸出的檔案位置,超級方便~
    https://ithelp.ithome.com.tw/upload/images/20210919/20112053DOksoPmflG.png
    檔案>喜好設定>設定,搜尋「livesass」就會出現安裝Live Sass Compile的設定
    https://ithelp.ithome.com.tw/upload/images/20210919/20112053l14Z6F45LO.png
    在setting.json裡面輸入你的設定,就完成囉~以下是我的設定
    https://ithelp.ithome.com.tw/upload/images/20210919/20112053XiWc95LfPn.png
    format的設定屬性有四種:

    • nested (預設的樣式) : 巢狀顯示
    • expanded : 不要巢狀
    • compact : 簡潔樣式,縮進成一行
    • compressed :壓縮模式

    Live Server

    使用虛擬路由執行網頁,存檔時候,會自動在瀏覽器新開網頁,顯示最新存檔後的畫面
    按下右下角「Go Live」
    https://ithelp.ithome.com.tw/upload/images/20210919/201120536OQUkdwyjI.png
    點擊啟動後,網址會是「 http://127.0.0.1:5501/ 」,當你在編輯器修改後,畫面就會立即改變
    https://ithelp.ithome.com.tw/upload/images/20210919/20112053XmrVgHnkLp.png

    版本控制

    Git History

    以GUI的格式顯示Git的commit資訊
    https://ithelp.ithome.com.tw/upload/images/20210919/20112053EmQBtYoOGP.png
    可以查看提交紀錄,有更動左方就會出現提示,還能直接同步提交給遠程版本庫
    https://ithelp.ithome.com.tw/upload/images/20210919/20112053JbNchxIbH3.png

    GitLens

    https://ithelp.ithome.com.tw/upload/images/20210919/20112053H0O4yVjINt.png
    在文件中點擊該行,會出現提交訊息、誰提交、時間
    https://ithelp.ithome.com.tw/upload/images/20210919/20112053J0fEtnL97x.png
    點擊右上紅框按鈕,還以可與內容做比對
    https://ithelp.ithome.com.tw/upload/images/20210919/201120531yX7Q1R5vn.png

    以上是我使用的工具,推薦給大家!

    ]]> sunny 2021-09-19 10:42:02
    找尋你的設計靈感、素材及好工具 https://ithelp.ithome.com.tw/articles/10266839?sc=rss.iron https://ithelp.ithome.com.tw/articles/10266839?sc=rss.iron 製作網站前,通常需要找尋相關設計靈感,有時候想破頭就是沒想法,素材對網頁內容來說很重要,好不容易找到了不錯的素材,大部分都是有著作權,不能直接使用,以下是我常逛或是設計師常用來找尋靈感及找素材的...]]> 製作網站前,通常需要找尋相關設計靈感,有時候想破頭就是沒想法,素材對網頁內容來說很重要,好不容易找到了不錯的素材,大部分都是有著作權,不能直接使用,以下是我常逛或是設計師常用來找尋靈感及找素材的網站
    https://ithelp.ithome.com.tw/upload/images/20210918/20112053GFvGoXDml8.png

    如何找素材?

    做網站需要使用素材及圖片,讓網站看起來更生動,吸引使用者的眼球
    使用CC0可商用圖片無版權圖片,就不用擔心會有版權問題了
    但在下載使用前,還是要再確認一下使用規則,以免觸法唷~

    CC0(Creative Commons Zero)授權是什麼?

    可用於私人或商業性質,使用者可以自由地修改創作衍生作品的權利,不需要特別註明素材出處來源。下面會分享圖庫及素材的網址

    圖庫

    素材

    ICON

    如何找尋靈感

    設計參考

    • Pinterest:找靈感網站,有網頁、平面設計等資源十分豐富
      https://ithelp.ithome.com.tw/upload/images/20210918/20112053YF9v2ot29S.png
    • Behance
    • dribbble
    • collectUI:有多種類型的UI設計可以參考,像是登入、表單、個人簡介等

    網站參考

    可以依照關鍵字、分類、顏色等搜尋需要的版型

    模板參考

    哪裡有好用工具?

    配色網站

    • Color Hunt:可以透過搜尋欄搜尋合適的配色
      https://ithelp.ithome.com.tw/upload/images/20210918/20112053BtRVAzhuW4.png
    • ColorSpace:設定一個主色,會有多種不同組合的配色參考
      https://ithelp.ithome.com.tw/upload/images/20210918/20112053oyVQS2Z89U.png
    • Coolors :按下鍵盤的空白鍵,會隨機提供五種顏色的配色,可以鎖定主要顏色,更換其他的顏色組合
      https://ithelp.ithome.com.tw/upload/images/20210918/20112053no8dpjHQfT.png

    漸層產生器

    • Colorzilla Gradients:可以在這裡設置好漸層色,在複製CSS到你的CSS檔案就可以了,超方便
      https://ithelp.ithome.com.tw/upload/images/20210918/20112053rtDmGKZWK4.png

    漸層配色參考

    製作Favicon icon

    三角形產生器

    Font Icon產生器

    • IcoMoon:除了可以在自行挑選需要的icon圖示之外,還可以匯入自己製作的svg icon圖
    • iconfont+:這個網站最大優點就是可以使用彩色的icon圖

    假字產生器

    圖片產生器

    線上生成動畫

    • Animista:提供數十種特效像是淡入、淡出、旋轉、消失等,存CSS產生的動畫

    看完這麼多厲害的網站及資源,趕快存到我的最愛裡,以後就不怕沒靈感了,以上是我常用的資源,如果你也有推薦的網站,也歡迎你告訴我唷~

    ]]>
    sunny 2021-09-18 15:10:19
    如何製作一個精美的網站 https://ithelp.ithome.com.tw/articles/10265822?sc=rss.iron https://ithelp.ithome.com.tw/articles/10265822?sc=rss.iron 什麼是好的網站設計?

    使用者使用網站時是否容易操作及有良好的動線,避免過多不必要的元素,讓使用者快速找到資訊。避免過多的動畫或圖片,導致載入速度變慢,間接影響到瀏覽品質。以下會...]]> 什麼是好的網站設計?

    使用者使用網站時是否容易操作及有良好的動線,避免過多不必要的元素,讓使用者快速找到資訊。避免過多的動畫或圖片,導致載入速度變慢,間接影響到瀏覽品質。以下會介紹:

    • 網頁的瀏覽動線
    • 網站效能
    • 配色

    網頁的瀏覽動線

    無論是什麼排版,都是從畫面左上方開始瀏覽網頁,所以左上方就要放重要的資訊,不太重要的放在右下或下方。因為內容多,使用者會快速進行掃描以便更快找到資訊,且內容多閱讀會疲乏,很少會認真閱讀段落內的內容,以下三種網站動線設計技巧,讓你在規劃的時候給予使用者最棒的瀏覽體驗

    古騰堡排版

    瀏覽方式為左上到右下,像報紙或雜誌一樣,一行一行的往下閱讀
    https://ithelp.ithome.com.tw/upload/images/20210917/201120535uRlGp8fvl.png

    Z 型排版

    瀏覽方式為從左到右,從上到下的瀏覽,形成Z字型瀏覽方式。使用者會用Z字型的方式,去掃描自己有興趣或需要的資訊去閱讀。
    https://ithelp.ithome.com.tw/upload/images/20210917/20112053XbqUJcm00l.jpg
    圖片來源:https://www.wow-world.co.jp/

    F 型排

    目前最廣泛作使用網頁佈局判定的依據,根據使用者瀏覽動線,用不同顏色標示使用者感興趣的內容。以下是NN/g 的眼動儀研究圖
    https://ithelp.ithome.com.tw/upload/images/20210917/20112053wMLFTFZcMb.png
    圖片來源

    配色

    選擇顏色時可根據主色、次要色、重點色做選擇,控制在四色或以下
    主色盡量以品牌色為主,讓整體頁面色彩協調,突出重點,這樣也能加深使用者對企業的品牌印象和識別度。
    以FANCL網站範例來說,他的LOGO是藍色,所以他全站的配色會以藍色的為主色,增加品牌的識別度
    https://ithelp.ithome.com.tw/upload/images/20210917/20112053uO7PJ9cJJ3.png
    圖片來源:https://www.fancl.jp/index.html
    配色靈感可以參考以下網站:

    網站效能

    網頁載入的快慢,不但影響了使用者停留時間,也會影響SEO的排名、曝光的機會,錯失很多客戶。可以參考以下四種方法,來提升網站速度

    ㄧ、調整圖片大小或壓縮

    可以使用 TinyPNG 來壓縮你的圖片
    https://ithelp.ithome.com.tw/upload/images/20210918/20112053lEBrpryM4T.png

    二、延遲載入

    圖片多的時候,網站開啟速度會比較慢,使用Lazy Load可以讓使用者剛好滑到圖片的時候,才載入圖片

    三、減少網站請求、移除沒用到的檔案

    四、使用快取

    網站用到的的CSS、JS、圖片等資料不會常更新,下次再瀏覽時可以不用重新下載取得檔案。

    Google有提供的網頁效能工具PageSpeed Insights(Google網頁測速工具),來為你的網站做評分,做改善參考。
    https://ithelp.ithome.com.tw/upload/images/20210918/20112053NjxQDWlbRk.png

    根據網站製作目的與用途可分為下列四種

    企業/形象網站

    通常用來發布公司簡介、產品資訊、徵才...等企業相關資訊,像是網頁設計公司

    購物網站

    用來銷售的網站,像是購物商城、電子商務網站,像是MOMO、PCHOME...

    一頁式網站

    網站只建立一個頁面,透過錨點,定位在不同的區塊

    社群網站

    能即時與使用者溝通傳送訊息,通常發布圖片、短片、短文,用來發布短文、圖片等,能與使用者即時溝通,像是Facebook、instagram

    開始規劃你的網站

    https://ithelp.ithome.com.tw/upload/images/20210917/20112053EJ6ugghZFi.png
    架設網站之前,要結合企業的行業定位、目標人群、品牌特點做需求分析,規劃好網站的整體框架和內容版塊,完成好這些再進行後續的細節設計,也方便設計師與工程師的溝通。以下是五點是製作網站的流程

    一、擬定網站企劃

    • 設定網站的用途(前面提到的企業網站、購物網站...)
    • 使用對象(包含年齡、性別、職業...)
      清楚知道網站目的與使用對象後,搜集相關資料(商品圖片、文字內容、logo...),並思考需要有哪些頁面,繪製架構圖,讓使用者在瀏覽網站時不會迷路。

    二、製作線稿(wireframe)

    找好資訊後,思考每個頁面內容的優先順序及動線,需呈現哪些內容。

    三、製作設計稿

    畫完線稿確認完成後就可以開始設計囉~
    思考網站的配色、字體、內容等呈現畫面,下一章節也會向你介紹設計靈感及素材。

    四、編碼

    確認好設計稿之後,就可以用編輯器切成網頁檔,會有*.html、css、圖片檔等網頁相關檔案。

    五、測試發佈

    網站完成後,測試網站的完整性,內容是否有錯誤,沒問題後也可以上傳到伺服器,讓更多人看到了

    結論

    要設計一個網站,需要思考架設網站的目的、使用者對象、瀏覽動線...等考量,尤其現在行動裝置的普遍,在手機瀏覽上更需要有好的的使用者體驗。平時可以多瀏覽別人製作的網站,找尋靈感,製作符合需求的網站。

    參考網站:
    https://www.nss.com.tw/2020-網頁設計大哉問,從排版開始抓住使用者的目光/
    https://medium.com/rar-design/使用者瀏覽網頁的3種路徑-古騰堡排列-z-字動線與-f-式佈局-7471cf0f2950
    https://www.nazka.me/網站加速/
    https://www.newseoera.com/page-speed-seo/

    ]]> sunny 2021-09-17 09:28:21
    30天學會HTML+CSS,製作精美網站 https://ithelp.ithome.com.tw/articles/10260436?sc=rss.iron https://ithelp.ithome.com.tw/articles/10260436?sc=rss.iron 隨著科技不斷進步,智慧型手機的普及,網際網路已經進入生活的食衣住行等各方面的需求,隨時隨地只要透過網頁就可以向使用者分享資訊、互動、溝通、購物....,使用者只要透過網站搜尋,就能即時獲取大量多...]]> 隨著科技不斷進步,智慧型手機的普及,網際網路已經進入生活的食衣住行等各方面的需求,隨時隨地只要透過網頁就可以向使用者分享資訊、互動、溝通、購物....,使用者只要透過網站搜尋,就能即時獲取大量多樣的資訊。

    寫作動機及目標

    https://ithelp.ithome.com.tw/upload/images/20210916/201120538ljTNhdFpB.png
    近幾年新的技術不斷地湧出,舊的技術也不斷地在更新,像是以前做動畫需要用Flash才能實現,現在也可以用CSS來實現了,因此打好基本功,才能隨心所欲的製作出各式各樣不同風格的網站。

    那你會問,現在也有很多免費架站平台來製作網站,幾分鐘之內快速做好一個網站了,用那做一做就好啦!是這樣沒錯,但是版型、功能大幅受限,想改的改不動,想加的不能加,所以就必須了解網頁相關知識,才能製作符合自己的網站風格,那最基本的就是要學會HTML及CSS了。
    這30天,這系列文章我會分享:

    • 常使用的素材網站、線上產生器
    • 使用編輯器好用套件
    • html+css介紹,並補充我自己遇到的問題及樣式寫法
    • 製作響應式網站需要注意的細節

    希望可以幫助初學者學習製作網站,也歡迎大家跟我分享

    目錄

    ]]>
    sunny 2021-09-16 09:00:46

paypal.me/twcctz50
http://blog.sina.com.tw/window/feed.php?ver=rss&type=entry&blog_id=48997
https://paypal.me/twcctz50?country.x=TW&locale.x=zh_TW
使用 PayPal.Me 連結付款給我: https://paypal.me/twcctz50?country.x=TW&locale.x=zh_TW 
健康是最好的禮物蛋黃油https://www.facebook.com/eggsoil  
在生寶妹之前,寶妹媽,就食用蛋黃油調養車禍後造成的心律不整等後遺症狀將近兩年,配合復健、整復治療和游泳運動等,逐漸恢復正常的心律。
直到懷寶妹後至今,感謝蛋黃油讓寶妹媽能恢復健康,給這意外來的祝福一個健康的生長環境。寶妹雖是家中最小的孩子,但也是最健康、幸福的孩子!惟有她是媽媽有豐富的母乳可供親餵。
至今,恭喜寶妹已經滿兩歲了!每天還是喜歡找媽媽喝餒餒睡覺,出生至今,身體健康,沒有感冒和生病的紀錄。祝福寶妹,能一直健康、快樂的成長、學習,成為眾人的祝福!
代工生產製造需一千斤
需用者請提早預約安排
每天補充蛋黃油可降低罹癌風險?!是的!!
昨晚,十多年老案主的弟弟周大哥說,二哥鼻咽癌治療恢復後的後遺症,又發作了!需配合醫師開的抗生素和補充細胞再生的營養素,又訂了10瓶50ml,補充瓶。
據了解個案案主,罹癌前的工作是從事印刷業。坦白說,有點醫學常識的人多半知道化學油墨對身體的傷害為何?
本科所學為設計的我,也曾在相關產業待過十幾年的時間,等到研究所和醫院合作完成論文後,才知道自己的工作:設計和教職,其實,都隱含著很高的罹癌風險!
我們都曾因此賠上過健康,但慶幸自己和案主們,都是有福之人!
感謝蛋黃油豐富的卵磷脂營養成份,除了維生素C之外,幾乎涵蓋了所有!在103學年間,我曾因超鐘點一週上課時數33小時,忙碌於家庭和工作間,哪時老二剛出生半年,做好月子後,馬上就恢復忙碌的教職工作,不出一個月,就為卵巢炎、併發盆腔炎,抗生素吃了半年,還是不見恢復的病痛所苦!
期間,幾乎每兩週跑醫院兩三趟,署基的婦科主任醫師,也建議我要跟校長請辭,調養身體為重!感謝校長體諒,讓我減課到16堂,撐到合約到期,沒有違約金的困擾,離職後,就回家照顧老二和調養自己的身體。
卵巢炎超痛的!併發盆腔炎更痛!從早痛到晚!醫師說,抗生素吃半年了,就不能再吃了!感謝醫師沒讓我繼續吃下去!
而是勸我調整工作、生活和飲食!於是,我又開始大量食用蛋黃油和自己料理三餐,就這樣子,吃了半年,某天,突然驚覺:卵巢不痛了耶!
感謝神!在恢復前的每一時刻,我被疼痛纏身,影響情緒和睡眠,每天都不知要多久,才會好?!只是一直做該做的事,好好吃飯、休息,調養身心!直到恢復時,才發覺:哇!幸好,半年就好了!
這是蛋黃油在我近十年的健康危機中,第二次救了我!感謝神創造各樣美好食物,保守、祝福我們能有機會恢復祂起初創造我們的美好!
感謝近十幾年來,因著每一次的健康危機,即時食用蛋黃油排毒、調養身體、恢復正常的心律,讓我能在身體得滋養後再懷孕生下健康的孩子們,也讓我們的生命得到延續。
為此,我才投入後來的時間、金錢、精神在服務和我一樣有需要的案主們身上。感謝大家一起陪我攜手走過已過的十幾年。祝福每個人都能有機會認知到維護健康的身體,其奧秘就在於養成正確的日常飲食習慣!
筆者:蛋黃油男
電話:02-24978169
手機:0989-422508
為資深個案自主健康管理設計師,
目前服務於品蔚養生設計事務所。
https://liker.social/invite/pRwYGraC
https://www.facebook.com/eggsoil
https://www.facebook.com/nectw721
https://www.instagram.com/0989422508mdc
https://www.pinterest.com/twcctz500
https://www.linkedin.com/in/twcctz500
https://www.twitter.com/twcctz500
https://currents.google.com/117454133619976175486
https://www.youtube.com/shorts/o8Jaud7px4w
https://www.youtube.com/channel/UC5E4_uNgGl_omnUVfL7fUyA
https://fitness-center-727.business.site/
https://g.page/r/CUt-sGCWmpP2EBM/review
https://matters.news/@twcctz500
https://pastebin.com/NgugYMZP   來自 @pastebin 
https://hardbin.com/ipfs/QmSmgLoGrr4dcJ4EFmszDXJAGbXW2oZU5nNgksdjG7bb3P/
https://zerobin.net/?b4e43b1d09b3dcbe#C4rH4SwtqM4v4BsehLtwVf2DSEhto1JRx8PzKIsmrYo=
https://zerobin.net/?4fdb0ea46d78f4a6#z7E38he/vzywjsvzxBwTBm5dvCaKc5Pei8nDkUflgOs=
https://privatebin.net/?8abe23c5b0253b66#7Vq3VyzThWp2ga7tvVBQ4om6aiYdqvma4bpfWYNKMCgG
https://medium.com/@twcctz50
https://about.me/twcctz500
paypal.me/twcctz50

ASP.NET 伺服器控制項開發 :: 2008 iT 邦幫忙鐵人賽 https://ithelp.ithome.com.tw/users/20007956/ironman zh-TW Mon, 06 Jun 2022 20:19:06 +0800 [ASP.NET 控制項實作 Day29] 解決 DropDownList 成員 Value 值相同產生的問題(續) https://ithelp.ithome.com.tw/articles/10013458?sc=rss.iron https://ithelp.ithome.com.tw/articles/10013458?sc=rss.iron 接續上一文
接下來還要覆寫 LoadPostData 方法,取得 __EVENTARGUMENT 這個 HiddenField 的值,並判斷與原 SelectedIndex 屬性值是...]]>
接續上一文
接下來還要覆寫 LoadPostData 方法,取得 __EVENTARGUMENT 這個 HiddenField 的值,並判斷與原 SelectedIndex 屬性值是否不同,不同的話傳回 True,使其產生 SelectedIndexChanged 事件。

        Protected Overrides Function LoadPostData(ByVal postDataKey As String, ByVal postCollection As NameValueCollection) As Boolean
            Dim values As String()
            Dim iSelectedIndex As Integer

            Me.EnsureDataBound()
            values = postCollection.GetValues(postDataKey)

            If (Not values Is Nothing) Then
                iSelectedIndex = CInt(Me.Page.Request.Form("__EVENTARGUMENT"))
                If (Me.SelectedIndex <> iSelectedIndex) Then
                    MyBase.SetPostDataSelection(iSelectedIndex)
                    Return True
                End If
            End If
            Return False
        End Function

四、測試程式
在 TBDropDownList 的 SelectedIndexChanged 事件撰寫如下測試程式碼。

    Protected Sub DropDownList2_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles DropDownList2.SelectedIndexChanged
        Dim sText As String

        sText = String.Format("TBDropDownList: Index={0} Value={1}", DropDownList2.SelectedIndex, DropDownList2.SelectedValue)
        Me.Response.Write(sText)
    End Sub

執行程式,在 TBDropDownList 選取 "王五" 這個選項時,會正常顯示該成員的 SelectedIndex 及 SelectedValue 屬性值。

接下選取 Value 值相同的 "陳六" 這個選項,也會正常引發 SelectedIndexChanged ,並顯示該成員的 SelectedIndex 及 SelectedValue 屬性值。

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/30/5830.aspx

]]>
jeff377 2008-10-30 21:23:12
[ASP.NET 控制項實作 Day29] 解決 DropDownList 成員 Value 值相同產生的問題 https://ithelp.ithome.com.tw/articles/10013457?sc=rss.iron https://ithelp.ithome.com.tw/articles/10013457?sc=rss.iron DropDownList 控制頁的成員清單中,若有 ListItem 的 Value 值是相同的情形時,會造成 DropDownList 無法取得正確的 SelectedIndex 屬性值、且無...]]> DropDownList 控制頁的成員清單中,若有 ListItem 的 Value 值是相同的情形時,會造成 DropDownList 無法取得正確的 SelectedIndex 屬性值、且無法正確引發 SelectedIndexChanged 事件的問題;今天剛好在網路上看到有人在詢問此問題,所以本文將說明這個問題的源由,並修改 DropDownList 控制項來解決這個問題。
程式碼下載:ASP.NET Server Control - Day29.rar

一、DropDownList 的成員 Value 值相同產生的問題
我們先寫個測試程式來描述問題,在頁面上放置一個 DropDownList 控制項,設定 AutoPostBack=True,並加入四個 ListItem,其中 "王五" 及 "陳六" 二個 ListItem 的 Value 值相同。

    <asp:DropDownList ID="DropDownList1" runat="server" AutoPostBack="True">
            <asp:ListItem Value="0">張三</asp:ListItem>
            <asp:ListItem Value="1">李四</asp:ListItem>
            <asp:ListItem Value="2">王五</asp:ListItem>
            <asp:ListItem Value="2">陳六</asp:ListItem>
    </asp:DropDownList>

在 DropDownList 的 SelectedIndexChanged 事件,輸出 DropDownList 的 SelectedIndex 及 SelectedValue 屬性值。

    Protected Sub DropDownList1_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles DropDownList1.SelectedIndexChanged
        Dim sText As String

        sText = String.Format("DropDownList: Index={0} Value={1}", DropDownList1.SelectedIndex, DropDownList1.SelectedValue)
        Me.Response.Write(sText)
    End Sub

執行程式,在 DropDownList 選取 "李四" 這個選項時,會正常顯示該成員的 SelectedIndex 及 SelectedValue 屬性值。

接下來選取 "陳六" 這個選項時,竟然發生奇怪的現象,DorpDownList 竟然顯示相同 Value 值的 "王五" 這個成員的 SelectedIndex 及 SelectedValue 屬性值。

二、問題發生的原因
我們先看一下 DropDownList 輸出到用戶端的 HTML 原始碼。

<select name="DropDownList1" onchange="javascript:setTimeout('__doPostBack(\'DropDownList1\',\'\')', 0)" id="DropDownList1">
	<option selected="selected" value="0">張三</option>
	<option value="1">李四</option>
	<option value="2">王五</option>
	<option value="2">陳六</option>
</select>

DropDownList 是呼叫 __doPostBack 函式,只傳入 eventTarget參數 (對應到 __EVENTTARGET 這個 HiddenField) 為 DropDownList 的 ClientID;當 PostBack 回伺服端時,在 DropDownList 的 LoadPostData 方法中,會取得用戶端選取的 SelectedValue 值,並去尋找對應的成員的 SelectedIndex 值。可是問題來了,因為 "王五" 與 "陳六" 的 Value 是相同的值,當在尋找符合 Value 值的成員時,前面的選項 "王五" 會先符合條件而傳回該 Index 值,所以先造成取得錯誤的 SelectedIndex 。

Protected Overridable Function LoadPostData(ByVal postDataKey As String, ByVal postCollection As NameValueCollection) As Boolean
    Dim values As String() = postCollection.GetValues(postDataKey)
    Me.EnsureDataBound
    If (Not values Is Nothing) Then
        MyBase.ValidateEvent(postDataKey, values(0))
        Dim selectedIndex As Integer = Me.Items.FindByValueInternal(values(0), False)
        If (Me.SelectedIndex <> selectedIndex) Then
            MyBase.SetPostDataSelection(selectedIndex)
            Return True
        End If
    End If
    Return False
End Function

三、修改 DropDownList 控制項來解決問題
要解決這個問題最好的方式就是直接修改 DropDownList 控制項,自行處理前端呼叫 __doPostBack 的動作,將用戶端 DropDownList 選擇 SelectedIndex 一併傳回伺服端。所以我們繼承 DropDownList 命名為 TBDropDownList,覆寫 AddAttributesToRender 來自行輸出 PostBack 的用戶端指令碼,我們會用一個變數記錄 AutoPostBack 屬性,並強制將 AutoPostBack 屬性值設為 False,這是為了不要 MyBase 產生 PostBack 的指令碼;然後再自行輸出 AutoPostBack 用戶端指令碼,其中 __doPostBack 的 eventArgument 參數 (對應到 __EVENTARGUMENT 這個 HiddenField) 傳入 this.selectedIndex。

        Protected Overrides Sub AddAttributesToRender(ByVal writer As HtmlTextWriter)
            Dim bAutoPostBack As Boolean
            Dim sScript As String

            '記錄 AutoPostBack 值,並將 AutoPostBack 設為 False,不要讓 MyBase 產生 PostBack 的指令碼
            bAutoPostBack = Me.AutoPostBack
            Me.AutoPostBack = False

            MyBase.AddAttributesToRender(writer)

            If bAutoPostBack Then
                MyBase.Attributes.Remove("onchange")
                sScript = String.Format("__doPostBack('{0}',{1})", Me.ClientID, "this.selectedIndex")
                writer.AddAttribute(HtmlTextWriterAttribute.Onchange, sScript)
                Me.AutoPostBack = True
            End If
        End Sub

在頁面上放置一個 TBDropDownList 控制項,設定與上述案例相同的成員清單。

        <bee:TBDropDownList ID="DropDownList2" runat="server" AutoPostBack="True">
            <asp:ListItem Value="0">張三</asp:ListItem>
            <asp:ListItem Value="1">李四</asp:ListItem>
            <asp:ListItem Value="2">王五</asp:ListItem>
            <asp:ListItem Value="2">陳六</asp:ListItem>
        </bee:TBDropDownList>

執行程式查看 TBDropDownList 控制項的 HTML 原始碼,呼叫 __doPostBack 函式的參數已經被修改,eventArgument 參數會傳入該控制項的 selectedIndex。

<select name="DropDownList2" id="DropDownList2" onchange="__doPostBack('DropDownList2',this.selectedIndex)">
	<option selected="selected" value="0">張三</option>
	<option value="1">李四</option>
	<option value="2">王五</option>
	<option value="2">陳六</option>
</select>

[超過字數限制,下一篇接續本文]

]]>
jeff377 2008-10-30 21:15:23
[ASP.NET 控制項實作 Day28] 圖形驗證碼控制項(續) https://ithelp.ithome.com.tw/articles/10013365?sc=rss.iron https://ithelp.ithome.com.tw/articles/10013365?sc=rss.iron 接續一上文
二、實作圖形驗證碼控制項
雖然我們可以使用 Image 控制項來呈現 ValidateCode.aspx 頁面產生的驗證碼圖...]]>
接續一上文
二、實作圖形驗證碼控制項
雖然我們可以使用 Image 控制項來呈現 ValidateCode.aspx 頁面產生的驗證碼圖形,可是這樣只處理一半的動作,因為沒有處理「使用者輸入的驗證碼」是否與「圖形驗證碼」相符,所以我們將實作一個圖形驗證碼控制項,來處理掉所有相關動作。
即然上面的示範使用 Image 控制項來呈現驗證碼,所以圖形驗證碼控制項就繼承 Image 命名為 TBValidateCode。

    < _
    Description("圖形驗證碼控制項"), _
    ToolboxData("<{0}:TBValidateCode runat=server></{0}:TBValidateCode>") _
    > _
    Public Class TBValidateCode
        Inherits System.Web.UI.WebControls.Image
    
    End

新增 ValidateCodeUrl 屬性,設定圖形驗證碼產生頁面的網址。

        ''' <summary>
        ''' 圖形驗證碼產生頁面網址。
        ''' </summary>
        < _
        Description("圖形驗證碼產生頁面網址"), _
        DefaultValue("") _
        > _
        Public Property ValidateCodeUrl() As String
            Get
                Return FValidateCodeUrl
            End Get
            Set(ByVal value As String)
                FValidateCodeUrl = value
            End Set
        End Property

覆寫 Render 方法,若未設定 ValidateCodeUrl 屬性,則預設為 ~/Page/ValidateCode.aspx 這個頁面。另外我們在圖形的 ondbclick 加上一段用戶端指令碼,其作用是讓用戶可以滑鼠二下來重新產生一個驗證碼圖形。

        Protected Overrides Sub Render(ByVal writer As System.Web.UI.HtmlTextWriter)
            Dim sUrl As String
            Dim sScript As String

            sUrl = Me.ValidateCodeUrl
            If String.IsNullOrEmpty(sUrl) Then
                sUrl = "~/Page/ValidateCode.aspx"
            End If
            If Me.BorderWidth = Unit.Empty Then
                Me.BorderWidth = Unit.Pixel(1)
            End If
            If Me.AlternateText = String.Empty Then
                Me.AlternateText = "圖形驗證碼"
            End If
            Me.ToolTip = "滑鼠點二下可重新產生驗證碼"
            Me.ImageUrl = sUrl
            If Not Me.DesignMode Then
                sScript = String.Format("this.src='{0}?flag='+Math.random();", Me.Page.ResolveClientUrl(sUrl))
                Me.Attributes("ondblclick") = sScript
            End If
            Me.Style(HtmlTextWriterStyle.Cursor) = "pointer"

            MyBase.Render(writer)
        End Sub

另外新增一個 ValidateCode 方法,用來檢查輸入驗證碼是否正確。還記得我們在產生驗證碼圖形時,同時把該驗證碼的值寫入 Session("_ValidateCode") 中吧,所以這個方法只是把用戶輸入的值與 Seesion 中的值做比對。

        ''' <summary>
        ''' 檢查輸入驗證碼是否正確。
        ''' </summary>
        ''' <param name="Code">輸入驗證碼。</param>
        ''' <returns>驗證成功傳回 True,反之傳回 False。</returns>
        Public Function ValidateCode(ByVal Code As String) As Boolean
            If Me.Page.Session(SessionKey) Is Nothing Then Return False
            If SameText(CCStr(Me.Page.Session(SessionKey)), Code) Then
                Return True
            Else
                Return False
            End If
        End Function

三、測試程式
在頁面放置一個 TBValidateCode 控制項,另外加一個文字框及按鈕,供使用者輸入驗證碼後按下「確定」鈕後到伺服端做輸入值比對的動作。

        <bee:TBValidateCode ID="TBValidateCode1" runat="server" />
        <bee:TBTextBox ID="txtCode" runat="server"></bee:TBTextBox>
        <bee:TBButton ID="TBButton1" runat="server" Text="確定" />

在「確定」鈕的 Click 事件中,我們使用 TBValidateCode 控制項的 ValidateCode 方法判斷驗證碼輸入的正確性。

    Protected Sub TBButton1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles TBButton1.Click
        If TBValidateCode1.ValidateCode(txtCode.Text) Then
            Me.Response.Write("驗證碼輸入正確")
        Else
            Me.Response.Write("驗證碼輸入錯誤!")
        End If
    End Sub

執行程式,頁面就會隨機產生一個驗證碼圖形。

輸入正確的值按「確定」鈕,就會顯示「驗證碼輸入正確」的訊息。因為我們在同一頁面測試的關係,你會發現 PostBack 後驗證碼圖形又會重新產生,一般正常的做法是驗證正確後就導向另一個頁面。

當我們輸入錯誤的值,就會顯示「驗證碼輸入錯誤!」的訊息。

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/29/5818.aspx

]]>
jeff377 2008-10-29 20:34:22
[ASP.NET 控制項實作 Day28] 圖形驗證碼控制項 https://ithelp.ithome.com.tw/articles/10013361?sc=rss.iron https://ithelp.ithome.com.tw/articles/10013361?sc=rss.iron 在網頁上常把圖形驗證碼應用在登入或貼文的頁面中,因為圖形驗證碼具有機器不易識別的特性,可以防止機器人程式惡意的存取網頁。在本文中將實作一個圖形驗證碼的伺服器控制項,透過簡單的屬性設定就可以輕易地...]]> 在網頁上常把圖形驗證碼應用在登入或貼文的頁面中,因為圖形驗證碼具有機器不易識別的特性,可以防止機器人程式惡意的存取網頁。在本文中將實作一個圖形驗證碼的伺服器控制項,透過簡單的屬性設定就可以輕易地在網頁上套用圖形驗證碼。
程式碼下載:ASP.NET Server Control - Day28.rar

一、產生圖形驗證碼
我們先準備一個產生圖形驗證碼的頁面 (ValidateCode.aspx),這個頁面主要是繪製驗證碼圖形,並將其寫入記憶體資料流,最後使用 Response.BinaryWrite 將圖形輸出傳遞到用戶端。當我們輸出此驗證碼圖形的同時,會使用 Session("_ValidateCode") 來記錄驗證碼的值,以便後續與使用者輸入驗證碼做比對之用。

Partial Class ValidateCode
    Inherits System.Web.UI.Page

    ''' <summary>
    ''' 產生圖形驗證碼。
    ''' </summary>
    Public Function CreateValidateCodeImage(ByRef Code As String, ByVal CodeLength As Integer, _
        ByVal Width As Integer, ByVal Height As Integer, ByVal FontSize As Integer) As Bitmap
        Dim sCode As String = String.Empty
        '顏色列表,用於驗證碼、噪線、噪點
        Dim oColors As Color() = { _
            Drawing.Color.Black, Drawing.Color.Red, Drawing.Color.Blue, Drawing.Color.Green, _
            Drawing.Color.Orange, Drawing.Color.Brown, Drawing.Color.Brown, Drawing.Color.DarkBlue}
        '字體列表,用於驗證碼
        Dim oFontNames As String() = {"Times New Roman", "MS Mincho", "Book Antiqua", _
                                      "Gungsuh", "PMingLiU", "Impact"}
        '驗證碼的字元集,去掉了一些容易混淆的字元
        Dim oCharacter As Char() = {"2"c, "3"c, "4"c, "5"c, "6"c, "8"c, _
                                    "9"c, "A"c, "B"c, "C"c, "D"c, "E"c, _
                                    "F"c, "G"c, "H"c, "J"c, "K"c, "L"c, _
                                    "M"c, "N"c, "P"c, "R"c, "S"c, "T"c, _
                                    "W"c, "X"c, "Y"c}
        Dim oRnd As New Random()
        Dim oBmp As Bitmap
        Dim oGraphics As Graphics
        Dim N1 As Integer
        Dim oPoint1 As Drawing.Point
        Dim oPoint2 As Drawing.Point
        Dim sFontName As String
        Dim oFont As Font
        Dim oColor As Color

        '生成驗證碼字串
        For N1 = 0 To CodeLength - 1
            sCode += oCharacter(oRnd.Next(oCharacter.Length))
        Next

        oBmp = New Bitmap(Width, Height)
        oGraphics = Graphics.FromImage(oBmp)
        oGraphics.Clear(Drawing.Color.White)
        Try
            For N1 = 0 To 4
                '畫噪線
                oPoint1.X = oRnd.Next(Width)
                oPoint1.Y = oRnd.Next(Height)
                oPoint2.X = oRnd.Next(Width)
                oPoint2.Y = oRnd.Next(Height)
                oColor = oColors(oRnd.Next(oColors.Length))
                oGraphics.DrawLine(New Pen(oColor), oPoint1, oPoint2)
            Next

            For N1 = 0 To sCode.Length - 1
                '畫驗證碼字串
                sFontName = oFontNames(oRnd.Next(oFontNames.Length))
                oFont = New Font(sFontName, FontSize, FontStyle.Italic)
                oColor = oColors(oRnd.Next(oColors.Length))
                oGraphics.DrawString(sCode(N1).ToString(), oFont, New SolidBrush(oColor), CSng(N1) * FontSize + 10, CSng(8))
            Next

            For i As Integer = 0 To 30
                '畫噪點
                Dim x As Integer = oRnd.Next(oBmp.Width)
                Dim y As Integer = oRnd.Next(oBmp.Height)
                Dim clr As Color = oColors(oRnd.Next(oColors.Length))
                oBmp.SetPixel(x, y, clr)
            Next

            Code = sCode
            Return oBmp
        Finally
            oGraphics.Dispose()
        End Try
    End Function

    ''' <summary>
    ''' 產生圖形驗證碼。
    ''' </summary>
    Public Sub CreateValidateCodeImage(ByRef MemoryStream As MemoryStream, _
        ByRef Code As String, ByVal CodeLength As Integer, _
        ByVal Width As Integer, ByVal Height As Integer, ByVal FontSize As Integer)
        Dim oBmp As Bitmap

        oBmp = CreateValidateCodeImage(Code, CodeLength, Width, Height, FontSize)
        Try
            oBmp.Save(MemoryStream, ImageFormat.Png)
        Finally
            oBmp.Dispose()
        End Try
    End Sub

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Dim sCode As String = String.Empty
        '清除該頁輸出緩存,設置該頁無緩存
        Response.Buffer = True
        Response.ExpiresAbsolute = System.DateTime.Now.AddMilliseconds(0)
        Response.Expires = 0
        Response.CacheControl = "no-cache"
        Response.AppendHeader("Pragma", "No-Cache")
        '將驗證碼圖片寫入記憶體流,並將其以 "image/Png" 格式輸出
        Dim oStream As New MemoryStream()
        Try
            CreateValidateCodeImage(oStream, sCode, 4, 100, 40, 18)
            Me.Session("_ValidateCode") = sCode
            Response.ClearContent()
            Response.ContentType = "image/Png"
            Response.BinaryWrite(oStream.ToArray())
        Finally
            '釋放資源
            oStream.Dispose()
        End Try
    End Sub
End Class

我們將此頁面置於 ~/Page/ValidateCode.aspx,當要使用此頁面的圖形驗證碼,只需要在使用 Image 控制項,設定 ImageUrl 為此頁面即可。

<asp:Image ID="imgValidateCode" runat="server" ImageUrl="~/Page/ValidateCode.aspx" />

[超過字數限制,下一篇接續本文]

]]>
jeff377 2008-10-29 20:31:45
[ASP.NET 控制項實作 Day27] 控制項依 FormView CurrentMode 自行設定狀態(續2) https://ithelp.ithome.com.tw/articles/10013241?sc=rss.iron https://ithelp.ithome.com.tw/articles/10013241?sc=rss.iron 接續上一文
接下來設定做為新增、編輯使用的 TBFormView 控制項,我們只使用 EditItemTemplate 來同時處理新增、刪除,所以 EditItemTemplate ...]]>
接續上一文
接下來設定做為新增、編輯使用的 TBFormView 控制項,我們只使用 EditItemTemplate 來同時處理新增、刪除,所以 EditItemTemplate 需要同時具有「新增」、「更新」、「取消」三個按鈕。其中 ProductID 為主索引欄位,所以我們使用 TBTextBox 來繫結 ProductID 欄位,設定 FormViewModeState.InsertMode="Enable" 使控制項在新增模式時為可編輯,設定 FormViewModeState.EditMode="Disable" 使控制項在修改模式是唯讀的。

        <bee:TBFormView ID="TBFormView1" runat="server" DataKeyNames="ProductID" DataSourceID="SqlDataSource1"
            DefaultMode="Edit" SingleTemplate="EditItemTemplate" BackColor="White" BorderColor="#CCCCCC"
            BorderStyle="None" BorderWidth="1px" CellPadding="3" GridLines="Both" Visible="False">
            <FooterStyle BackColor="White" ForeColor="#000066" />
            <RowStyle ForeColor="#000066" />
            <EditItemTemplate>
                ProductID:
                <bee:TBTextBox ID="TextBox1" runat="server" Text='<%# Bind("ProductID") %>'> 
                  <FormViewModeState EditMode="Disable" InsertMode="Enable">
                  </FormViewModeState>
                </bee:TBTextBox>

                '省略

                <asp:LinkButton ID="LinkButton1" runat="server" CausesValidation="True" CommandName="Insert"
                    Text="新增" />
                 <asp:LinkButton ID="UpdateButton" runat="server" CausesValidation="True" CommandName="Update"
                    Text="更新" />
                 <asp:LinkButton ID="UpdateCancelButton" runat="server" CausesValidation="False"
                    CommandName="Cancel" Text="取消" />
            </EditItemTemplate>
        </bee:TBFormView>

2. 測試新增模式
接下來執行程式,一開始為瀏覽模式,以 TBGridView 來呈現資料。

按下 Header 的「新增」鈕,就會隱藏 TBGridView,而切換到 TBFormView 的新增模式。其中繫結 ProductID 欄位的 TBTextBox 為可編輯模式,而下方的按鈕只會顯示「新增」及「取消」鈕。

在新增模式輸入完畢後,按下「新增」鈕,資料錄就會被寫入資料庫。

3. 測試修改模式
接下來測試修改模式,按下「編輯」鈕,就會隱藏 TBGridView,而切換到 TBFormView 的修改模式。其中繫結 ProductID 欄位的 TBTextBox 為唯讀模式,而下方的按鈕只會顯示「更新」及「取消」鈕。

在修改模式輸入完畢後,按下「更新」鈕,資料錄就會被寫入資料庫。

4. 頁面程式碼
示範了上述的操作後,接下來我們回頭看一下頁面的程式碼。你沒看錯,筆者也沒貼錯,真的是一行程式碼都沒有,因為所有相關動作都由控制項處理掉了。

Partial Class Day27
    Inherits System.Web.UI.Page

End Class

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/28/5806.aspx

]]>
jeff377 2008-10-28 13:57:23
[ASP.NET 控制項實作 Day27] 控制項依 FormView CurrentMode 自行設定狀態(續1) https://ithelp.ithome.com.tw/articles/10013239?sc=rss.iron https://ithelp.ithome.com.tw/articles/10013239?sc=rss.iron 接續上一文
二、讓 TextBox 控制項可自行維護狀態
接下來擴展 TextBox 控制項,繼承 TextBox 命名為 TBText...]]>
接續上一文
二、讓 TextBox 控制項可自行維護狀態
接下來擴展 TextBox 控制項,繼承 TextBox 命名為 TBTextBox。新增 FormViewModeState 屬性 (TBFormViewModeState 型別),依 FormView Mode 來設定控制項狀。並覆寫 PreRender 方法,在此方法中呼叫 DoFormViewModeStatus 私有方法,依 FormView 的模式來處理控制項狀態。

    ''' <summary>
    ''' 文字框控制項。
    ''' </summary>
    < _
    Description("文字框控制項。"), _
    ToolboxData("<{0}:TBTextBox runat=server></{0}:TBTextBox>") _
    > _
    Public Class TBTextBox
        Inherits TextBox
        Private FFormViewModeState As TBFormViewModeState

        ''' <summary>
        ''' 依 FormViewMode 來設定控制項狀態。
        ''' </summary>
        < _
        Category(WebCommon.Category.Behavior), _
        NotifyParentProperty(True), _
        DesignerSerializationVisibility(DesignerSerializationVisibility.Content), _
        PersistenceMode(PersistenceMode.InnerProperty), _
        DefaultValue("") _
        > _
        Public ReadOnly Property FormViewModeState() As TBFormViewModeState
            Get
                If FFormViewModeState Is Nothing Then
                    FFormViewModeState = New TBFormViewModeState
                End If
                Return FFormViewModeState
            End Get
        End Property

        ''' <summary>
        ''' 處理控制項狀態。
        ''' </summary>
        Private Sub DoControlStatus(ByVal ControlStatus As EControlState)
            Select Case ControlStatus
                Case EControlState.Enable
                    Me.Enabled = True
                Case EControlState.Disable
                    Me.Enabled = False
                Case EControlState.Hide
                    Me.Visible = False
            End Select
        End Sub

        ''' <summary>
        ''' 依 FormView 的模式來處理控制項狀態。
        ''' </summary>
        Private Sub DoFormViewModeStatus()
            Dim oFormView As FormView

            '若控制項置於 FormView 中,則依 FormView 的模式來處理控制項狀態
            If TypeOf Me.BindingContainer Is FormView Then
                oFormView = DirectCast(Me.BindingContainer, FormView)
                Select Case oFormView.CurrentMode
                    Case FormViewMode.Insert
                        DoControlStatus(Me.FormViewModeState.InsertMode)
                    Case FormViewMode.Edit
                        DoControlStatus(Me.FormViewModeState.EditMode)
                    Case FormViewMode.ReadOnly
                        DoControlStatus(Me.FormViewModeState.BrowseMode)
                End Select
            End If
        End Sub

        ''' <summary>
        ''' 覆寫。引發 PreRender 事件。
        ''' </summary>
        Protected Overrides Sub OnPreRender(ByVal e As EventArgs)
            MyBase.OnPreRender(e)
            '依 FormView 的模式來處理控制項狀態
            DoFormViewModeStatus()
        End Sub

    End Class

三、測試程式
1. 設定控制項相關屬性
我們使用 Northwnd 資料庫的 Products資料表為例,以 GridView+FormView 示範資料「新增/修改/刪除」的操作。在頁面拖曳 SqlDataSource 控制項後,在頁面上的使用 TBGridView 來顯示瀏覽資料。TBGridView 的 FormViewID 設為關連的 TBFormVIew 控制項;另外有使用到 TBCommandField,設定 ShowHeaderNewButton=True,讓命令列具有「新增」鈕。

        <bee:TBGridView ID="TBGridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="ProductID"
            DataSourceID="SqlDataSource1" FormViewID="TBFormView1">
            <Columns>
                <bee:TBCommandField ShowDeleteButton="True" ShowEditButton="True" 
                    ShowHeaderNewButton="True" >
                </bee:TBCommandField>
                
                '省略
                
            </Columns>
        </bee:TBGridView>

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/28/5806.aspx

]]>
jeff377 2008-10-28 13:53:32
[ASP.NET 控制項實作 Day27] 控制項依 FormView CurrentMode 自行設定狀態 https://ithelp.ithome.com.tw/articles/10013233?sc=rss.iron https://ithelp.ithome.com.tw/articles/10013233?sc=rss.iron GridV...]]> GridView+FormView 示範資料 新增/修改/刪除(進階篇:伺服器控制項) 一文中,示範了擴展 GridView 及 FormView 控制項,讓 GridView 可以透過屬性與 FormView 做關連來處理資料的「新增/修改/刪除」的動作。因為在該案例中,只使用 FormView 的 EditTemplate 同時處理「新增」及「修改」的動作,所以還需要自行撰寫部分程式碼去判斷控制項在新增或修改的啟用狀態,例如編號欄位在新增時為啟用,修改時就不啟用。在該文最後也提及其實有辨法讓這個案例達到零程式碼的目標,那就是讓控制項 (如 TextBox) 自行判斷所在的 FormView 的 CurrentMode,自行決定本身是否要「啟用/不啟用」、「顯示/隱藏」等狀態。本文以 TextBox 為例,說明如何修改 TextBox 讓它可以達到上述的需求。
程式碼下載:ASP.NET Server Control - Day27.rar
Northwnd 資料庫下載:NORTHWND.rar

一、TBFormViewModeState 類別

我們先定義 EControlState (控制項狀態) 列舉,描述控制項在特定模式的狀態為何。

    ''' <summary>
    ''' 控制項狀態列舉。
    ''' </summary>
    Public Enum EControlState
        ''' <summary>
        ''' 不設定。
        ''' </summary>
        NotSet = 0
        ''' <summary>
        ''' 啟用。
        ''' </summary>
        Enable = 1
        ''' <summary>
        ''' 不啟用。
        ''' </summary>
        Disable = 2
        ''' <summary>
        ''' 隱藏。
        ''' </summary>
        Hide = 3
    End Enum

再來定義 TBFormViewModeState 類別,用來設定控制項在各種 FormView 模式 (瀏覽、新增、修改) 中的控制項狀態。

''' <summary>
''' 依 FormViewMode 來設定控制項狀態。
''' </summary>
< _
Serializable(), _
TypeConverter(GetType(ExpandableObjectConverter)) _
> _
Public Class TBFormViewModeState
    Private FInsertMode As EControlState = EControlState.NotSet
    Private FEditMode As EControlState = EControlState.NotSet
    Private FBrowseMode As EControlState = EControlState.NotSet

    ''' <summary>
    ''' 在新增模式(FormViewMode=Insert)的控制項狀態。
    ''' </summary>
    < _
    NotifyParentProperty(True), _
    DefaultValue(GetType(EControlState), "NotSet") _
    > _
    Public Property InsertMode() As EControlState
        Get
            Return FInsertMode
        End Get
        Set(ByVal value As EControlState)
            FInsertMode = value
        End Set
    End Property

    ''' <summary>
    ''' 在編輯模式(FormViewMode=Edit)的控制項狀態。
    ''' </summary>
    < _
    NotifyParentProperty(True), _
    DefaultValue(GetType(EControlState), "NotSet") _
    > _
    Public Property EditMode() As EControlState
        Get
            Return FEditMode
        End Get
        Set(ByVal value As EControlState)
            FEditMode = value
        End Set
    End Property

    ''' <summary>
    ''' 在瀏覽模式(FormViewMode=ReadOnly)的控制項狀態。
    ''' </summary>
    < _
    NotifyParentProperty(True), _
    DefaultValue(GetType(EControlState), "NotSet") _
    > _
    Public Property BrowseMode() As EControlState
        Get
            Return FBrowseMode
        End Get
        Set(ByVal value As EControlState)
            FBrowseMode = value
        End Set
    End Property
End Class

定義為 TBFormViewModeState 型別的屬性是屬於複雜屬性,要套用 TypeConverter(GetType(ExpandableObjectConverter)),讓該屬性可在屬性視窗 (PropertyGrid) 擴展以便設定屬性值,如下圖所示。

[超過字數限制,下一篇接續本文]

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/28/5806.aspx

]]> jeff377 2008-10-28 13:45:43
[ASP.NET 控制項實作 Day26] 讓你的 GridView 與眾不同 https://ithelp.ithome.com.tw/articles/10013209?sc=rss.iron https://ithelp.ithome.com.tw/articles/10013209?sc=rss.iron 在網路上可以找到相當多擴展 GridView 控制項功能的文章,在筆者的部落格中也有多篇提及擴展 GridView、DataControlField、BoundFIeld 功能的相關文章,在本文...]]> 在網路上可以找到相當多擴展 GridView 控制項功能的文章,在筆者的部落格中也有多篇提及擴展 GridView、DataControlField、BoundFIeld 功能的相關文章,在本文將這些關於擴展 GridView 控制項功能及欄位類別的相關文章做一整理簡介,若需要擴展 GridView 相關功能時可以做為參考。
1. 擴展 GridView 控制項 - 無資料時顯示標題列
摘要:當 GridView 繫結的 DataSource 資料筆數為 0 時,會依 EmptyDataTemplate 及 EmptyDataText 的設定來顯示無資料的狀態。若我們希望 GridView 在無資料時,可以顯示欄位標題,有一種作法是在 EmptyDataTemplate 中手動在設定一個標題列,不過這種作法很麻煩。本文擴展 GridView 控制項,直接透過屬性設定就可以在無資料顯示欄位標題。

2. 擴展 GridView 控制項 - 支援 Excel 及 Word 匯出
摘要:GridView 匯出 Excel 及 Word 文件是蠻常使用的需求,此篇文章將擴展 GridView 控制項提供匯出 Excel 及 Word 文件的方法。一般在 GridView 匯出的常見下列問題也會在此一併被解決。

3. GridView+FormView 示範資料 新增/修改/刪除(進階篇:伺服器控制項)
摘要:擴展 GridView 及 FormView 控制項,在 GridView 控制項中新增 FormViewID 屬性,關連至指定的 FormView 控制項 ID,就可以讓 GridView 結合 FormView 來做資料異動的動作。

4. 擴展 CommandField 類別 - 刪除提示訊息
摘要:新增 DeleteConfirmMessage 屬性,設定刪除提示確認訊息。

5. 擴展 CommandField 類別 - 刪除提示訊息含欄位值
摘要:設定刪除提示確認訊息中可包含指定 DataField 欄位值,明確提示要刪除的資料列。

6. 讓 CheckBoxField 繫結非布林值(0 或 1)欄位
摘要:CheckBoxField 若繫結的欄位值為 0 或 1 時 (非布林值) 會發生錯誤,本文擴展 CheckBoxField 類別,讓 CheckBoxField 有辨法繫結 0 或 1 的欄位值。

7. 擴展 CheckBoxField 類別 - 支援非布林值的雙向繫結
摘要:CheckBoxField 繫結的欄位值並無法直接使用 CBool 轉型為布林值,例如 "T/F"、"是/否" 之類的資料,若希望使用 CheckBoxField 來顯示就比較麻煩,一般的作法都是轉為 TemplateField,自行撰寫資料繫結的函式,而且只能支援單向繫結。在本文直接改寫 CheckBoxField 類別,讓 CheckBoxField 可以直接雙向繫結 "T/F" 或 "是/否" 之類的資料。

8. 擴展 CommandField 類別 - Header 加入新增鈕
摘要:支援在 CommandField 的 Header 的部分加入「新增」鈕,執行新增鈕會引發 RowCommand 事件。

9. GridView 自動編號欄位 - TBSerialNumberField
摘要:繼承 DataControlField 來撰寫自動編號欄位,若 GridView 需要自動編號欄位時只需加入欄位即可。

10. 自訂 GridVie 欄位類別 - 實作 TBDropDownField 欄位類別
摘要:支援在 GridView 中顯示下拉清單的欄位類別。

11. 自訂 GridView 欄位 - 日期欄位
摘要:支援在 GridView 中顯示日期下拉選單編輯的欄位類別。

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/27/5793.aspx

]]>
jeff377 2008-10-27 22:37:14
[ASP.NET 控制項實作 Day25] 自訂 GridView 欄位 - 日期欄位(續) https://ithelp.ithome.com.tw/articles/10013091?sc=rss.iron https://ithelp.ithome.com.tw/articles/10013091?sc=rss.iron 接續上一文
四、覆寫 ExtractValuesFromCell 方法 - 擷取儲存格的欄位值
當用戶端使用 GridView 編輯後執...]]>
接續上一文
四、覆寫 ExtractValuesFromCell 方法 - 擷取儲存格的欄位值
當用戶端使用 GridView 編輯後執行更新動作時,會呼叫 ExtractValuesFromCell 方法,來取得儲存格的欄位值,以便寫入資料來源。所以我們要覆寫 ExtractValuesFromCell 方法,將 Cell 或 TDateEdit 控制項的值取出填入具 IOrderedDictionary 介面的物件。

        ''' <summary>
        ''' 使用指定 DataControlFieldCell 的值填入指定的 IDictionary 物件。 
        ''' </summary>
        ''' <param name="Dictionary">用於儲存指定儲存格的值。</param>
        ''' <param name="Cell">包含要擷取值的儲存格。</param>
        ''' <param name="RowState">資料列的狀態。</param>
        ''' <param name="IncludeReadOnly">true 表示包含唯讀欄位的值,否則為 false。</param>
        Public Overrides Sub ExtractValuesFromCell( _
            ByVal Dictionary As IOrderedDictionary, _
            ByVal Cell As DataControlFieldCell, _
            ByVal RowState As DataControlRowState, _
            ByVal IncludeReadOnly As Boolean)

            Dim oControl As Control = Nothing
            Dim sDataField As String = Me.DataField
            Dim oValue As Object = Nothing
            Dim sNullDisplayText As String = Me.NullDisplayText
            Dim oDateEdit As TBDateEdit

            If (((RowState And DataControlRowState.Insert) = DataControlRowState.Normal) OrElse Me.InsertVisible) Then
                If (Cell.Controls.Count > 0) Then
                    oControl = Cell.Controls.Item(0)
                    oDateEdit = TryCast(oControl, TBDateEdit)
                    If (Not oDateEdit Is Nothing) Then
                        oValue = oDateEdit.Text
                    End If
                ElseIf IncludeReadOnly Then
                    Dim s As String = Cell.Text
                    If (s = " ") Then
                        oValue = String.Empty
                    ElseIf (Me.SupportsHtmlEncode AndAlso Me.HtmlEncode) Then
                        oValue = HttpUtility.HtmlDecode(s)
                    Else
                        oValue = s
                    End If
                End If

                If (Not oValue Is Nothing) Then
                    If TypeOf oValue Is String Then
                        If (CStr(oValue).Length = 0) AndAlso Me.ConvertEmptyStringToNull Then
                            oValue = Nothing
                        ElseIf (CStr(oValue) = sNullDisplayText) AndAlso (sNullDisplayText.Length > 0) Then
                            oValue = Nothing
                        End If
                    End If

                    If Dictionary.Contains(sDataField) Then
                        Dictionary.Item(sDataField) = oValue
                    Else
                        Dictionary.Add(sDataField, oValue)
                    End If
                End If
            End If
        End Sub

五、測試程式
我們使用 Northwnd 資料庫的 Employees 資料表為例,在 GridView 加入自訂的 TBDateField 欄位繫結 BirthDate 欄位,另外加入另一個 BoundField 的唯讀欄位,也同樣繫結 BirthDate 欄位來做比較。

            <bee:TBDateField DataField="BirthDate" HeaderText="BirthDate" 
                SortExpression="BirthDate" DataFormatString="{0:d}" 
                ApplyFormatInEditMode="True" CalendarStyle="Winter" />            
            <asp:BoundField DataField="BirthDate" HeaderText="BirthDate" 
                SortExpression="BirthDate" DataFormatString="{0:d}" 
                ApplyFormatInEditMode="True" ReadOnly="true" />

執行程式,在編輯資料列時,TBDateField 就會以 TDateEdit 控制項來進行編輯。

使用 TDateEdit 編輯欄位值後,按「更新」鈕,資料就會被寫回資料庫。

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/26/5777.aspx

]]>
jeff377 2008-10-26 17:04:50
[ASP.NET 控制項實作 Day25] 自訂 GridView 欄位 - 日期欄位 https://ithelp.ithome.com.tw/articles/10013083?sc=rss.iron https://ithelp.ithome.com.tw/articles/10013083?sc=rss.iron 前二篇文章介紹了自訂 GridView 使用的下拉清單欄位 (TBDropDownField),對如何繼承 BoundField 類別下來改寫自訂欄位應該有進一步的了解。在 GridView 中...]]> 前二篇文章介紹了自訂 GridView 使用的下拉清單欄位 (TBDropDownField),對如何繼承 BoundField 類別下來改寫自訂欄位應該有進一步的了解。在 GridView 中輸入日期也常蠻常見的需求,在本文將再實作一個 GridView 使用的日期欄位,在欄位儲存格使用 TBDateEdit 控制項來編輯資料。
程式碼下載:ASP.NET Server Control - Day25.rar
Northwnd 資料庫下載:NORTHWND.rar

一、繼承 TBBaseBoundField 實作 TDateField
GridView 的日期欄位需要繫結資料,一般的作法是由 BoundField 繼承下來改寫;不過我們之前已經有繼承 BoundField 製作一個 TBBaseBoundField 的自訂欄位基底類別 (詳見「 [ASP.NET 控制項實作 Day23] 自訂 GridVie 欄位類別 - 實作 TBDropDownField 欄位類別」 一文),所以我們要實作的日期欄位直接繼承 TBBaseBoundField 命名為 TDateField,並覆寫 CreateField 方法,傳回 TDateField 物件。

    ''' <summary>
    ''' 日期欄位。
    ''' </summary>
    Public Class TBDateField
        Inherits TBBaseBoundField

        Protected Overrides Function CreateField() As DataControlField
            Return New TBDateField()
        End Function
    End Class

自訂欄位類別主要是要覆寫 InitializeDataCell 方法做資料儲存格初始化、覆寫 OnDataBindField 方法將欄位值繫結至 BoundField 物件、覆寫 ExtractValuesFromCell 方法來擷取儲存格的欄位值,下面我們將針對這幾個需要覆寫的方法做一說明。

二、覆寫 InitializeDataCell 方法 - 資料儲存格初始化
首先覆寫 InitializeDataCell 方法處理資料儲存格初始化,當唯讀狀態時使用 Cell 來呈現資料;若為編輯狀態時,則在 Cell 中加入 TBDateEdit 控制項,並將 TBDateField 的屬性設定給 TBDateEdit 控制項的相關屬性。然後將儲存格 (DataControlFieldCell) 或日期控制項 (TDateEdit) 的 DataBinding 事件導向 OnDataBindField 事件處理方法。

        ''' <summary>
        ''' 資料儲存格初始化。
        ''' </summary>
        ''' <param name="Cell">要初始化的儲存格。</param>
        ''' <param name="RowState">資料列狀態。</param>
        Protected Overrides Sub InitializeDataCell(ByVal Cell As DataControlFieldCell, ByVal RowState As DataControlRowState)
            Dim oDateEdit As TBDateEdit
            Dim oControl As Control

            If Me.CellIsEdit(RowState) Then
                '編輯狀態在儲存格加入 TBDateEdit 控制項
                oDateEdit = New TBDateEdit()
                oDateEdit.FirstDayOfWeek = Me.FirstDayOfWeek
                oDateEdit.ShowWeekNumbers = Me.ShowWeekNumbers
                oDateEdit.CalendarStyle = Me.CalendarStyle
                oDateEdit.Lang = Me.Lang
                oDateEdit.ShowTime = Me.ShowTime
                oControl = oDateEdit
                Cell.Controls.Add(oControl)
            Else
                oControl = Cell
            End If

            If (oControl IsNot Nothing) AndAlso MyBase.Visible Then
                AddHandler oControl.DataBinding, New EventHandler(AddressOf Me.OnDataBindField)
            End If
        End Sub

TDateEdit 控制項為筆者自行撰寫的日期控制項,TDateEdit 控制項的相關細節可以參考筆者部落格下面幾篇文章有進一步說明。
日期控制項實作教學(1) - 結合 JavaScript
日期控制項實作教學(2) - PostBack 與 事件
TBDateEdit 日期控制項 - 1.0.0.0 版 (Open Source)

三、覆寫 OnDataBindField 方法 - 將欄位值繫結至 BoundField 物件
當 GridView 執行 DataBind 時,每個儲存格的 DataBinding 事件都會被導向 OnDataBindField 方法,此方法中我們會由資料來源取得指定欄位值,處理此欄位值的格式化時,將欄位值呈現在 Cell 或 TDateEdit 控制項上。

        ''' <summary>
        ''' 將欄位值繫結至 BoundField 物件。 
        ''' </summary>
        Protected Overrides Sub OnDataBindField(ByVal sender As Object, ByVal e As EventArgs)
            Dim oControl As Control
            Dim oDateEdit As TBDateEdit
            Dim oNamingContainer As Control
            Dim oDataValue As Object            '欄位值
            Dim bEncode As Boolean              '是否編碼
            Dim sText As String                 '格式化字串

            oControl = DirectCast(sender, Control)
            oNamingContainer = oControl.NamingContainer
            oDataValue = Me.GetValue(oNamingContainer)
            bEncode = ((Me.SupportsHtmlEncode AndAlso Me.HtmlEncode) AndAlso TypeOf oControl Is TableCell)
            sText = Me.FormatDataValue(oDataValue, bEncode)

            If TypeOf oControl Is TableCell Then
                If (sText.Length = 0) Then
                    sText = " "
                End If
                DirectCast(oControl, TableCell).Text = sText
            Else
                If Not TypeOf oControl Is TBDateEdit Then
                    Throw New HttpException(String.Format("{0}: Wrong Control Type", Me.DataField))
                End If

                oDateEdit = DirectCast(oControl, TBDateEdit)
                If Me.ApplyFormatInEditMode Then
                    oDateEdit.Text = sText
                ElseIf (Not oDataValue Is Nothing) Then
                    oDateEdit.Text = oDataValue.ToString
                End If
            End If
        End Sub

[超過字數限制,下一篇接續本文]

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/25/5772.aspx

]]>
jeff377 2008-10-26 16:56:36
[ASP.NET 控制項實作 Day24] TBDropDownField 的 Items 屬性的資料繫結(續) https://ithelp.ithome.com.tw/articles/10013047?sc=rss.iron https://ithelp.ithome.com.tw/articles/10013047?sc=rss.iron 接續上一文
三、由關連的資料來源擷取資料
再來就是重點就是要處理 PerformSelecrt 私有方法,來取得 Items 屬性的成員...]]>
接續上一文
三、由關連的資料來源擷取資料
再來就是重點就是要處理 PerformSelecrt 私有方法,來取得 Items 屬性的成員清單內容。PerformSelect 方法的作用是去尋找頁面上的具 IDataSource 介面的控制項,並執行此資料來源的 Select 方法,以取得資料來設定 Items 的清單內容。
step1. 尋找資料來源控制項
PerformSelect 方法中有使用 FindControlEx 方法,它是自訂援尋控制項的多載方法,是取代 FindControl 進階方法。程式碼中使用 FindControlEx 去是頁面中以遞迴方式尋找具有 IDataSource 介面的控制項,且 ID 屬性值為 TBDropDownList.ID 的屬性值。
step2. 執行資料來源控制項的 Select 方法
當找到資料來源控制項後 (如 SqlDataSource、ObjectDataSource ...等等),執行其 DataSourceView.Select 方法,此方法需入一個 DataSourceViewSelectCallback 函式當作參數,當資料來源控制項取得資料後回呼我們指定的 OnDataSourceViewSelectCallback 函式中做後序處理。
step3. 將取得的資料來設定生 Items 的清單內容
在 OnDataSourceViewSelectCallback 函式中接到回傳的具 IEnumerable 介面的資料,有可能是 DataView、DataTable ...等型別的資料。利用 DataBinder.GetPropertyValue 來取得 DataTextField 及 DataValueField 設定的欄位值,逐一建立 ListItem 項目,並加入 Items 集合屬性中。

        ''' <summary>
        ''' 從關聯的資料來源擷取資料。
        ''' </summary>
        Private Sub PerformSelect()
            Dim oControl As Control
            Dim oDataSource As IDataSource
            Dim oDataSourceView As DataSourceView

            '若未設定 DataSourceID 屬性則離開
            If StrIsEmpty(Me.DataSourceID) Then Exit Sub
            '找到具 IDataSource 介面的控制項
            oControl = FindControlEx(Me.Control.Page, GetType(IDataSource), "ID", Me.DataSourceID)
            If oControl Is Nothing Then Exit Sub

            oDataSource = DirectCast(oControl, IDataSource)
            oDataSourceView = oDataSource.GetView(String.Empty)
            oDataSourceView.Select(DataSourceSelectArguments.Empty, _
                        New DataSourceViewSelectCallback(AddressOf Me.OnDataSourceViewSelectCallback))
        End Sub

        ''' <summary>
        ''' 擷取資料的回呼函式。
        ''' </summary>
        ''' <param name="data">取得的資料。</param>
        Private Sub OnDataSourceViewSelectCallback(ByVal data As IEnumerable)
            Dim oCollection As ICollection
            Dim oValue As Object
            Dim oItem As ListItem

            Me.Items.Clear()
            If data Is Nothing Then Exit Sub

            oCollection = TryCast(data, ICollection)
            Me.Items.Capacity = oCollection.Count

            For Each oValue In data
                oItem = New ListItem()
                If StrIsNotEmpty(Me.DataTextField) Then
                    oItem.Text = DataBinder.GetPropertyValue(oValue, DataTextField, Nothing)
                End If
                If StrIsNotEmpty(Me.DataValueField) Then
                    oItem.Value = DataBinder.GetPropertyValue(oValue, DataValueField, Nothing)
                End If
                Me.Items.Add(oItem)
            Next
        End Sub

四、測試程式
使用上篇中同一個案例做測試,同樣以 Northwnd 資料庫的 Products 資料表為例。在 GridView 加入自訂的 TBDropDownField 欄位繫結 CategoryID 欄位,並設定 DataSourceID、DataTextField、DataValueField 屬性;另外加入另一個 BoundField 的唯讀欄位,也同樣繫結 CategoryID 欄位來做比較。

                <bee:TBDropDownField  HeaderText="CategoryID"  
                    SortExpression="CategoryID" DataField="CategoryID" 
                    DataTextField="CategoryName" DataValueField="CategoryID" 

DataSourceID="SqlDataSource2">
                </bee:TBDropDownField>
                <asp:BoundField DataField="CategoryID" HeaderText="CategoryID" 
                    SortExpression="CategoryID"  ReadOnly="true" />

執行程式,在 GridView 瀏覽的模式時,TBDropDownField 的儲存格已經會呈現 Items 對應成員的顯示文字。

執行資料列編輯時,也可以正常顯示下拉清單的內容。

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/25/5772.aspx

]]>
jeff377 2008-10-25 18:11:28
[ASP.NET 控制項實作 Day24] TBDropDownField 的 Items 屬性的資料繫結 https://ithelp.ithome.com.tw/articles/10013041?sc=rss.iron https://ithelp.ithome.com.tw/articles/10013041?sc=rss.iron 上篇中我們實作了 GridView 的 TBDropDownField 欄位類別,不過眼尖的讀者不知有沒有發覺我們並處理 Items 屬性取得成員清單的動作,而是直接設定儲存格內含的 TBDro...]]> 上篇中我們實作了 GridView 的 TBDropDownField 欄位類別,不過眼尖的讀者不知有沒有發覺我們並處理 Items 屬性取得成員清單的動作,而是直接設定儲存格內含的 TBDropDownList 控制項相關屬性 (DataSourceID、DataTextField、DataValueField 屬性) 後,就由 TDropDownList 控制項自行處理 Items 屬性的資料繫結。當 GridView 的資料列是編輯狀態時,下拉清單會顯示出 Items 的文字內容;可是瀏覽狀態的資料列,卻是顯示欄位原始值,無法呈現 Items 的文字內容。本文將說明如何自行處理 TBDropDownField 的 Items 屬性的資料繫結動作,並使唯讀狀態的資料列也可以呈現 Items 的文字內容。

程式碼下載:ASP.NET Server Control - Day24.rar
Northwnd 資料庫下載:NORTHWND.rar

一、Items 屬性的問題
我們重新看一次原本 TBDropDownField 類別在處理 Items 屬性的資料繫結取得清單內容的程式碼,在覆寫 InitializeDataCell 方法中,當儲存格為編輯模式時,會呈現 TBDropDownList 控制項並設定取得 Items 清單內容的相關屬性,讓 TBDropDownList 自行去處理它的 Items 屬性的清單內容。

'由資料來源控制項取得清單項目
oDropDownList.DataSourceID = Me.DataSourceID
oDropDownList.DataTextField = Me.DataTextField
oDropDownList.DataValueField = Me.DataValueField

不知你有沒有發覺,我們無論在 InitializeDataCell 及 OnDataBindField 方法中,都沒有針對 TBDropDownList 控制項做任何 DataBind 動作,那它是怎麼從 DataSourceID 關聯的資料來源擷取資料呢?因為 GridView 在執行 DataBind 時,就會要求所有的子控制項做 DataBind,所以我們只要設定好 BDropDownList 控制項相關屬性後,當 TBDropDownList 自動被要求資料繫結時就會取得 Items 的清單內容。
當然使用 TBDropDownList 控制項去處理 Items 的資料繫結動作最簡單,可是這樣唯讀的儲存格只能顯示原始欄位值,無法呈現 Items 中對應成員的文字;除非無論唯讀或編輯狀態,都要建立 TBDropDownList 控制項去取得 Items 清單內容,而唯讀欄位使用 TBDropDownList.Items 去找到對應成員的顯示文字,不過這樣的作法會怪怪的,而且沒有執行效能率。所以比較好的辨法,就是由 TBDropDownField 類別自行處理 Items 的資料繫結,同時提供給唯讀狀態的
DataControlFieldCell 及編輯狀態的 TBDropDownList 使用。

二、由 TBDropDownField 類別處理 Items 屬性的資料繫結
我們要自行處理 Items 屬性來取得成員清單,在 InitializeDataCell 方法中無須處理 Items 屬性,只需產生儲存格需要的子控制項,未來在執行子控制項的 DataBinding 時的 OnDataBindField 方法中再來處理 Items 屬性。

        Protected Overrides Sub InitializeDataCell( _
            ByVal Cell As DataControlFieldCell, _
            ByVal RowState As DataControlRowState)

            Dim oDropDownList As TBDropDownList
            Dim oControl As Control

            If Me.CellIsEdit(RowState) Then
                oDropDownList = New TBDropDownList()
                oControl = oDropDownList
                Cell.Controls.Add(oControl)
            Else
                oControl = Cell
            End If

            If (oControl IsNot Nothing) AndAlso MyBase.Visible Then
                AddHandler oControl.DataBinding, New EventHandler(AddressOf Me.OnDataBindField)
            End If
        End Sub

在 OnDataBindField 方法中,我們加上一段處理 Items 屬性的程式碼如下,會利用 PerformSelecrt 私有方法,由關聯的資料來源 (即 DataSrouceID 指定的資料來源控制項) 擷取資料並產生 Items 的成員清單,在後面會詳細講解 PerformSelecrt 方法處理擷取資料的細節。因為 TBDropDownField 每個資料儲存格都會執行 OnDataBindField 方法,但 Items 取得成員清單的動作只需做一次即可,所以會以 FIsPerformSelect 區域變數來判斷是否已取得 Items 的成員清單,若已取過就不重新取得,這樣比較有執行效能。

            If Not Me.DesignMode Then
                If Not FIsPerformSelect Then
                    '從關聯的資料來源擷取資料
                    PerformSelect()
                    FIsPerformSelect = True
                End If
            End If

當取得儲存儲的對應的欄位值時,依此欄位值由 Items 集合去取得對應的 ListItem 成員,並以此 ListItem.Text 的文字內容來做顯示。

            '由 Items 去取得對應成員的顯示內容
            oListItem = Me.Items.FindByValue(CCStr(sText))
            If oListItem IsNot Nothing Then
                sText = oListItem.Text
            End If

若是由 TBDropDownList 所引發的 OnDataBindField 方法時,使用 SetItems 私有方法將 TBDropDownField.Items 屬性複製給 TBDropDownList.Item 屬性。

                ODropDownList = DirectCast(oControl, TBDropDownList)
                SetItems(ODropDownList)

SetItems 私有方法的程式碼如下。

        Private Sub SetItems(ByVal DropDownList As TBDropDownList)
            Dim oItems() As ListItem

            If Not Me.DesignMode Then
                ReDim oItems(Me.Items.Count - 1)
                Me.Items.CopyTo(oItems, 0)
                DropDownList.Items.AddRange(oItems)
            End If
        End Sub

[超過字數限制,下一篇接續本文]

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/25/5772.aspx

]]>
jeff377 2008-10-25 18:09:12
[ASP.NET 控制項實作 Day23] 自訂GridVie欄位-實作TBDropDownField欄位(續3) https://ithelp.ithome.com.tw/articles/10012977?sc=rss.iron https://ithelp.ithome.com.tw/articles/10012977?sc=rss.iron 接續上一文
四、測試程式
辛苦寫好 TBDropDownField 欄位類別時,接下來就是驗收成果的時候。我們以 Northwnd 資料...]]>
接續上一文
四、測試程式
辛苦寫好 TBDropDownField 欄位類別時,接下來就是驗收成果的時候。我們以 Northwnd 資料庫的 Products 資料表為例,將 TBDropDownList .DataField 設為 CategoryID 欄位來做測試。首先我們測試沒有 DataSoruceID 的情況,在 GridView 加入自訂的 TBDropDownField 欄位繫結 CategoryID 欄位,另外加入另一個 BoundField 的唯讀欄位,也同樣繫結 CategoryID 欄位來做比較。

                <bee:TBDropDownField  HeaderText="CategoryID"  
                    SortExpression="CategoryID" DataField="CategoryID" >
                    <Items>
                    <asp:ListItem Value="">未對應</asp:ListItem>
                    <asp:ListItem Value="2">Condiments</asp:ListItem>
                    <asp:ListItem Value="3">Confections</asp:ListItem>
                    </Items>
                </bee:TBDropDownField>
                <asp:BoundField DataField="CategoryID" HeaderText="CategoryID" 
                    SortExpression="CategoryID"  ReadOnly="true" />

執行程式,在 GridView 在唯讀模式,TBDropDownFIeld 可以正確的繫結 CategoryID 欄位值。

編輯某筆資料列進入編輯狀態,就會顯示 TBDropDownList 控制項,清單成員為我們在 Items 設定的內容。

使用 TBDropDownList 來做編輯欄位值,按下更新鈕,這時會執行 TBDropDownField.ExtractValuesFromCell 方法,取得儲存格中的值;最後由資料來源控制項將欄位值寫回資料庫。

接下來測試設定 TBDropDownField.DataSourceID 的情況,把 DataSourcID 指向含 Categories 資料表內容的 SqlDataSoruce 控制項。

                <bee:TBDropDownField  HeaderText="CategoryID"  
                    SortExpression="CategoryID" DataField="CategoryID" 
                    DataTextField="CategoryName" DataValueField="CategoryID" DataSourceID="SqlDataSource2">
                </bee:TBDropDownField>

執行程式查看結果,可以發現 TBDropDownList 控制項的清單內容也可以正常顯示 SqlDataSoruce 控制項取得資料。

[超過字數限制,下一篇接續本文]

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/24/5762.aspx

]]>
jeff377 2008-10-24 00:32:30
[ASP.NET 控制項實作 Day23] 自訂GridVie欄位-實作TBDropDownField欄位(續2) https://ithelp.ithome.com.tw/articles/10012973?sc=rss.iron https://ithelp.ithome.com.tw/articles/10012973?sc=rss.iron 接續上一文
step4. 處理資料繫結
當 GridView 控制項在執行資料繫結時,儲存格的控制項就會引發 DataBinding 事...]]>
接續上一文
step4. 處理資料繫結
當 GridView 控制項在執行資料繫結時,儲存格的控制項就會引發 DataBinding 事件,而這些事件會被導向 OnDataBindField 方法來統一處理儲存格中控制項的繫結動作。

       ''' <summary>
        ''' 將欄位值繫結至 BoundField 物件。 
        ''' </summary>
        ''' <param name="sender">控制項。</param>
        ''' <param name="e">事件引數。</param>
        Protected Overrides Sub OnDataBindField(ByVal sender As Object, ByVal e As EventArgs)
            Dim oControl As Control
            Dim ODropDownList As TBDropDownList
            Dim oNamingContainer As Control
            Dim oDataValue As Object            '欄位值
            Dim bEncode As Boolean              '是否編碼
            Dim sText As String                 '格式化字串

            oControl = DirectCast(sender, Control)
            oNamingContainer = oControl.NamingContainer
            oDataValue = Me.GetValue(oNamingContainer)
            bEncode = ((Me.SupportsHtmlEncode AndAlso Me.HtmlEncode) AndAlso TypeOf oControl Is TableCell)
            sText = Me.FormatDataValue(oDataValue, bEncode)

            If TypeOf oControl Is TableCell Then
                If (sText.Length = 0) Then
                    sText = " "
                End If
                DirectCast(oControl, TableCell).Text = sText
            Else
                If Not TypeOf oControl Is TBDropDownList Then
                    Throw New HttpException(String.Format("{0}: Wrong Control Type", Me.DataField))
                End If

                ODropDownList = DirectCast(oControl, TBDropDownList)

                If Me.ApplyFormatInEditMode Then
                    ODropDownList.Text = sText
                ElseIf (Not oDataValue Is Nothing) Then
                    ODropDownList.Text = oDataValue.ToString
                End If
            End If
        End Sub

step5. 取得儲存格中的值
另外我們還需要覆寫 ExtractValuesFromCell 方法,取得儲存格中的值。這個方法是當 GridView 的編輯資料要準備寫入資料庫時,會經由 ExtractValuesFromCell 方法此來取得每個儲存格的值,並將這些欄位值加入 Dictionary 參數中,這個準備寫入的欄位值集合,可以在 DataSource 控制項的寫入資料庫的相關方法中取得使用。

        ''' <summary>
        ''' 使用指定 DataControlFieldCell 物件的值填入指定的 System.Collections.IDictionary 物件。 
        ''' </summary>
        ''' <param name="Dictionary">用於儲存指定儲存格的值。</param>
        ''' <param name="Cell">包含要擷取值的儲存格。</param>
        ''' <param name="RowState">資料列的狀態。</param>
        ''' <param name="IncludeReadOnly">true 表示包含唯讀欄位的值,否則為 false。</param>
        Public Overrides Sub ExtractValuesFromCell( _
            ByVal Dictionary As IOrderedDictionary, _
            ByVal Cell As DataControlFieldCell, _
            ByVal RowState As DataControlRowState, _
            ByVal IncludeReadOnly As Boolean)

            Dim oControl As Control = Nothing
            Dim sDataField As String = Me.DataField
            Dim oValue As Object = Nothing
            Dim sNullDisplayText As String = Me.NullDisplayText
            Dim oDropDownList As TBDropDownList

            If (((RowState And DataControlRowState.Insert) = DataControlRowState.Normal) OrElse Me.InsertVisible) Then
                If (Cell.Controls.Count > 0) Then
                    oControl = Cell.Controls.Item(0)
                    oDropDownList = TryCast(oControl, TBDropDownList)
                    If (Not oDropDownList Is Nothing) Then
                        oValue = oDropDownList.Text
                    End If
                ElseIf IncludeReadOnly Then
                    Dim s As String = Cell.Text
                    If (s = " ") Then
                        oValue = String.Empty
                    ElseIf (Me.SupportsHtmlEncode AndAlso Me.HtmlEncode) Then
                        oValue = HttpUtility.HtmlDecode(s)
                    Else
                        oValue = s
                    End If
                End If

                If (Not oValue Is Nothing) Then
                    If TypeOf oValue Is String Then
                        If (CStr(oValue).Length = 0) AndAlso Me.ConvertEmptyStringToNull Then
                            oValue = Nothing
                        ElseIf (CStr(oValue) = sNullDisplayText) AndAlso (sNullDisplayText.Length > 0) Then
                            oValue = Nothing
                        End If
                    End If

                    If Dictionary.Contains(sDataField) Then
                        Dictionary.Item(sDataField) = oValue
                    Else
                        Dictionary.Add(sDataField, oValue)
                    End If
                End If
            End If
        End Sub

[超過字數限制,下一篇接續本文]

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/24/5762.aspx

]]>
jeff377 2008-10-24 00:31:32
[ASP.NET 控制項實作 Day23] 自訂GridVie欄位-實作TBDropDownField欄位(續1) https://ithelp.ithome.com.tw/articles/10012971?sc=rss.iron https://ithelp.ithome.com.tw/articles/10012971?sc=rss.iron 接續上一文
step2. 加入 TBBaseBoundField 的屬性
TBBaseBoundField 類別會內含 DropDown...]]>
接續上一文
step2. 加入 TBBaseBoundField 的屬性
TBBaseBoundField 類別會內含 DropDownList 控制項,所以加入設定 DropDownList 控制項的對應屬性;我們在 TBBaseBoundField 類別加入了 Items 、DataSourceID、DataTextField、DataValueField 屬性。其中 Items 屬性的型別與 DropDownList.Items 屬性相同,都是 ListItemCollection 集合類別,且 Items 屬性會儲存於 ViewState 中。

        ''' <summary>
        ''' 清單項目集合。
        ''' </summary>
        < _
        Description("清單項目集合。"), _
        DefaultValue(CStr(Nothing)), _
        PersistenceMode(PersistenceMode.InnerProperty), _
        DesignerSerializationVisibility(DesignerSerializationVisibility.Content), _
        Editor(GetType(ListItemsCollectionEditor), GetType(UITypeEditor)), _
        MergableProperty(False), _
        Category("Default")> _
        Public Overridable ReadOnly Property Items() As ListItemCollection
            Get
                If (FItems Is Nothing) Then
                    FItems = New ListItemCollection()
                    If MyBase.IsTrackingViewState Then
                        CType(FItems, IStateManager).TrackViewState()
                    End If
                End If
                Return FItems
            End Get
        End Property

        ''' <summary>
        ''' 資料來源控制項的 ID 屬性。
        ''' </summary>
        Public Property DataSourceID() As String
            Get
                Return FDataSourceID
            End Get
            Set(ByVal value As String)
                FDataSourceID = value
            End Set
        End Property

        ''' <summary>
        ''' 提供清單項目文字內容的資料來源的欄位。
        ''' </summary>
        < _
        Description("提供清單項目文字內容的資料來源的欄位。"), _
        DefaultValue("") _
        > _
        Public Property DataTextField() As String
            Get
                Return FDataTextField
            End Get
            Set(ByVal value As String)
                FDataTextField = value
            End Set
        End Property

        ''' <summary>
        ''' 提供清單項目值的資料來源的欄位。
        ''' </summary>
        Public Property DataValueField() As String
            Get
                Return FDataValueField
            End Get
            Set(ByVal value As String)
                FDataValueField = value
            End Set
        End Property

step3.建立儲存格內含的控制項
GridView 是以儲存格 (DataControlFieldCell) 為單位,我們要覆寫 InitializeDataCell 方法來建立儲存格中的控制項;當儲存格為可編輯狀態時,就建立 DropDownList 控制項並加入儲存格中,在此使用上篇文章提及的 TBDropDownList 控制項來取代,以解決清單成員不存在造成錯誤的問題。若未設定 DataSourceID 屬性時,則由 Items 屬性取得自訂的清單項目;若有設定 DataSourceID 屬性,則由資料來源控制項 (如 SqlDataSource、ObjectDataSource 控制項) 來取得清單項目。
當建立儲存格中的控制項後,需要以 AddHeadler 的方法,將此控制項的 DataBinding 事件導向 OnDataBindField 這個事件處理方法,我們要在 OnDataBindField 處理資料繫結的動作。

        ''' <summary>
        ''' 資料儲存格初始化。
        ''' </summary>
        ''' <param name="Cell">要初始化的儲存格。</param>
        ''' <param name="RowState">資料列狀態。</param>
        Protected Overrides Sub InitializeDataCell( _
            ByVal Cell As DataControlFieldCell, _
            ByVal RowState As DataControlRowState)

            Dim oDropDownList As TBDropDownList
            Dim oItems() As ListItem
            Dim oControl As Control

            If Me.CellIsEdit(RowState) Then
                oDropDownList = New TBDropDownList()
                oControl = oDropDownList
                Cell.Controls.Add(oControl)

                If Not Me.DesignMode Then
                    If StrIsEmpty(Me.DataSourceID) Then
                        '自訂清單項目
                        ReDim oItems(Me.Items.Count - 1)
                        Me.Items.CopyTo(oItems, 0)
                        oDropDownList.Items.AddRange(oItems)
                    Else
                        '由資料來源控制項取得清單項目
                        oDropDownList.DataSourceID = Me.DataSourceID
                        oDropDownList.DataTextField = Me.DataTextField
                        oDropDownList.DataValueField = Me.DataValueField
                    End If
                End If
            Else
                oControl = Cell
            End If

            If (oControl IsNot Nothing) AndAlso MyBase.Visible Then
                AddHandler oControl.DataBinding, New EventHandler(AddressOf Me.OnDataBindField)
            End If

        End Sub

[超過字數限制,下一篇接續本文]

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/24/5762.aspx

]]>
jeff377 2008-10-24 00:25:02
[ASP.NET 控制項實作 Day23] 自訂GridVie欄位-實作TBDropDownField欄位 https://ithelp.ithome.com.tw/articles/10012965?sc=rss.iron https://ithelp.ithome.com.tw/articles/10012965?sc=rss.iron GridView 是 ASP.NET 中一個相當常用的控制項,在 GridView 可加入 BoundField、CheckBoxField、CommandField、TemplateField...]]> GridView 是 ASP.NET 中一個相當常用的控制項,在 GridView 可加入 BoundField、CheckBoxField、CommandField、TemplateField ... 等不同型別的欄位,可是偏偏沒有提供在 GridView 中可呈現 DropDownList 的欄位型別;遇到這類需求時,一般的作法都是使用 TemplateField 來處理。雖然 TemplateField 具有相當好的設計彈性。可是在當 GridView 需要動態產生欄位的需求時,TemplateField 就相當麻煩,要寫一堆程式碼自行去處理資料繫結的動作。相互比較起來,BoundField、CheckBoxField ...等這類事先定義類型的欄位,在 GridView 要動態產生這些欄位就相當方便。如果我們可以把一些常用的 GridView 的欄位,都做成類似 BoundField 一樣,只要設定欄位的屬性就好,這樣使用上就會方便許多,所以在本文將以實作 DropDownList 欄位為例,讓大家了解如何去自訂 GridView 的欄位類別。
程式碼下載:ASP.NET Server Control - Day23.rar
Northwnd 資料庫下載:NORTHWND.rar

一、選擇合適的父類別
一般自訂 GridView 的欄位類別時,大都是由 DataControlField 或 BoundField 繼承下來改寫。若是欄位不需繫結資料(如 CommandFIeld),可以由 DataControlFIeld 繼承下來,若是欄位需要做資料繫結時(如 CheckBoxFIld,可以直接由 BoundField 繼承下來改寫比較方便。
DataControlField 類別是所有類型欄位的基底類別,BoundField 類別也是由 DataControlField 類別繼承下來擴展了資料繫結部分的功能,所以我們要實作含 DropDownList 的欄位,也是由 BoundField 繼承下來改寫。

二、自訂欄位基底類別
在此我們不直接繼承 BoundFIeld,而是先撰寫一個繼承 BoundField 命名為 TBBaseBoundField 的基底類別,此類別提供一些通用的屬性及方法,使我們更方便去撰寫自訂的欄位類別。

    ''' <summary>
    ''' 資料欄位基礎類別。
    ''' </summary>
    Public MustInherit Class TBBaseBoundField
        Inherits BoundField

        Private FRowIndex As Integer = 0

        ''' <summary>
        ''' 資料列是否為編輯模式。
        ''' </summary>
        ''' <param name="RowState">資料列狀態。</param>
        Public Function RowStateIsEdit(ByVal RowState As DataControlRowState) As Boolean
            Return (RowState And DataControlRowState.Edit) <> DataControlRowState.Normal
        End Function

        ''' <summary>
        ''' 資料列是否為新增模式。
        ''' </summary>
        ''' <param name="RowState">資料列狀態。</param>
        Public Function RowStateIsInsert(ByVal RowState As DataControlRowState) As Boolean
            Return (RowState And DataControlRowState.Insert) <> DataControlRowState.Normal
        End Function

        ''' <summary>
        ''' 資料列是否為編輯或新增模式。
        ''' </summary>
        ''' <param name="RowState">資料列狀態。</param>
        Public Function RowStateIsEditOrInsert(ByVal RowState As DataControlRowState) As Boolean
            Return RowStateIsEdit(RowState) OrElse RowStateIsInsert(RowState)
        End Function

        ''' <summary>
        ''' 判斷儲存格是否可編輯(新增/修改)。
        ''' </summary>
        ''' <param name="RowState">資料列狀態。</param>
        Friend Function CellIsEdit(ByVal RowState As DataControlRowState) As Boolean
            Return (Not Me.ReadOnly) AndAlso RowStateIsEditOrInsert(RowState)
        End Function

        ''' <summary>
        ''' 資料列索引。
        ''' </summary>
        Friend ReadOnly Property RowIndex() As Integer
            Get
                Return FRowIndex
            End Get
        End Property

        ''' <summary>
        ''' 儲存格初始化。
        ''' </summary>
        ''' <param name="Cell">要初始化的儲存格。</param>
        ''' <param name="CellType">儲存格類型。</param>
        ''' <param name="RowState">資料列狀態。</param>
        ''' <param name="RowIndex">資料列之以零起始的索引。</param>
        Public Overrides Sub InitializeCell(ByVal Cell As DataControlFieldCell, ByVal CellType As DataControlCellType, _
            ByVal RowState As DataControlRowState, ByVal RowIndex As Integer)

            FRowIndex = RowIndex
            MyBase.InitializeCell(Cell, CellType, RowState, RowIndex)
        End Sub

        ''' <summary>
        ''' 是否需要執行資料繫結。
        ''' </summary>
        ''' <param name="RowState">資料列狀態。</param>
        Friend Function RequiresDataBinding(ByVal RowState As DataControlRowState) As Boolean
            If MyBase.Visible AndAlso StrIsNotEmpty(MyBase.DataField) AndAlso RowStateIsEdit(RowState) Then
                Return True
            Else
                Return False
            End If
        End Function
    End Class

三、實作 TBDropDownField 欄位類別
step1. 繼承 TBBaseBoundField 類別
首先新增一個類別,繼承 TBBaseBoundField 命名為 TBDropDownFIeld 類別,覆寫 CreateField 方法,傳回 TBDropDownFIeld 物件。

    Public Class TBDropDownField
        Inherits TBBaseBoundField

        Protected Overrides Function CreateField() As System.Web.UI.WebControls.DataControlField
            Return New TBDropDownField()
        End Function
    End Class

[超過字數限制,下一篇接續本文]

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/24/5762.aspx

]]>
jeff377 2008-10-24 00:19:12
[ASP.NET 控制項實作 Day22] 讓 DropDownList 不再因項目清單不存在而造成錯誤(續) https://ithelp.ithome.com.tw/articles/10012915?sc=rss.iron https://ithelp.ithome.com.tw/articles/10012915?sc=rss.iron 接續上篇文章內容
三、解決 TBDropDownList 設定 DataSourceID 造成資料無法繫結的問題
要解決上述 TBDro...]]>
接續上篇文章內容
三、解決 TBDropDownList 設定 DataSourceID 造成資料無法繫結的問題
要解決上述 TBDropDownList 設定 DataSourceID 問題,需在設定 SelectedValue 屬性時,若 Items.Count=0 先用一個 FCachedSelectedValue 變數將正確的值先暫存下來,然後覆寫 PerformDataBinding 方法,當 DorpDownList 取得 DataSoruceID 所對應的項目清單內容後,因為這時 Items 的內容才會完整取回,再去設定一次 SelectedValue 屬性就可以正確的繫結資料。

    Public Class TBDropDownList
        Inherits DropDownList

        Private FCachedSelectedValue As String

        ''' <summary>
        ''' 覆寫 SelectedValue 屬性。
        ''' </summary>
        Public Overrides Property SelectedValue() As String
            Get
                Return MyBase.SelectedValue
            End Get
            Set(ByVal value As String)
                If Me.Items.Count <> 0 Then
                    Dim oItem As ListItem = Me.Items.FindByValue(value)
                    If (oItem Is Nothing) Then
                        Me.SelectedIndex = -1 '當 Items 不存在時 
                    Else
                        MyBase.SelectedValue = value
                    End If
                Else
                    FCachedSelectedValue = value
                End If
            End Set
        End Property

        Protected Overrides Sub PerformDataBinding(ByVal data As System.Collections.IEnumerable)
            MyBase.PerformDataBinding(data)

            'DataSoruceID 資料繫結後再設定 SelectedValue 屬性值
            If (Not FCachedSelectedValue Is Nothing) Then
                Me.SelectedValue = FCachedSelectedValue
            End If
        End Sub

    End Class

重新執行程式,切換到編輯模式時,TBDropDownList 就可以正確的繫結欄位值了。

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/22/5749.aspx

]]>
jeff377 2008-10-23 07:03:54
[ASP.NET 控制項實作 Day22] 讓 DropDownList 不再因項目清單不存在而造成錯誤 https://ithelp.ithome.com.tw/articles/10012909?sc=rss.iron https://ithelp.ithome.com.tw/articles/10012909?sc=rss.iron DropDownList 控制項常常會因為項目清單中不存在繫結的欄位,而發生以下的錯誤訊息。因為繫結資料的不完整或異常就會造成這樣的異常錯誤,在設計上實在是相當困擾,而且最麻煩的是這個錯誤在頁面...]]> DropDownList 控制項常常會因為項目清單中不存在繫結的欄位,而發生以下的錯誤訊息。因為繫結資料的不完整或異常就會造成這樣的異常錯誤,在設計上實在是相當困擾,而且最麻煩的是這個錯誤在頁面的程式碼也無法使用 Try ... Catch 方式來略過錯誤。其實最簡單的方式就去直接去修改 DropDownList 控制項,讓 DropDownList 控制項繫結資料時,就算欄位值不存在清單項目中也不要釋出錯誤,本文就要說明如何繼承 DorpDownList 下來修改,來有效解決這個問題。

程式碼下載:ASP.NET Server Control - Day22.rar
Northwnd 資料庫下載:NORTHWND.rar

一、覆寫 SelectedValue 屬性解決資料繫結的問題
DropDownList 控制項繫結錯誤的原因,可以由上圖的錯誤訊息可以大概得知是寫入 SelectedValue 屬性時發生的錯誤;所以我們繼承 DorpDownList 下來命名為 TBDropDownList,並覆寫 SelectedValue 屬性來解決這個問題。解決方式是在寫入 SelectedValue 屬性時,先判斷準備寫入的值是否存在項目清單中,存在的話才寫入 SelectedValue 屬性,若不存在則直接設定 SelectedIndex 屬性為 -1。

    Public Class TBDropDownList
        Inherits DropDownList

        ''' <summary>
        ''' 覆寫 SelectedValue 屬性。
        ''' </summary>
        Public Overrides Property SelectedValue() As String
            Get
                Return MyBase.SelectedValue
            End Get
            Set(ByVal value As String)
                Dim oItem As ListItem = Me.Items.FindByValue(value)
                If (oItem Is Nothing) Then
                    Me.SelectedIndex = -1 '當 Items 不存在時 
                    Exit Property
                Else
                    MyBase.SelectedValue = value
                End If
            End Set
        End Property

    End Class

我們以 Northwnd 資料庫的 Products 資料表做為測試資料,事先定義 DropDownList 的 Items 內容,其中第一個加入 "未對應" 的項目,將 SelectedValue 屬性繫結至 CategoryID 欄位。

                <bee:TBDropDownList ID="DropDownList1" runat="server" 
                    SelectedValue='<%# Bind("CategoryID") %>'>
                    <asp:ListItem Value="">未對應</asp:ListItem>
                    <asp:ListItem Value="2">Condiments</asp:ListItem>
                    <asp:ListItem Value="3">Confections</asp:ListItem>
                </bee:TBDropDownList>

當資料的 CategoryID 欄位值不存在於 DropDownList 的 Items 集合屬性中時,就會顯示第一個 "未對應" 的項目。

二、TBDropDownList 設定 DataSoruceID 產生的問題
上述的解決方法在筆者的「讓 DropDownList DataBind 不再發生錯誤」一文中已經有提及,不過有讀者發現另一個問題,就是當 DropDownList 設定 DataSourceID 時卻會發生資料無法正常繫結,以下就來解決這個問題。
我們設定 TBDropDownList 的 DataSoruceID 來取得項目清單的內容,將 DataSourceID 設定為另一個取得 Categories 資料表內容的 SqlDataSource 控制項。

                <bee:TBDropDownList ID="DropDownList1" runat="server" 
                    SelectedValue='<%# Bind("CategoryID") %>' DataSourceID="SqlDataSource2" 
                    DataTextField="CategoryName" DataValueField="CategoryID">
                </bee:TBDropDownList>
                <asp:SqlDataSource ID="SqlDataSource2" runat="server" 
                    ConnectionString="<%$ ConnectionStrings:Northwnd %>" 
                    SelectCommand="SELECT CategoryID, CategoryName, Description, Picture FROM Categories" 
                    ProviderName="<%$ ConnectionStrings:Northwnd.ProviderName %>" >
                </asp:SqlDataSource>

當執行程式時,FormView 原本在瀏覽模式時的 CategoryID 欄位值為 7 (CategoryName 應為 Product)。

當按下「編輯」時切換到 EditItemTemplate 時,改用 TBDropDownList 繫結 CategoryID 欄位值,可以這時欲無法繫結正確的值。

[超過字數限制,下一篇接續本文]

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/22/5749.aspx

]]>
jeff377 2008-10-23 06:59:56
[ASP.NET 控制項實作 Day21] 實作控制項智慧標籤(續) https://ithelp.ithome.com.tw/articles/10012897?sc=rss.iron https://ithelp.ithome.com.tw/articles/10012897?sc=rss.iron 接續 [ASP.NET 控制項實作 Day21] 實作控制項智慧標籤 一文
step2. 在智慧標籤面板加入屬性項目
DesignerA...]]>
接續 [ASP.NET 控制項實作 Day21] 實作控制項智慧標籤 一文
step2. 在智慧標籤面板加入屬性項目
DesignerActionPropertyItem 類別是設定智慧標籤面上的屬性項目,DesignerActionPropertyItem 建構函式的第一個參數(memberName) 為屬性名稱,這個屬性指的是 TBDateEditActionList 類別中的屬性,所以要在 TBDateEditActionList 新增一個對應的屬性。
例如在智慧標籤中加入 AutoPostBack 屬性項目,則在 TBDateEditActionList 類別需有一個對應 AutoPostBack 屬性。

            oItems.Add(New DesignerActionPropertyItem("AutoPostBack", _
                "AutoPostBack", "Behavior", "是否引發 PostBack 動作。"))

TBDateEditActionList.AutoPostBack 屬性如下,其中 Me.Component 指的是目前的 TDateEdit 控制項,透過 GetPropertyValue 及 SetPropertyValue 方法來存取控制項的指定屬性。

        ''' <summary>
        ''' 是否引發 PostBack 動作。
        ''' </summary>
        Public Property AutoPostBack() As Boolean
            Get
                Return CType(GetPropertyValue(Me.Component, "AutoPostBack"), Boolean)
            End Get
            Set(ByVal value As Boolean)
                SetPropertyValue(Me.Component, "AutoPostBack", value)
            End Set
        End Property

    ''' <summary>
    ''' 設定物件的屬性值。
    ''' </summary>
    ''' <param name="Component">屬性值將要設定的物件。</param>
    ''' <param name="PropertyName">屬性名稱。</param>
    ''' <param name="Value">新值。</param>
    Public Shared Sub SetPropertyValue(ByVal Component As Object, ByVal PropertyName As String, ByVal Value As Object)
        Dim Prop As PropertyDescriptor = TypeDescriptor.GetProperties(Component).Item(PropertyName)
        Prop.SetValue(Component, Value)
    End Sub

    ''' <summary>
    ''' 取得物件的屬性值。
    ''' </summary>
    ''' <param name="Component">具有要擷取屬性的物件。</param>
    ''' <param name="PropertyName">屬性名稱。</param>
    Public Shared Function GetPropertyValue(ByVal Component As Object, ByVal PropertyName As String) As Object
        Dim Prop As PropertyDescriptor = TypeDescriptor.GetProperties(Component).Item(PropertyName)
        Return Prop.GetValue(Component)
    End Function

step3. 在智慧標籤面板加入方法項目
DesignerActionMethodItem 類別是設定智慧標籤面上的方法項目,DesignerActionPropertyItem 建構函式的第二個參數(memberName) 為方法名稱,這個方法指的是 TBDateEditActionList 類別中的方法,所以要在 TBDateEditActionList 新增一個對應的方法。
例如在智慧標籤中加入 About 方法項目,則在 TBDateEditActionList 類別需有一個對應 About 方法。

            oItems.Add(New DesignerActionMethodItem(Me, "About", _
                "關於 TDateEdit 控制項", "About", _
                "關於 TDateEdit 控制項。", True))

TBDateEditActionList 的 About 方法只是單純顯示一個訊息視窗,一般你可以在這方法加入任何想在設計階段處理的動作。例如自動產生 GridView 的欄位、在 FormView 加入控制項並自動排版,這些都可以在此實現的。

        Public Sub About()
            MsgBox("TDateEdit 是結合 The Coolest DHTML Calendar 日期選擇器實作的控制項")
        End Sub

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/22/5749.aspx

]]>
jeff377 2008-10-22 18:02:28
[ASP.NET 控制項實作 Day21] 實作控制項智慧標籤 https://ithelp.ithome.com.tw/articles/10012896?sc=rss.iron https://ithelp.ithome.com.tw/articles/10012896?sc=rss.iron 控制項通常會把常用屬性或功能顯示在智慧標籤中,提供使用者更簡便的快速設定,例如下圖為 GridView 的智慧。若要製作控制項的智慧標籤,需實作控制項的 ActionList 加入智慧標籤中要顯...]]> 控制項通常會把常用屬性或功能顯示在智慧標籤中,提供使用者更簡便的快速設定,例如下圖為 GridView 的智慧。若要製作控制項的智慧標籤,需實作控制項的 ActionList 加入智慧標籤中要顯示的項目,在本文將以 TDateEdit 控制項為例,進一步說明控制項的智慧標籤的實作方式。

程式碼下載:ASP.NET Server Control - Day21.rar

一、TDateEdit 控制項介紹
TDateEdit 控制項是筆者之前在部落格中實作的一個日期控制項,如下圖所示。它是結合 JavaScript 的 The Coolest DHTML Calendar 日期選擇器實作的控制項,我已將 TDateEdit 控制項的相關程式碼含入 Bee.Web.dll 組件中。TDateEdit 控制項的相關細節可以參考筆者部落格下面幾篇文章有進一步說明,本文將以 TDateEdit 控制項為例,只針對實作智慧標籤的部分做進一步說明。
日期控制項實作教學(1) - 結合 JavaScript
日期控制項實作教學(2) - PostBack 與 事件
TBDateEdit 日期控制項 - 1.0.0.0 版 (Open Source)

二、控制項加入智慧標籤
控制項要加入智慧標籤要實作控制項的 Designer,我們繼承 ControlDesigner 命名為 TBDateEditDesigner,然後覆寫 ActionLists 屬性,此屬性即是傳回智慧標籤中所包含的項目清單集合。在 ActionLists 屬性中一般會先加入父類別的 ActionLists 屬性,再加入自訂的 ActionList 類別,這樣才可以保留原父類別中智慧標籤的項目清單。

    ''' <summary>
    ''' TBDateEdit 控制項的設計模式行為。
    ''' </summary>
    Public Class TBDateEditDesigner
        Inherits System.Web.UI.Design.ControlDesigner

        ''' <summary>
        ''' 取得控制項設計工具的動作清單集合。
        ''' </summary>
        Public Overrides ReadOnly Property ActionLists() As DesignerActionListCollection
            Get
                Dim oActionLists As New DesignerActionListCollection()
                oActionLists.AddRange(MyBase.ActionLists)
                oActionLists.Add(New TBDateEditActionList(Me))
                Return oActionLists
            End Get
        End Property

    End Class

我們自訂的 ActionList 為 TBDateEditActionList 類別,它在智慧標籤呈現的項目清單如下圖所示,接下去我們會說明 TBDateEditActionList 類別的內容。

三、自訂智慧標籤面板的項目清單集合
DesignerActionList 類別定義用於建立智慧標籤面板的項目清單的基底類別,所以我們首先繼承 DesignerActionList 命名為 TBDateEditActionList。

    ''' <summary>
    ''' 定義 TBDateEdit 控制項智慧標籤面板的項目清單集合。
    ''' </summary>
    Public Class TBDateEditActionList
        Inherits DesignerActionList

        ''' <summary>
        ''' 建構函式。
        ''' </summary>
        Public Sub New(ByVal owner As ControlDesigner)
            MyBase.New(owner.Component)
        End Sub

    End Class

接下來要覆寫 GetSortedActionItems 方法,它會回傳 DesignerActionItemCollection 集合型別,此集合中會傳回要顯示在智慧標籤面板的項目清單集合,所以我們要在 DesignerActionItemCollection 集合中加入我們要呈現的項目清單內容。

        ''' <summary>
        ''' 傳回要顯示在智慧標籤面板的項目清單集合。
        ''' </summary>
        Public Overrides Function GetSortedActionItems() As System.ComponentModel.Design.DesignerActionItemCollection
            Dim oItems As New DesignerActionItemCollection()

            '在此加入智慧標籤面板的項目清單	           

            Return oItems
        End Function

step1. 在智慧標籤面板加入靜態標題項目
首先介紹 DesignerActionHeaderItem 類別,它是設定靜態標題項目,例如我們在 TDateEdit 的智慧標籤中加入「行為」、「外觀」二個標題項目,其中 DesignerActionHeaderItem 建構函式的 category 參數是群組名稱,我們可以將相關的項目歸類到同一個群組。

Dim oItems As New DesignerActionItemCollection()

oItems.Add(New DesignerActionHeaderItem("行為", "Behavior"))
oItems.Add(New DesignerActionHeaderItem("外觀", "Appearance"))

[超過字數限制,下一篇接續本文]

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/22/5749.aspx

]]>
jeff377 2008-10-22 18:01:29
[ASP.NET 控制項實作 Day20] 偵錯設計階段的程式碼 https://ithelp.ithome.com.tw/articles/10012807?sc=rss.iron https://ithelp.ithome.com.tw/articles/10012807?sc=rss.iron 上篇我們介紹了自訂 Designer 來輸出控制項設計階段的 HTML 碼,可是若你去對針 Designer 的程式碼下中斷點,你會發覺根本無法偵錯。因為程式在執行階段時期,根本不會執行 Des...]]> 上篇我們介紹了自訂 Designer 來輸出控制項設計階段的 HTML 碼,可是若你去對針 Designer 的程式碼下中斷點,你會發覺根本無法偵錯。因為程式在執行階段時期,根本不會執行 Designer 相關類別,所以你在 Designer 類別中下的中斷點完全無效;當然不可能這樣寫程式碼而用感覺去偵錯,本文將告訴你如何去偵錯設計階段的程式碼。
一、設計階段程式碼的錯誤
如果撰寫 Designer、Editor、ActionList 等設計階段的程式碼,當這些設計階段的程式碼發生錯誤,可能會發生設計頁面中控制項的錯誤情形,如下圖所示。因為控制項專案本身非啟動專案,在測試網站的設計頁面若控制項發生異常時會直接釋出錯誤,無法偵錯設計階段的程式碼;若真得要偵錯誤設計階段的問題,就要使用另一個 VS2008 來偵錯。

二、設定起始外部程式
要偵錯控制項設計階段的程式碼,要先將控制項專案(Bee.Web)設定為啟時專案。然後設定控制項專案的「屬性」,在「偵錯」頁籤中的起始動作選擇「起始外部程式」,選擇 VS2008 的執行檔位置,預設為 C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\devenv.exe。

三、開始偵錯設計階段程式碼
step1. 控制項專案開始偵錯
在設計階要偵錯的程式碼下中斷點,在控制項專案按下 F5 開始偵錯,這時會啟動另一個新的 VS2008 執行檔。

step2. 在新的 VS2008 的工具箱加入控制項
在新的 VS2008 中新增一個測試網站,在工具箱按右鍵執行「選擇項目」開啟「選擇工具箱項目」視窗,然後按「瀏覽」鈕按選擇控制項組件(Bee.Web.dll),將要偵錯的控制項加入工具箱中。


step3. 將控制項拖曳至頁面做設計動作
在新的 VS2008 中,將控制項拖曳至頁面,就會開始執行設計階段的程式碼,特定的設計動作就會執行到相對的設計階段程式碼,當執行到之前下的中斷點時就可以開始偵錯了。

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/21/5741.aspx

]]>
jeff377 2008-10-21 00:28:45
[ASP.NET 控制項實作 Day19] 控制項設計階段的外觀 https://ithelp.ithome.com.tw/articles/10012682?sc=rss.iron https://ithelp.ithome.com.tw/articles/10012682?sc=rss.iron 有一些控制項在執行階段是不會呈現,也就是說控制項本身在執行階段不會 Render 出 HTML 碼,例如 SqlDataSoruce、ScriptManager 這類控制項;那它們在設計階段的頁...]]> 有一些控制項在執行階段是不會呈現,也就是說控制項本身在執行階段不會 Render 出 HTML 碼,例如 SqlDataSoruce、ScriptManager 這類控制項;那它們在設計階段的頁面是如何呈現出來呢?本文將針對控制項設計階段的外觀做進一步的說明。
程式碼下載:ASP.NET Server Control - Day19.rar
一、控制項設計階段的 HTML 碼
Web 伺服器控制項的設計模式行為都是透過 ControlDesigner 來處理,連設計階段時控制項的外觀也是如此;控制項在設計階段與執行執行時呈現的外觀不一定相同,當然大部分會儘量一致,使其能所見即所得。
控制項在設計階段的 HTML 碼是透 ControlDesigner.GetDesignTimeHtml 方法來處理,在 ControlDesigner.GetDesignTimeHtml 預設會執行控制項的 RenderControl 方法,所以大部分的情況下設計階段與執行階段輸出的 HTML 碼會相同。當控制項的 Visible=False 時,執行階段是完全不會輸出 HTML 碼,可是在設計階段時會特別將控制項設定 Visible=True,使控制項能完整呈現。

ControlDesigner.GetDesignTimeHtml 方法

Public Overridable Function GetDesignTimeHtml() As String
    Dim writer As New StringWriter(CultureInfo.InvariantCulture)
    Dim writer2 As New DesignTimeHtmlTextWriter(writer)
    Dim errorDesignTimeHtml As String = Nothing
    Dim flag As Boolean = False
    Dim visible As Boolean = True
    Dim viewControl As Control = Nothing
    Try 
        viewControl = Me.ViewControl
        visible = viewControl.Visible
        If Not visible Then
            viewControl.Visible = True
            flag = Not Me.UsePreviewControl
        End If
        viewControl.RenderControl(writer2)
        errorDesignTimeHtml = writer.ToString
    Catch exception As Exception
        errorDesignTimeHtml = Me.GetErrorDesignTimeHtml(exception)
    Finally
        If flag Then
            viewControl.Visible = visible
        End If
    End Try
    If ((Not errorDesignTimeHtml Is Nothing) AndAlso (errorDesignTimeHtml.Length <> 0)) Then
        Return errorDesignTimeHtml
    End If
    Return Me.GetEmptyDesignTimeHtml
End Function

二、自訂控制項的 Designer
以 TBToolbar 為例,若我們在 RenderContents 方法未針對 Items.Count=0 做輸出 HTML 的處理,會發現未設定 Items 屬性時,在設計頁面上完全看不到 TBToolbar 控制項;像這種控制項設計階段的 HTML 碼,就可以自訂控制項的 Designer 來處理。

繼承 ControlDesigner 命名為 TBToolbarDesigner,這個類別是用來擴充 TBToolbar 控制項的設計模式行為。我們可以覆寫 GetDesignTimeHtml 方法,處理設計階段表示控制項的 HTML 標記,此方法回傳的 HTML 原始碼就是控制項呈現在設計頁面的外觀。所以我們可以在 TBToolbar.Items.Count=0 時,輸出一段提示的 HTML 碼,這樣當 TBToolbar 未設定 Items 屬性時一樣可以在設計頁面上呈現控制項。

    ''' <summary>
    ''' 擴充 TBToolbar 控制項的設計模式行為。
    ''' </summary>
    Public Class TBToolbarDesigner
        Inherits System.Web.UI.Design.ControlDesigner

        ''' <summary>
        ''' 用來在設計階段表示控制項的 HTML 標記。
        ''' </summary>
        Public Overrides Function GetDesignTimeHtml() As String
            Dim sHTML As String
            Dim oControl As TBToolbar

            oControl = CType(ViewControl, TBToolbar)
            If oControl.Items.Count = 0 Then
                sHTML = "<div style=""background-color: #C0C0C0; border:solid 1px; width:200px"">請設定 Items 屬性</div>"
            Else
                sHTML = MyBase.GetDesignTimeHtml()
            End If
            Return sHTML
        End Function

    End Class

在 TBToolbar 控制項套用 DesignerAttribute 設定自訂的 TBToolbarDesigner 類別。

    <Designer(GetType(TBToolbarDesigner))> _
    Public Class TBToolbar
        Inherits WebControl

    End Class

重建控制項組件,切換到設計頁面上的看 TBToolbar 控制項未設定 Items 屬性時的外觀,就是我們在 TBToolbarDesigner.GetDesignTimeHtml 方法回傳的 HTML 碼。

如果你覺得上述設計階段的控制項有點太陽春,我們也可以輸出類似 SqlDataSource 控制項的外觀,將未設定 Items 屬性時輸出 HTML 改呼叫 CreatePlaceHolderDesignTimeHtml 方法。

            If oControl.Items.Count = 0 Then
                sHTML = MyBase.CreatePlaceHolderDesignTimeHtml("請設定 Items 屬性")
            Else
                sHTML = MyBase.GetDesignTimeHtml()
            End If

來看一下這樣修改後的結果,是不是比較專業一點了呢。

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/20/5726.aspx

]]>
jeff377 2008-10-20 02:25:29
[ASP.NET 控制項實作 Day18] 修改集合屬性編輯器 https://ithelp.ithome.com.tw/articles/10012636?sc=rss.iron https://ithelp.ithome.com.tw/articles/10012636?sc=rss.iron 上篇我們實作了「集合屬性包含不同型別的成員」,不過若有去使用屬性視窗編輯 TBToolbar 的 Items 屬性,你會發覺這個集合屬性編輯器無法加入我們定義不同型別的成員,只能加入最原始的集合...]]> 上篇我們實作了「集合屬性包含不同型別的成員」,不過若有去使用屬性視窗編輯 TBToolbar 的 Items 屬性,你會發覺這個集合屬性編輯器無法加入我們定義不同型別的成員,只能加入最原始的集合成員。是不是只能在 aspx 程式碼中手動去輸入呢?當然不需要這樣人工作業,只要改掉集合屬性編輯器就可以達到我們的需求,本文將介紹修改集合屬性編輯器的相關作法。
程式碼下載:ASP.NET Server Control - Day18.rar

一、自訂集合屬性編輯器
我們先看一下 TBToolbar.Items 屬性套用的 EditorAttribute,它是使用 CollectionEditor 類別來當作屬性編輯器,所以我們就是要繼承 CollectionEditor 類別下來修改成自訂的屬性編輯器。

< _
Editor(GetType(CollectionEditor), GetType(UITypeEditor)) _
> _
Public ReadOnly Property Items() As TBToolbarItemCollection

新增一個繼承 CollectionEditor 的 TBToolbarItemCollectionEditor 類別,並加入建構函式。此類別屬於 Bee.WebControls.Design 命名空間,通常我們會把設計階段使用的類別歸類到特別的命名空間便於管理及使用。

Namespace WebControls.Design
    Public Class TBToolbarItemCollectionEditor
        Inherits CollectionEditor

        ''' <summary>
        ''' 建構函式。
        ''' </summary>
        ''' <param name="Type">型別。</param>
        Public Sub New(ByVal Type As Type)
            MyBase.New(Type)
        End Sub

    End Class
End Namespace

我們可以先修改 Items 屬性的 EditorAttribute,看看我們自訂的 TBToolbarItemCollectionEditor 是否能正常運作。不過這個屬性編輯器跟原本的沒什麼差異,因為我們只是單純繼承下來沒做任何異動,接下去我們就要開始來修改這個屬性編輯器。

< _
Editor(GetType(TBToolbarItemCollectionEditor), GetType(UITypeEditor)) _
> _
Public ReadOnly Property Items() As TBToolbarItemCollection

二、加入不同型別的集合成員
再來我們就要著手修改集合屬性編輯器,讓它可以加入不同型別的集合成員。覆寫 CollectionEditor 的 CanSelectMultipleInstances 方法傳回 True,這個方法是設定 CollectionEditor 是否允許加入多種不同型別的集合成員。

        Protected Overrides Function CanSelectMultipleInstances() As Boolean
            Return True
        End Function

再來覆寫 CreateNewItemTypes 方法,這個方法是取得這個集合編輯器可包含的資料型別,將集合可包含的資料型別以陣列傳回。

        ''' <summary>
        ''' 取得這個集合編輯器可包含的資料型別。
        ''' </summary>
        ''' <returns>這個集合可包含的資料型別陣列。</returns>
        Protected Overrides Function CreateNewItemTypes() As System.Type()
            Dim ItemTypes(2) As System.Type
            ItemTypes(0) = GetType(TBToolbarButton)
            ItemTypes(1) = GetType(TBToolbarTextbox)
            ItemTypes(2) = GetType(TBToolbarLabel)
            Return ItemTypes
        End Function

重建控制項組件,使用 Items 的集合屬性編輯器,就可以發現「加入」鈕的下拉清單就會出現我們所定義的三種型別的集合成員,如此可以加入不同型別的成員了。

三、設定清單項目的顯示文字
在成員清單項目中預設會顯示成員含命名空間的型別,若我們要修改成比較有識別的顯示文字,例如 TBToolbarButton(Key=Add) 可以顯示「按鈕-Add」,這時可以覆寫 GetDisplayText 方法來設定清單項目的顯示文字。

        ''' <summary>
        ''' 取出指定清單項目的顯示文字。
        ''' </summary>
        Protected Overrides Function GetDisplayText(ByVal value As Object) As String
            If TypeOf value Is TBToolbarButton Then
                Return String.Format("按鈕 - {0}", CType(value, TBToolbarButton).Key)
            ElseIf TypeOf value Is TBToolbarTextbox Then
                Return "文字框"
            ElseIf TypeOf value Is TBToolbarLabel Then
                Return String.Format("標籤 - {0}", CType(value, TBToolbarLabel).Text)
            Else
                Return value.GetType.Name
            End If
        End Function

四、集合編輯器的屬性視窗的屬性描述
一般屬性視窗下面都會有屬性描述,可以集合屬性編輯器中的屬性視窗下面竟沒有屬性描述。若我們要讓它的屬性描述可以顯示,可以覆寫 CreateCollectionForm 方法,取得集合屬性編輯表單,再去設定表單上的 PropertyGrid.HelpVisible
= True 即可。

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/19/5721.aspx

]]>
jeff377 2008-10-19 00:13:21
[ASP.NET 控制項實作 Day17] 集合屬性包含不同型別的成員 https://ithelp.ithome.com.tw/articles/10012600?sc=rss.iron https://ithelp.ithome.com.tw/articles/10012600?sc=rss.iron 我們知道在 GridView 的 Columns 集合屬性中,可以包含不同型別的欄位,如 BoundFIeld、CheckBoxField、HyperLinkField ...等不同型別的欄位。...]]> 我們知道在 GridView 的 Columns 集合屬性中,可以包含不同型別的欄位,如 BoundFIeld、CheckBoxField、HyperLinkField ...等不同型別的欄位。如果我們希望工具列中不只包含按鈕,可以包含其他不同類型的子控制項,那該怎麼做呢?本文就以上篇中的 TBToolbar 控制項為案例,讓 Items 集合屬性可以加入 Button、TextBox、Label ...等不同的子控制項。
程式碼下載:ASP.NET Server Control - Day17.rar
一、不同型別的集合成員
我們的需求是讓工具列可以加入 Button、TextBox、Label 三種子控制項,所以繼承原來的 TBToolbarItem (只保留 Enabled 屬性),新增了 TBToolbarButton、TBToolbarTextbox、TBToolbarLabel 三個類別。

這些新增的成員類別都是繼承至 TBToolbarItem,所以在 aspx 程式碼中,手動輸入 Items 的成員時,就會列出這幾種定義的成員型別。

二、建立不同型別集合成員的子控制項
因為 Items 屬性的成員具不同型別,所以我們要改寫 RenderContents 方法,判斷成員型別來建立對應類型的子控制項。若為 TBToolbarButton 型別建立 Button 控制項、若為 TBToolbarTextbox 型別則建立 TextBox 控制項、若為 TBToolbarLabel 型別則建立 Label 控制項。其中 TBToolbarButton 建立的控制項為 TBButton,這個控制項是我們在「 [ASP.NET 控制項實作 Day3] 擴展現有伺服器控制項功能」一文中實作的具詢問訊息的按鈕控制項。

        ''' <summary>
        ''' 覆寫 RenderContents 方法。
        ''' </summary>
        Protected Overrides Sub RenderContents(ByVal writer As System.Web.UI.HtmlTextWriter)
            Dim oItem As TBToolbarItem
            Dim oControl As Control

            For Each oItem In Me.Items
                If TypeOf oItem Is TBToolbarButton Then
                    '建立 Button 控制項
                    oControl = CreateToolbarButton(CType(oItem, TBToolbarButton))
                ElseIf TypeOf oItem Is TBToolbarTextbox Then
                    '建立 Textbox 控制項
                    oControl = CreateToolbarTextbox(CType(oItem, TBToolbarTextbox))
                Else
                    '建立 Label 控制項
                    oControl = CreateToolbarLabel(CType(oItem, TBToolbarLabel))
                End If
                Me.Controls.Add(oControl)
            Next

            MyBase.RenderContents(writer)
        End Sub

        ''' <summary>
        ''' 建立工具列按鈕。
        ''' </summary>
        Private Function CreateToolbarButton(ByVal Item As TBToolbarButton) As Control
            Dim oButton As TBButton
            Dim sScript As String

            oButton = New TBButton()
            oButton.Text = Item.Text
            oButton.Enabled = Item.Enabled
            oButton.ID = Item.Key
            oButton.ConfirmMessage = Item.ConfirmMessage
            sScript = Me.Page.ClientScript.GetPostBackEventReference(Me, Item.Key)
            oButton.OnClientClick = sScript

            Return oButton
        End Function

        ''' <summary>
        ''' 建立工具列文字框。
        ''' </summary>
        Private Function CreateToolbarTextbox(ByVal Item As TBToolbarTextbox) As Control
            Dim oTextBox As TextBox

            oTextBox = New TextBox
            Return oTextBox
        End Function

        ''' <summary>
        ''' 建立工具列標籤。
        ''' </summary>
        Private Function CreateToolbarLabel(ByVal Item As TBToolbarLabel) As Control
            Dim oLabel As Label

            oLabel = New Label()
            oLabel.Text = Item.Text
            Return oLabel
        End Function

我們手動在 aspx 程式碼中輸入不同型別的成員,TBToolbar 控制項就會呈現對應的子控制項。

三、執行程式
執行程式,就可以在瀏覽器看到呈現的工具列,當按下「刪除」時也會出現我們定義的詢問訊息。

輸出的 HTML 碼如下

<span id="TBToolbar1">
<input type="submit" name="TBToolbar1$Add" value="新增" onclick="__doPostBack('TBToolbar1','Add');" id="TBToolbar1_Add" />
<input type="submit" name="TBToolbar1$Edit" value="修改" onclick="__doPostBack('TBToolbar1','Edit');" id="TBToolbar1_Edit" />
<input type="submit" name="TBToolbar1$Delete" value="刪除" onclick="if (confirm('確定刪除嗎?')==false) {return false;}__doPostBack('TBToolbar1','Delete');" id="TBToolbar1_Delete" />
<span>關鍵字</span>
<input name="TBToolbar1$ctl01" type="text" />
<input type="submit" name="TBToolbar1$Search" value="搜尋" onclick="__doPostBack('TBToolbar1','Search');" id="TBToolbar1_Search" />
</span>

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/18/5718.aspx

]]>
jeff377 2008-10-18 00:05:57
[ASP.NET 控制項實作 Day16] 繼承 WebControl 實作 Toolbar 控制項 https://ithelp.ithome.com.tw/articles/10012507?sc=rss.iron https://ithelp.ithome.com.tw/articles/10012507?sc=rss.iron 前面我們討論過「繼承 CompositeControl 實作 Toolbar 控制項」,本文將繼承 WebControl 來實作同樣功能的 Toolbar 控制項,用不同的方式來實作同一個控制項...]]> 前面我們討論過「繼承 CompositeControl 實作 Toolbar 控制項」,本文將繼承 WebControl 來實作同樣功能的 Toolbar 控制項,用不同的方式來實作同一個控制項,進而比較二者之間的差異。
程式碼下載:ASP.NET Server Control - Day16.rar

一、繼承 WebControl 實作 TBToolbar 控制項
step1. 新增繼承 WebControl 的 TBToolbar 控制項
新增繼承 WebControl 的 TBToolbar 控制項,你也可以直接原修改原 TBToolbar 控制項,繼承對象由 CompositeControl 更改為 WebControl即可。跟之前一樣在 TBToolbar 控制項加入 Items 屬性及 Click 事件。
另外 TBToolbar 控制項需實作 INamingContainer 界面,此界面很特殊沒有任何屬性或方法,INamingContainer 界面的作用是子控制項的 ClientID 會在前面加上父控制項的 ClickID,使每個子控制項有唯一的 ClientID。

step2. 建立工具列按鈕集合
覆寫 RenderContents 方法,將原本 TBToolbar (複合控制項) 的 CreateChildControls 方法中建立工具列按鈕程式碼,搬移至 RenderContents 方法即可。

        Private Sub ButtonClickEventHandler(ByVal sender As Object, ByVal e As EventArgs)
            Dim oButton As Button
            Dim oEventArgs As ClickEventArgs

            oButton = CType(sender, Button)
            oEventArgs = New ClickEventArgs()
            oEventArgs.Key = oButton.ID
            OnClick(oEventArgs)
        End Sub

        ''' <summary>
        ''' 覆寫 RenderContents 方法。
        ''' </summary>
        Protected Overrides Sub RenderContents(ByVal writer As System.Web.UI.HtmlTextWriter)
            Dim oItem As TBToolbarItem
            Dim oButton As Button

            For Each oItem In Me.Items
                oButton = New Button()
                oButton.Text = oItem.Text
                oButton.Enabled = oItem.Enabled
                oButton.ID = oItem.Key
                AddHandler oButton.Click, AddressOf ButtonClickEventHandler
                Me.Controls.Add(oButton)
            Next

            If Me.Items.Count = 0 AndAlso Me.DesignMode Then
                oButton = New Button()
                oButton.Text = "請設定 Items 屬性。"
                Me.Controls.Add(oButton)
            End If

            MyBase.RenderContents(writer)
        End Sub

上述的直接搬移過來的程式碼還有個問題,就是原來的使用 AddHandler 來處理按鈕事件的方式變成沒有作用了?因為現在不是複合式控制項,當前端的按鈕 PostBack 傳回伺服端時,TBToolbar 不會事先建立子控制槓,所以機制會找不到原來產生的按鈕,也就無法使用 AddHandler 來處理事件了。

AddHandler oButton.Click, AddressOf ButtonClickEventHandler

step3. 處理 Click 事件
因為不能使用 AddHandler 來處理按鈕事件,所以我們就自行使用 Page.ClientScript.GetPostBackEventReference 方法來產生 PostBack 動作的用戶端指令碼,按鈕的 OnClientClick 去執行 PostBack 的動作。

            For Each oItem In Me.Items
                oButton = New Button()
                oButton.Text = oItem.Text
                oButton.Enabled = oItem.Enabled
                oButton.ID = oItem.Key
                sScript = Me.Page.ClientScript.GetPostBackEventReference(Me, oItem.Key)
                oButton.OnClientClick = sScript
                Me.Controls.Add(oButton)
            Next

TBToolar 控制項輸出的 HTML 碼如下

<span id="TBToolbar1">
<input type="submit" name="TBToolbar1$Add" value="新增" onclick="__doPostBack('TBToolbar1','Add');" 

id="TBToolbar1_Add" />
<input type="submit" name="TBToolbar1$Edit" value="修改" onclick="__doPostBack('TBToolbar1','Edit');" 

id="TBToolbar1_Edit" />
<input type="submit" name="TBToolbar1$Delete" value="刪除" onclick="__doPostBack('TBToolbar1','Delete');" 

id="TBToolbar1_Delete" />
</span>

要自行處理 PostBack 的事件,需實作 IPostBackEventHandler 介面,在 RaisePostBackEvent 方法來引發 TBToolbar 的 Click 事件。

    Public Class TBToolbar
        Inherits WebControl
        Implements INamingContainer
        Implements IPostBackEventHandler

        Public Sub RaisePostBackEvent(ByVal eventArgument As String) Implements 

System.Web.UI.IPostBackEventHandler.RaisePostBackEvent
            Dim oEventArgs As ClickEventArgs

            oEventArgs = New ClickEventArgs()
            oEventArgs.Key = eventArgument
            Me.OnClick(oEventArgs)
        End Sub

    End Class

二、測試程式
在測試頁面上放置 TBToolbar 控制項,在 Click 事件撰寫測試程式碼。

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/17/5706.aspx

]]>
jeff377 2008-10-17 00:05:40
[ASP.NET 控制項實作 Day15] 複合控制項隱藏的問題 https://ithelp.ithome.com.tw/articles/10012425?sc=rss.iron https://ithelp.ithome.com.tw/articles/10012425?sc=rss.iron 上一篇我們使用複合控制項(繼承 CompositeControl)的方式來實作 TBToolbar 控制項,本文將針對複合控制項做一些測試,說明在使用複合控制項要注意的一些問題。
程...]]>
上一篇我們使用複合控制項(繼承 CompositeControl)的方式來實作 TBToolbar 控制項,本文將針對複合控制項做一些測試,說明在使用複合控制項要注意的一些問題。
程式碼下載:ASP.NET Server Control - Day15.rar
一、複合控制項建立子控制項的時機
還記得我們之前介紹複合控制項時有談到 CompositeControl 類別會確保我們存取子控制項時,它的子控制項一定會事先建立;也就是當我們使用 Controls 屬性去存取子控制項時,一定會執行 CreateChildControls 方法,以確保子控制項事先被建立。我們看一下 CompositeControl 類別的 Controls 屬性的寫法就可以了解其中的原由,在存取 CompositeControl.Controls 屬性時,它會先執行 Control.EnsureChildControls 方法;而 EnsureChildControls 方法會去判斷子控制項是否已建立,若未建立會去執行 CreateChildControls 方法,這也就是為什麼 CompositeControl 有辨法確保子控制項事先被建立的原因。

CompositeControl.Controls 屬性如下

Public Overrides ReadOnly Property Controls As ControlCollection
    Get
        Me.EnsureChildControls
        Return MyBase.Controls
    End Get
End Property

Control.EnsureChildControls 方法如下

Protected Overridable Sub EnsureChildControls()
    If (Not Me.ChildControlsCreated AndAlso Not Me.flags.Item(&H100)) Then
        Me.flags.Set(&H100)
        Try 
            Me.ResolveAdapter
            If (Not Me._adapter Is Nothing) Then
                Me._adapter.CreateChildControls
            Else
                Me.CreateChildControls
            End If
            Me.ChildControlsCreated = True
        Finally
            Me.flags.Clear(&H100)
        End Try
    End If
End Sub

二、複合控制項隱藏的問題
我們以上篇的 TBToolbar 控制項為例,撰寫一些測試案例來說明複合控制項的問題。在撰寫測試案例之前,我們先修改一下 TBToolbar 控制項,覆寫 LoadViewState 及 SaveViewState 方法,將 Items 屬性儲存於 ViewState 中以維持狀態。

在測試頁面上放置「測試一」、「測試二」、「PostBack」三個按鈕,這三個按鈕的動作如下。
「測試一」按鈕:在工具列直接新增一個按鈕。
「測試二」按鈕:先使用 FindControl 取得工具列的按鈕,然後在在工具列再新增一個按鈕。
「PostBack」按鈕:單純執行 PostBack,不撰寫程式碼。

三個按鈕的程式碼如下所示。

    Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles 

Button1.Click
        Dim oItem As TBToolbarItem

        '加入新按鈕
        oItem = New TBToolbarItem()
        oItem.Text = "新按鈕"
        oItem.Key = "NewButton"
        TBToolbar1.Items.Add(oItem)
        Me.Response.Write("「測試一」按鈕")
    End Sub

    Protected Sub Button2_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles 

Button2.Click
        Dim oItem As TBToolbarItem
        Dim oButton As Button

        '先執行 FindControl 去取得 ID="Add" 的按鈕
        oButton = TBToolbar1.FindControl("Add")

        '再加入新按鈕
        oItem = New TBToolbarItem()
        oItem.Text = "新按鈕"
        oItem.Key = "NewButton"
        TBToolbar1.Items.Add(oItem)
        Me.Response.Write("「測試二」按鈕")
    End Sub

    Protected Sub Button3_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles 

Button3.Click
        '單純 PostBack,無程式碼
        Me.Response.Write("「PostBack」按鈕")
    End Sub

案例一:執行「測試一」按鈕,在工具列直接新增一個按鈕。
當按下「測試一」按鈕時,工具列可以正常加入我們新增的按鈕。

案例二:執行「測試二」按鈕,先使用 FindControl 取得工具列的按鈕,然後在在工具列再新增一個按鈕。
重新執行程式,當按下「測試二」按鈕時,你會發現奇怪的現象,工具列竟然沒有加入我們新增的按鈕?

此時再按下「PostBack」按鈕,工具列才會出現我們剛剛加入的按鈕。

為什麼會發生這種怪現象呢?其實原因很簡單,因為 FindControl 時會去存取 Controls 屬性,而這時子控制項已經被建立了;而之前再用 Items 屬性加入新按鈕,它已經不會在重建子控制項,導致第一時間沒有加入新按鈕。不過 Items 屬性會被存在 ViewState 中,所以當執行「PostBack」按鈕時,就會出現我們剛剛新增的按鈕。

三、解決方式
要解決上述「測試二」的問題,只要覆寫 TBToolbar 控制項的 Render 方法,在 Render 前執行 RecreateChildControls 方法,強制重建子控制項。

        ''' <summary>
        ''' 覆寫 Render 方法。
        ''' </summary>
        Protected Overrides Sub Render(ByVal writer As System.Web.UI.HtmlTextWriter)
            Me.RecreateChildControls()
            MyBase.Render(writer)
        End Sub

再一次執行「測試二」的動作,就會發現執行結果就會正常了。

四、結語
在複合控制項的 Render 前執行 RecreateChildControls 方法可以強制重建子控制項,可是這樣又會引發另一個問題,那就是當直接存取子控制項去修改子控制項的屬性後,一旦在 Render 又重建子控制項,那之前設定子控制項狀態又被全部重建了,所以需特別注意有這樣的情形。另外複合控制項有可能重覆執行建立子控制的動作,在執行效能上也比較不佳。

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/16/5695.aspx

]]>
jeff377 2008-10-16 00:14:12
[ASP.NET 控制項實作 Day14] 繼承 CompositeControl 實作 Toolbar 控制項 https://ithelp.ithome.com.tw/articles/10012339?sc=rss.iron https://ithelp.ithome.com.tw/articles/10012339?sc=rss.iron 之前我們簡單介紹過繼承 CompositeControl 來實作複合控制項,在本文我們將以 Toolbar 控制項為例,以複合控制項的作法(繼承 CompositeControl )來實作 To...]]> 之前我們簡單介紹過繼承 CompositeControl 來實作複合控制項,在本文我們將以 Toolbar 控制項為例,以複合控制項的作法(繼承 CompositeControl )來實作 Toolbar 控制項,此工具列控制項包含 Items 屬性來描述工具列項目集合,依 Items 屬性的設定來建立工具列按鈕,另外包含 Click 事件可以得知使用按了那個按鈕。
程式碼下載:ASP.NET Server Control - Day14.rar
一、工具列項目集合類別
工具列包含多個按鈕,新增 TBToolbarItem 類別來描述工具列項目,TBToolbarItem 類別包含 Key、Text、Enabled 三個屬性;而 TBToolbarItemCollection 為 TBToolbarItem 的集合類別來描述工具列按鈕集合。

二、實作 TBToolbar 控制項
step1. 新增繼承 CompositeControl 的 TBToolbar 控制項

    < _
    Description("工具列控制項。"), _
    ParseChildren(True, "Items"), _
    ToolboxData("<{0}:TBToolbar runat=server ></{0}:TBToolbar>") _
    > _
    Public Class TBToolbar
        Inherits CompositeControl
    End Class 

step2. 新增 Items 屬性,描述工具列項目集合

        ''' <summary>
        ''' 工具列項目集合。
        ''' </summary>
        < _
        Description("工具列項目集合。"), _
        PersistenceMode(PersistenceMode.InnerProperty), _
        DesignerSerializationVisibility(DesignerSerializationVisibility.Content), _
        Editor(GetType(CollectionEditor), GetType(UITypeEditor)) _
        > _
        Public ReadOnly Property Items() As TBToolbarItemCollection
            Get
                If FItems Is Nothing Then
                    FItems = New TBToolbarItemCollection()
                End If
                Return FItems
            End Get
        End Property

step3. 新增 Click 事件
TBToolbar 類別新增 Click 事件,當按下按鈕時會引發 Click 事件,由 Click 的事件引數 e.Key 可以得知使用者按了那個按鈕。

        ''' <summary>
        ''' Click 事件引數。
        ''' </summary>
        Public Class ClickEventArgs
            Inherits System.EventArgs
            Private FKey As String = String.Empty

            ''' <summary>
            ''' 項目鍵值。
            ''' </summary>
            Public Property Key() As String
                Get
                    Return FKey
                End Get
                Set(ByVal value As String)
                    FKey = value
                End Set
            End Property
        End Class

        ''' <summary>
        ''' 按下工具列按鈕所引發的事件。
        ''' </summary>
        < _
        Description("按下工具列按鈕所引發的事件。") _
        > _
        Public Event Click(ByVal sender As Object, ByVal e As ClickEventArgs)

        ''' <summary>
        ''' 引發 Click 事件。
        ''' </summary>
        Protected Overridable Sub OnClick(ByVal e As ClickEventArgs)
            RaiseEvent Click(Me, e)
        End Sub

step4. 建立工具列按鈕集合
覆寫 CreateChildControls 方法,依 Items 屬性的設定,來建立工具列中的按鈕集合。每個按鈕的 Click 事件都導向 ButtonClickEventHandler 方法,來處理所有按鈕的 Click 動作,並引發 TBToolbar 的 Click 事件。

        Private Sub ButtonClickEventHandler(ByVal sender As Object, ByVal e As EventArgs)
            Dim oButton As Button
            Dim oEventArgs As ClickEventArgs

            oButton = CType(sender, Button)
            oEventArgs = New ClickEventArgs()
            oEventArgs.Key = oButton.ID
            OnClick(oEventArgs)
        End Sub

        ''' <summary>
        ''' 建立子控制項。
        ''' </summary>
        Protected Overrides Sub CreateChildControls()
            Dim oItem As TBToolbarItem
            Dim oButton As Button

            For Each oItem In Me.Items
                oButton = New Button()
                oButton.Text = oItem.Text
                oButton.Enabled = oItem.Enabled
                oButton.ID = oItem.Key
                AddHandler oButton.Click, AddressOf ButtonClickEventHandler
                Me.Controls.Add(oButton)
            Next
            MyBase.CreateChildControls()
        End Sub

三、測試程式
在頁面拖曳 TBToolbar 控制項,並設定 Items 屬性,如入新增、修改、刪除三個按鈕。

在 TBToolbar 控制項的 Click 事件加入測試程式碼,輸出引發 Click 事件的 e.Key。

    Protected Sub TBToolbar1_Click(ByVal sender As Object, ByVal e As Bee.Web.WebControls.TBToolbar.ClickEventArgs) Handles TBToolbar1.Click
        Me.Response.Write(String.Format("您按了 {0}", e.Key))
    End Sub

執行程式,當按了工具列上的按鈕時,就會引發 Click 事件,並輸出該按鈕對應的 Key。

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/15/5687.aspx

]]>
jeff377 2008-10-15 00:13:50
[ASP.NET 控制項實作 Day13] Flash 控制項 https://ithelp.ithome.com.tw/articles/10012267?sc=rss.iron https://ithelp.ithome.com.tw/articles/10012267?sc=rss.iron Flash 也是網頁常用的 ActiveX 插件,在本文中將繼承 TBActiveX 下來撰寫 TBFlash 控制項,用來輸出網頁套用 Flash 的相關 HTML 碼。
程式碼下...]]>
Flash 也是網頁常用的 ActiveX 插件,在本文中將繼承 TBActiveX 下來撰寫 TBFlash 控制項,用來輸出網頁套用 Flash 的相關 HTML 碼。
程式碼下載:ASP.NET Server Control - Day13.rar

一、網頁 Flash 的原始 HTML 碼
我們先觀查在網頁中套用 Flash 插件的原始 HTML 碼,以點部落首頁抬頭的 Flash 原始碼為例如下,其中 <object> tag 的 codebase attribute 是指 Flash 插件的下載位置及版本。

<object id="ShockwaveFlash2" height="90" width="728" 
  codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,29,0" 
  classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000">
<param value="http://files.dotblogs.com.tw/dotjum/ad/debug.swf" name="movie"/>
<param value="high" name="quality"/>
<param value="#000000" name="bgcolor"/>
<embed height="90" width="728" type="application/x-shockwave-flash" 
  pluginspage="http://www.macromedia.com/go/getflashplayer" quality="high" 
  src="http://files.dotblogs.com.tw/dotjum/ad/debug.swf"/>
</object>

在 <object> tag 中必要的 attribute 為 classid、codebase、movie、width、height,而 <embed> tag 的必要 attribute 為 src、pluginspage、width、height,其他選擇性的 attribute 可參閱以下網頁。

Flash OBJECT and EMBED tag attributes
http://kb.adobe.com/selfservice/viewContent.do?externalId=tn\_12701

二、實作 TFlash 控制項
了解 Flash 的原始 HTML 碼後,我們就可以開始著手撰寫 TBFlash 控制項,想辨法來輸出所需要的 HTML 碼。

step1. 新增 TBFlash 控制項繼承至 TBActiveX
我們先在 TBActiveX 控制項新增一個 CodeBase 屬性,用來設定 ActiveX 插入的下載位置及版本,然後新增 TBFlash 控制項繼承至 TBActiveX,並在建構函式中設定 MyBase.ClassId 及 MyBase.CodeBase 屬性。

    Public Class TBFlash
        Inherits TBActiveX

        ''' <summary>
        ''' 建構函式。
        ''' </summary>
        Sub New()
            MyBase.ClassId = "D27CDB6E-AE6D-11CF-96B8-444553540000"
            MyBase.CodeBase = "http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,29,0"
        End Sub
    End Class 

step2. 加入相關屬性
在 TBFlash 加入 MovieUrl 及 Quality 屬性,MovieUrl 為 Flash 檔案來源,Quality 為影音品質。

step3. 輸出 Flash 相關參數
覆寫 CreateChildControls 方法,輸出 MovieUrl 及 Quality 屬性對應的參數,以及在 Params 集合屬性設定的參數。

        ''' <summary>
        ''' 加入 MediaPlayer 參數。
        ''' </summary>
        ''' <param name="Name">參數名稱。</param>
        ''' <param name="Value">參數值。</param>
        Private Sub AddParam(ByVal Name As String, ByVal Value As String)
            Dim oParam As TBActiveXParam

            oParam = New TBActiveXParam(Name, Value)
            Me.Params.Add(oParam)
        End Sub

        ''' <summary>
        ''' 建立 Embed 標記。
        ''' </summary>
        Private Function CreateEmbed() As HtmlControls.HtmlGenericControl
            Dim oEmbed As HtmlControls.HtmlGenericControl
            Dim oParam As TBActiveXParam

            oEmbed = New HtmlControls.HtmlGenericControl()
            oEmbed.TagName = "embed"
            oEmbed.Attributes("src") = Me.ResolveClientUrl(Me.MovieUrl)
            oEmbed.Attributes("pluginspage") = "http://www.macromedia.com/go/getflashplayer"
            oEmbed.Attributes("height") = Me.Height.ToString
            oEmbed.Attributes("width") = Me.Width.ToString

            'Embed 的 Attributes 加入 Params 集合屬性的設定
            For Each oParam In Me.Params
                If oParam.Name <> "movie" Then
                    oEmbed.Attributes(oParam.Name) = oParam.Value
                End If
            Next
            Return oEmbed
        End Function

        ''' <summary>
        ''' 建立子控制項。
        ''' </summary>
        Protected Overrides Sub CreateChildControls()
            Dim oEmbed As HtmlControls.HtmlGenericControl

            '加入 movie 參數
            AddParam("movie", Me.ResolveClientUrl(Me.MovieUrl))

            '加入 quality 參數
            If Me.Quality <> EQuality.NotSet Then
                AddParam("quality", Me.Quality.ToString.ToLower)
            End If

            MyBase.CreateChildControls()

            oEmbed = CreateEmbed()
            Me.Controls.Add(oEmbed)
        End Sub

三、測試程式
在頁面拖曳 TBFlash 控制項,設定 MovieUrl 及 Quality 屬性,若有需要加入其他參數,可自行設定 Params 集合屬性。執行程式就可以在頁面上看到呈現出來的 Flash。

        <bee:TBFlash ID="TBFlash1" runat="server" Height="90px" 
            MovieUrl="http://files.dotblogs.com.tw/dotjum/ad/debug.swf" Quality="High" 
            Width="728px">
        </bee:TBFlash>

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/14/5674.aspx

]]>
jeff377 2008-10-14 00:16:30
[ASP.NET 控制項實作 Day12] 繼承 TBActiveX 重新改寫 TBMediaPlayer 控制項 https://ithelp.ithome.com.tw/articles/10012196?sc=rss.iron https://ithelp.ithome.com.tw/articles/10012196?sc=rss.iron 上篇介紹的 TBActiveX 控制項,它可以支援網頁 Media Player 的設定,這跟前面提及的 TBMediaPlayer 功能相同。TBActiveX 具有網頁設定 ActiveX ...]]> 上篇介紹的 TBActiveX 控制項,它可以支援網頁 Media Player 的設定,這跟前面提及的 TBMediaPlayer 功能相同。TBActiveX 具有網頁設定 ActiveX 通用屬性,所以 TBMediaPlayer 基本上是可以由 TBActiveX 繼承下來,再加入 Media Player 特有的屬性即可。本文將原來的 TBMediaPlayer 控制項,繼承的父類別由 WebControl 改為 TBActiveX 類別,重新改寫 TBMediaPlayer 控制項。
程式碼下載:ASP.NET Server Control - Day12.rar

一、改寫 TBMediaPlayer 控制項
TBMediaPlayer 控制項原本是繼承 WebControl,現改繼承對象為 TBActiveX,來重新改寫 TBMediaPlayer 控制項。

step1. TBMediaPlayer 繼承至 TBActiveX
新增 TBMediaPlayer 控制項,繼承至 TBActiveX,並在建構函式設定 Media Player ActiveX 的 ClassId。

    Public Class TBMediaPlayer
        Inherits TBActiveX

        ''' <summary>
        ''' 建構函式。
        ''' </summary>
        Sub New()
            MyBase.ClassId = "6BF52A52-394A-11D3-B153-00C04F79FAA6"
        End Sub
    End Class

step2. 加入相關屬性
跟原來的 TBMediaPlayer 控制項一樣,加入 Url、AutoStart、UIMode 三個屬性,可視情形加入需要設定的屬性。

step3. 加入 Media Player 參數
覆寫 CreateChildControls 方法,動態依屬性設定在 Params 集合屬性加入參數。雖然 TBMediaPlayer 控制項目前只有 Url、AutoStart、UIMode 三個屬性,但是父類別 TBActiveX 具有 Params 集合屬性,所以開發人員可以視需求加入其他未定義的參數。

        ''' <summary>
        ''' 加入 MediaPlayer 參數。
        ''' </summary>
        ''' <param name="Name">參數名稱。</param>
        ''' <param name="Value">參數值。</param>
        Private Sub AddParam(ByVal Name As String, ByVal Value As String)
            Dim oParam As TBActiveXParam

            oParam = New TBActiveXParam(Name, Value)
            Me.Params.Add(oParam)
        End Sub

        ''' <summary>
        ''' 覆寫 CreateChildControls 方法。
        ''' </summary>
        Protected Overrides Sub CreateChildControls()
            '加入 Url 參數
            If Me.Url <> String.Empty Then
                AddParam("URL", Me.ResolveClientUrl(Me.Url))
            End If
            '加入 autoStart 參數
            If Me.AutoStart Then
                AddParam("autoStart", "true")
            End If
            '加入 uiMode 參數
            If Me.UIMode <> EUIMode.NotSet Then
                AddParam("uiMode", Me.UIMode.ToString)
            End If
            MyBase.CreateChildControls()
        End Sub

二、執行程式
在頁面拖曳 TBMediaPlayer 控制項,設定 Url、AutoStart、UIMode 屬性,若有需要加入其他參數,可自行設定 Params 集合屬性。執行程式就可以在頁面上看到呈現出來的 Media Player。

        <bee:TBMediaPlayer ID="TBMediaPlayer1" runat="server" AutoStart="True" 
            Height="249px" Url="D:\Movie_01.wmv" Width="250px">
        </bee:TBMediaPlayer>

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/13/5663.aspx

]]>
jeff377 2008-10-13 00:13:29
[ASP.NET 控制項實作 Day11] ActiveX 伺服器控制項 https://ithelp.ithome.com.tw/articles/10012159?sc=rss.iron https://ithelp.ithome.com.tw/articles/10012159?sc=rss.iron Media Player 與 Flash 之類在網頁上執行的外掛控制項,都是屬於 ActiveX 控制項,它們套用在 HTML 碼中的方式差不多,除了要指定 ClassID 以外,ActiveX...]]> Media Player 與 Flash 之類在網頁上執行的外掛控制項,都是屬於 ActiveX 控制項,它們套用在 HTML 碼中的方式差不多,除了要指定 ClassID 以外,ActiveX 使用的參數(相當於 ActiveX 控制項的屬性)以 Param Tag 來表示。本文標題命名為「ActiveX 伺服器控制項」就是避免誤解為 ActiveX 控制項,而是在 ASP.NET 中輸出 ActiveX 相關 HTML 碼的伺服器控制項;我們可透過 ActiveX 伺服器控制項可以用來輸出網頁上引用 ActiveX 的通用 HTML 碼,另外 ActiveX 的參數會以集合屬性來呈現,所以也會一併學習到集合屬性的撰寫方式。
程式碼下載:ASP.NET Server Control - Day11.rar

一、集合屬性
ActiveX 的 Param 參數是集合屬性,所以我們定義了 TBActiveParam 類別描述 ActiveX 參數,包含 Name 及 Value 屬性;而 TBActiveXParamCollection 為 TBActiveParam 的集合類別,用來描述 ActiveX 參數集合。TBActiveXParamCollection 繼承 CollectionBase,加入操作集合的 Add、Insert、Remove、IndexOf、Contains 等方法,關於集合屬性的用法可以參閱筆者在部落格的「撰寫伺服器控制項的集合屬性 (CollectionBase)」一文中有詳細說明。

二、實作 ActiveX 伺服器控制項
step1. 新增繼承 WebControl 的 TBActiveX

step2. 覆寫 TagKey 屬性,傳回 object 的 Tag

        Protected Overrides ReadOnly Property TagKey() As HtmlTextWriterTag
            Get
                Return HtmlTextWriterTag.Object
            End Get
        End Property

step3. 新增 ClassId 屬性,描述 ActiveX 的 ClassId
定義 ClassId 屬性,並覆寫 AddAttributesToRender 來輸出此屬性。

        ''' <summary>
        ''' 覆寫 AddAttributesToRender 方法。
        ''' </summary>
        Protected Overrides Sub AddAttributesToRender(ByVal writer As HtmlTextWriter)
            '加入 MediaPlayer ActiveX 元件的 classid
            writer.AddAttribute("classid", String.Format("clsid:{0}", Me.ClassId))
            MyBase.AddAttributesToRender(writer)
        End Sub

step4. 新增 Params 屬性,描述 ActiveX 的參數集合
定義 Params 屬性,型別為 TBActiveXParamCollection 類別,套用 EditorAttribute 設定 CollectionEditor 為集合編輯器。

        ''' <summary>
        ''' ActiveX 控制項參數集合。
        ''' </summary>
        < _
        Description("控制項參數集合。"), _
        PersistenceMode(PersistenceMode.InnerProperty), _
        DesignerSerializationVisibility(DesignerSerializationVisibility.Content), _
        Editor(GetType(CollectionEditor), GetType(UITypeEditor)) _
        > _
        Public ReadOnly Property Params() As TBActiveXParamCollection
            Get
                If FParams Is Nothing Then
                    FParams = New TBActiveXParamCollection()
                End If
                Return FParams
            End Get
        End Property

當編輯 Params 時,會使用的 CollectionEditor 集合編輯器。

step5. 輸出 ActiveX 參數
覆寫 CreateChildControls 方法,在此方法依 Params 集合屬性定義依序來輸出 ActiveX 的參數集合。

        Private Sub AddParam(ByVal Name As String, ByVal Value As String)
            Dim oParam As HtmlControls.HtmlGenericControl

            oParam = New HtmlControls.HtmlGenericControl("param")
            oParam.Attributes.Add("name", Name)
            oParam.Attributes.Add("value", Value)
            Me.Controls.Add(oParam)
        End Sub

        ''' <summary>
        ''' 建立子控制項。
        ''' </summary>
        Protected Overrides Sub CreateChildControls()
            Dim oParam As TBActiveXParam

            '加入 ActiveX 參數集合
            For Each oParam In Me.Params
                AddParam(oParam.Name, oParam.Value)
            Next
            MyBase.CreateChildControls()
        End Sub

三、執行程式
上一篇我們使用 TBMediaPlayer 控制項來設定 Media Player,在此我們改用 TBActiveX 控制項來設定 Media Player,一樣可以呈現相同的結果。

        <bee:TBActiveX ID="TBActiveX1" runat="server" 
            ClassId="6BF52A52-394A-11D3-B153-00C04F79FAA6" Height="250px" Width="250px">
            <Params>
                <bee:TBActiveXParam Name="URL" Value="d:/Movie_01.wmv" />
                <bee:TBActiveXParam Name="autoStart" Value="true" />
            </Params>
        </bee:TBActiveX>

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/12/5659.aspx

]]>
jeff377 2008-10-12 04:20:27
[ASP.NET 控制項實作 Day10] Media Player 控制項 https://ithelp.ithome.com.tw/articles/10012142?sc=rss.iron https://ithelp.ithome.com.tw/articles/10012142?sc=rss.iron 我們在前面幾篇文章中,已經簡要的對伺服器控制項做了基本介紹,接下來的幾篇文章中我們要開始實作伺服器控制項。在網頁上常使用 Media Player 來撥放影片,在 ASP.NET 中沒有現成的控...]]> 我們在前面幾篇文章中,已經簡要的對伺服器控制項做了基本介紹,接下來的幾篇文章中我們要開始實作伺服器控制項。在網頁上常使用 Media Player 來撥放影片,在 ASP.NET 中沒有現成的控制項來處理 Media Player,只能在 aspx 中加入 Media Player 相關的程式碼;本文將示範如何製作一個 Media Player 控制項,讓我們在 ASP.NET 中更方便的使用 Media Player。
程式碼下載:ASP.NET Server Control - Day10.rar

一、Media Player 原始 HTML 碼
在製作 Media Player 控制項之前,你需要先了解 Media Player 原本的 HTML 碼,控制項的作用就是想辨法把這些寫在 aspx 中的 HTML 碼交由控制項來輸出而已,以下為網頁中加入 Media Player 的 HTML 碼範例。

<OBJECT id="VIDEO" width="320" height="240" 
	style="position:absolute; left:0;top:0;"
	CLASSID="CLSID:6BF52A52-394A-11d3-B153-00C04F79FAA6"
	type="application/x-oleobject">
	
	<PARAM NAME="URL" VALUE="your file or url">
	<PARAM NAME="SendPlayStateChangeEvents" VALUE="True">
	<PARAM NAME="AutoStart" VALUE="True">
	<PARAM name="uiMode" value="none">
	<PARAM name="PlayCount" value="9999">
</OBJECT>

在下面的網頁有 Media Player 相關參數說明。
http://www.mioplanet.com/rsc/embed\_mediaplayer.htm

二、實作 Media Player 控制項
step1.首先新增由 WebControl 繼承下來的 TBMediaPlayer 類別。

    Public Class TBMediaPlayer
        Inherits WebControl

    End Class

step2.覆寫 TagKey 屬性,傳回 object 的 Tag。

        Protected Overrides ReadOnly Property TagKey() As System.Web.UI.HtmlTextWriterTag
            Get
                Return HtmlTextWriterTag.Object
            End Get
        End Property

step3.輸出 HTML Tag 的 Attribute
在 object Tag 中包含 style、classid、type 二個 Attribute,WebControl 本身會處理 style,所以我們只需覆寫 AddAttributesToRender 方法,處理 classid 及 type 二個 Attribute,記得覆寫 AddAttributesToRender 方法時最後要加入 MyBase.AddAttributesToRender(writer),才會執行父類別的 AddAttributesToRender 方法。

        ''' <summary>
        ''' 覆寫 AddAttributesToRender 方法。
        ''' </summary>
        Protected Overrides Sub AddAttributesToRender(ByVal writer As System.Web.UI.HtmlTextWriter)
            '加入 MediaPlayer ActiveX 元件的 classid
            writer.AddAttribute("classid", "clsid:6BF52A52-394A-11D3-B153-00C04F79FAA6")
            writer.AddAttribute("type", "application/x-oleobject")
            MyBase.AddAttributesToRender(writer)
        End Sub

step4.加入 Url 屬性
加入指定播放檔案來源的 Url 屬性,其中套用 EditorAttribute 設定 UrlEditor,使用 Url 專用的編輯器來設定屬性。

        ''' <summary>
        ''' 播放檔案來源。
        ''' </summary>
        < _
        Description("播放檔案來源"), _
        Bindable(True), _
        Category("Appearance"), _
        Editor(GetType(UrlEditor), GetType(UITypeEditor)), _
        UrlProperty(), _
        DefaultValue("") _
        > _
        Public Property Url() As String
            Get
                Return FUrl
            End Get
            Set(ByVal value As String)
                FUrl = value
            End Set
        End Property

step5.輸出 Url 參數
接下來覆寫 CreateChildControls 方法,輸出 Url 參數。

        ''' <summary>
        ''' 加入參數。
        ''' </summary>
        ''' <param name="Name">參數名稱。</param>
        ''' <param name="Value">參數值。</param>
        Private Sub AddParam(ByVal Name As String, ByVal Value As String)
            Dim oParam As HtmlControls.HtmlGenericControl

            oParam = New HtmlControls.HtmlGenericControl("param")
            oParam.Attributes.Add("name", Name)
            oParam.Attributes.Add("value", Value)
            Me.Controls.Add(oParam)
        End Sub

        Protected Overrides Sub CreateChildControls()
            '加入 Url 參數
            AddParam("url", Me.ResolveClientUrl(Me.Url))
            MyBase.CreateChildControls()
        End Sub

step6.輸出 Media Player 其他參數
你可以將 Media Player 的參數設定皆使用相對應的屬性來設定,然後使用 step5 的方式來輸出所有設定的參數值。

三、Media Player 控制項程式碼
Media Player 控制項的完整程式碼如下,此控制項只加入 URL、AutoStart、UIMode 三個參數,你可以視需求情形將使用到的參數定義為屬性來做設定即可。
因為此處有字元數限制,完整的程式碼請參閱筆者部落格相同文章
http://www.dotblogs.com.tw/jeff377/archive/2008/10/11/5655.aspx

四、執行程式
把 TBMediaPlayer 控制項拖曳至頁面,設定好屬性後,執行程式就可以在頁面上看到呈現出來的 Media Player。

        <bee:TBMediaPlayer ID="TBMediaPlayer1" runat="server" Height="250px" 
            Width="250px" Url="~/test.wmv" />

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/11/5655.aspx

]]>
jeff377 2008-10-11 19:08:27
[ASP.NET 控制項實作 Day9] 控制項常用 Attribute 介紹(2) https://ithelp.ithome.com.tw/articles/10012060?sc=rss.iron https://ithelp.ithome.com.tw/articles/10012060?sc=rss.iron 接續上篇 Attribute 的介紹,本文將再介紹一些伺服器控制項常用的 Attribute。
六、ToolboxDataAttribute 類別<...]]>
接續上篇 Attribute 的介紹,本文將再介紹一些伺服器控制項常用的 Attribute。
六、ToolboxDataAttribute 類別
作用:指定當自訂控制項從工具箱拖曳到頁面時,為此自訂控制項產生的預設標記。
當我們新增一個伺服器控制項,它就會預設在控制項類別套用 ToolboxDataAttribute,定義在控制項在 aspx 程式碼中的標記。

<ToolboxData("<{0}:TBButton runat=server ></{0}:TBButton>")> _
Public Class TBButton
    Inherits System.Web.UI.WebControls.Button
End Class

七、DefaultPropertyAttribute 類別
作用:指定類別的預設屬性。
下面的範例中,MyTextbox 類別套用 DefaultPropertyAttribute,設定 Text 屬性為預設屬性。

<DefaultProperty("Text")> _
Public Class MyTextbox
    Inherits WebControl

    Public Property Text() As String
        Get
            Return CType(Me.ViewState("Text"), String)
        End Get

        Set(ByVal value As String)
            Me.ViewState("Text") = value
        End Set
    End Property
End Class

八、DefaultEventAttribute 類別
作用:指定控制項的預設事件。
下面的範例中,MyTextbox 類別套用 DefaultEventAttribute,設定 TextChanged 為預設屬性。

<DefaultEvent("TextChanged")> _
Public Class MyTextbox
    Inherits WebControl

    ''' <summary>
    ''' TextChanged 事件。
    ''' </summary>
    Public Event TextChanged As EventHandler
End Class

當設計階段在頁面上的 MyTextbox 控制項點二下時,就會產生預設事件的處理函式。

    Protected Sub MyTextbox1_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyTextbox3.TextChanged

    End Sub

九、LocalizableAttribute 類別
作用:指定屬性是否應該當地語系化。
當屬性套用設為為 true 的 LocalizableAttribute 時,其屬性值會儲存在資源檔中,未來不需修改程式碼就可以將這些資源檔當地語系化。

        <Localizable(True)> _
        Public Property Text() As String
            Get
                Return CType(Me.ViewState("Text"), String)
            End Get

            Set(ByVal value As String)
                Me.ViewState("Text") = value
            End Set
        End Property

十、DesignerAttribute 類別
作用:設定控制項在設計階段服務的類別。
指定一個設計階段的服務類別,來管理控制項在設計階段的行為,例如控制項的設計階段外觀、智慧標籤內容。例如下面範例的 TBGridView 控制項就定義了 TBGridViewDesigner 來實作設計階段的行為,未來的章節中也會介紹如何實作控制項的 Designer。

    < Designer(GetType(TBGridViewDesigner)) > _
    Public Class TBGridView
        Inherits GridView
    End Class

十一、EditorAttribute 類別
作用:指定在屬性視窗中編輯屬性值的編輯器。
例如 ListBox 控制項的 Items 屬性,在屬性視窗編輯 Items 屬性時,會彈出 Items 集合屬性的編輯器。以下範例就是定義 Items 屬性的編輯器類別為 TBListItemsCollectionEditor,未來的章節中也會介紹如何實作屬性的 Editor。

        <Editor(GetType(TBListItemsCollectionEditor), GetType(System.Drawing.Design.UITypeEditor))> _
        Public Overrides ReadOnly Property Items() As ListItemCollection

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/10/5653.aspx

]]>
jeff377 2008-10-10 11:27:02
[ASP.NET 控制項實作 Day8] 控制項常用 Attribute 介紹(1) https://ithelp.ithome.com.tw/articles/10012016?sc=rss.iron https://ithelp.ithome.com.tw/articles/10012016?sc=rss.iron Property 與 Attribute 二個術語一般都是翻譯成「屬性」,例如類別的屬性,是使用英文的 Property,而 HTML/XML 的元素屬性,使用的英文則是 Attribute。在...]]> Property 與 Attribute 二個術語一般都是翻譯成「屬性」,例如類別的屬性,是使用英文的 Property,而 HTML/XML 的元素屬性,使用的英文則是 Attribute。在 .NET 中 Property 與 Attribute 的意義及用法不同,不過微軟線上文件也將它翻譯為「屬性」,這可能讓人發生困擾及誤解;筆者比較喜歡的方式就是 Property 是屬性,Attribute 就維持原文。在 .NET 中類別或屬性上可以套用上不同的 Attribute,使類別或屬性具有不同的特性,本文將介紹一些在伺服器控制項常使用到的 Attribute。
一、DescriptionAttribute 類別
作用:指定控制項或屬性的描述。
當 DescriptionAttribute 套用至控制項的類別時,設定的描述內容就會出現在工具箱中控制項的提示。

<Description("按鈕控制項")> _
Public Class TBButton
    Inherits System.Web.UI.WebControls.Button
End Class


當 DescriptionAttribute 套用至控制項的屬性時,在屬性視窗下面就會出現設定的屬性描述內容。

<Description("詢問訊息")> _
Public Property ConfirmMessage() As String

二、DefaultValueAttribute 類別
作用:指定屬性的預設值。
使用 DefaultValueAttribute 設定屬性的預設值,若設定的屬性值與預設值相同時,此屬性值就不會出現在 aspx 程式碼中;筆者強烈建議屬性一定套用 DefaultValueAttribute,一來在 aspx 中的程式碼會比較少,另外一個重點是若因為某些因素需要修改屬性的預設值時,所有已開發頁面的控制項屬性值會一併變更;因為當初屬性值是預設值,沒有被寫入 aspx 程式碼中,所以一但控制項的屬性預設值變更,頁面已佈屬的控制項的屬性值就會全面適用。

        Private FConfirmMessage As String = String.Empty

        <DefaultValue("")> _
        Public Property ConfirmMessage() As String
            Get
                Return FConfirmMessage
            End Get
            Set(ByVal value As String)
                FConfirmMessage = value
            End Set
        End Property

三、CategoryAttribute 類別
作用:指定屬性或事件的分類名稱,當屬性視窗設定為 [分類] 模式時,以群組方式來顯示屬性或事件。
例如設定 ConfirmMessage 屬性在 "Behavior" 分類,則 ConfirmMessage 屬性會被歸類到「行為」分類。

        <Category("Behavior")> _
        Public Property ConfirmMessage() As String

四、BindableAttribute 類別
作用:指定成員是否通常使用於繫結。
在資料繫結設定視窗中中,指定屬性是否預設會出現在屬性清單中。

<Bindable(True)> _
Public Property ConfirmMessage() As String

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/09/5647.aspx

]]>
jeff377 2008-10-09 21:11:43
[ASP.NET 控制項實作 Day7] 設定工具箱的控制項圖示 https://ithelp.ithome.com.tw/articles/10011933?sc=rss.iron https://ithelp.ithome.com.tw/articles/10011933?sc=rss.iron 當我們把自訂控制項加入到工具箱中時,你會發現所有的控制項預設都是同樣的圖示,雖然控制項的圖示不變更不會有什麼影響,不過我們還是希望為自訂控制項加上合適的外衣,本文將介紹如何設定工具箱控制項圖示。...]]> 當我們把自訂控制項加入到工具箱中時,你會發現所有的控制項預設都是同樣的圖示,雖然控制項的圖示不變更不會有什麼影響,不過我們還是希望為自訂控制項加上合適的外衣,本文將介紹如何設定工具箱控制項圖示。
一、加入控制項圖示檔
首先要準備一個 16 x 16 的點陣圖(bmp),如下所示。

將此圖檔加入至「伺服器控制項專案」中,可以如下圖所示,用一個特定的資料夾來儲存所有工具箱的圖示。

然後在圖檔的屬性視窗中,設定建置動作為「內嵌資源」。

二、設定控制項的圖示
首先定義一個 TBResource 類別,此為一個空的類別,其命名空間需與根命名空間相同,做為引用資源檔時使用。並加上控制項圖示的 WebResource 定義,因為根命名空間是 Bee.Web,而圖檔名稱為 TBButton.bmp,所以定義如下所示。

假設我們要設定 TBButton 的工具箱圖示,則在 TBButton 類別套用 ToolboxBitmapAttribute 如下,其中第一個參數為 GetType(TBResource),第二個參數為圖檔檔名。

重新編輯伺服器控制項專案,再將 Bee.Web.dll 組件的控制項加入工具箱中,你就可以發現 TBButton 的圖示已經變成設定的圖示了。

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/08/5624.aspx

]]>
jeff377 2008-10-08 22:26:13
[ASP.NET 控制項實作 Day6] 事件與 PostBack https://ithelp.ithome.com.tw/articles/10011861?sc=rss.iron https://ithelp.ithome.com.tw/articles/10011861?sc=rss.iron 一般類別的事件撰寫很單純,不過在 ASP.NET 中與前端使用者互動產生的事件就不是那麼簡單了;在以往的 ASP 年代是沒有事件這回事的,而在 ASP.NET 把網頁程式撰寫真正的物件導向化,用...]]> 一般類別的事件撰寫很單純,不過在 ASP.NET 中與前端使用者互動產生的事件就不是那麼簡單了;在以往的 ASP 年代是沒有事件這回事的,而在 ASP.NET 把網頁程式撰寫真正的物件導向化,用戶端使用者的操作透過 PostBack 來產生相對應的事件。例如前端使用者按鈕後會引發伺服端 Button 的 Click 事件,當前端使用者輸入文字框完畢後離開後會引發伺服端 TextBox 的 TextChanged 事件,在本文中就是要說明如何透過 PostBack 來產生與使用者互動的事件。
一、IPostBackEventHandler 與 IPostBackDataHandler 介面
控制項要處理 PostBack 產生的事件,必須實作 IPostBackEventHandler 或 IPostBackDataHandler 介面,這二個介面有什麼差別呢?例如 Button 是實作IPostBackEventHandler 介面,由控制項產生的 PostBack 直接引發事件,如 Button 的 Click 事件。例如 TextBox 是實作 IPostBackDataHandler 介面,當頁面產生 PostBack 時,會傳用戶端輸入的新值給控制項,由控制項本身去決定是否引發該事件;以 TextBox 舉例來說,它會判斷新值與舊值不同時才會引發 TextChanged 事件。

二、IPostBackEventHandler 介面實作
首先介紹 IPostBackEventHandler 介面,它包含 RaisePostBackEvent 方法,控制項在此方法中需處理要引發那些事件。我們繼承 WebControl 撰寫 MyButton 類別來說明 IPostBackEventHandler 介面,我們簡化控制項程式碼直接在 Render 方法輸入按鈕的 HTML 原始碼,並定義一個 Click 事件。實作 IPostBackEventHandler 介面的 RaisePostBackEvent 方法,在此方法中直接引發 Click 事件。

Public Class MyButton
    Inherits WebControl
    Implements IPostBackEventHandler

    ''' <summary>
    ''' Click 事件。
    ''' </summary>
    Public Event Click As EventHandler

    ''' <summary>
    ''' 引發 Click 事件。
    ''' </summary>
    Private Sub OnClick(ByVal e As EventArgs)
        RaiseEvent Click(Me, e)
    End Sub

    Public Sub RaisePostBackEvent(ByVal eventArgument As String) Implements System.Web.UI.IPostBackEventHandler.RaisePostBackEvent
        Dim e As New EventArgs()
        OnClick(e) '引發 Click 事件
    End Sub

    ''' <summary>
    ''' 覆寫 Render 方法。
    ''' </summary>
    Protected Overrides Sub Render(ByVal writer As System.Web.UI.HtmlTextWriter)
        Dim sHTML As String

        sHTML = String.Format("<INPUT TYPE=Submit Name={0} Value = '按鈕'/>", Me.UniqueID)
        writer.Write(sHTML)
    End Sub

End Class

在頁面上拖曳 MyButton 控制項,在屬性視窗找到 Click 事件,點二下產生 Click 事件處理函式,並撰寫測試程式碼如下。

    Protected Sub MyButton1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyButton1.Click
        Me.Page.Response.Write("MyButton Click 事件")
    End Sub

執行程式,當按下 MyButton 按鈕時,就會執行它的 RaisePostBackEvent 方法,進而引發 Click 事件,也就會執行 Click 事件處理函式的程式碼。

三、IPostBackDataHandler 介面實作
IPostBackDataHandler 介面包含 LoadPostData 及 RaisePostDataChangedEvent 方法,當頁面 PostBack 時,會尋找具 IPostBackDataHandler 介面的控制項,先執行LoadPostData 方法,控制項在 LoadPostData 方法中會判斷用戶端傳入值決定是否引發事件,若 LoadPostData 傳回 True 表示要引發事件,此時會執行RaisePostDataChangedEvent 方法去決定要引發那些事件,反之傳回 False 表示不引發事件。

我們繼承 WebControl 撰寫 MyText 類別來說明 IPostBackDataHandler 介面,我們簡化控制項程式碼直接在 Render 方法輸入文字框的 HTML 原始碼,並定義一個 TextChanged 事件。在 LoadPostData 方法中我們會判斷用戶端傳入值與目前的值是否不相同,不相同時才會傳回 True,此時才會執行 RaisePostDataChangedEvent 方法,進而引發 TextChanged 事件。

Public Class MyTextbox
    Inherits WebControl
    Implements IPostBackDataHandler

    Public Property Text() As String
        Get
            Return CType(Me.ViewState("Text"), String)
        End Get
        Set(ByVal value As String)
            Me.ViewState("Text") = value
        End Set
    End Property

    ''' <summary>
    ''' TextChanged 事件。
    ''' </summary>
    Public Event TextChanged As EventHandler

    ''' <summary>
    ''' 引發 TextChanged 事件。
    ''' </summary>
    Private Sub OnTextChanged(ByVal e As EventArgs)
        RaiseEvent TextChanged(Me, e)
    End Sub

    Public Function LoadPostData(ByVal postDataKey As String, ByVal postCollection As System.Collections.Specialized.NameValueCollection) As Boolean Implements System.Web.UI.IPostBackDataHandler.LoadPostData
        '前端使用者輸入值
        Dim oNewValue As String = postCollection.Item(postDataKey)
        If oNewValue <> Me.Text Then
            Me.Text = oNewValue
            Return True
        Else
            Return False
        End If
    End Function

    Public Sub RaisePostDataChangedEvent() Implements System.Web.UI.IPostBackDataHandler.RaisePostDataChangedEvent
        Dim e As New EventArgs()
        '引發 TextChanged 事件
        OnTextChanged(e)
    End Sub

    ''' <summary>
    ''' 覆寫 Render 方法。
    ''' </summary>
    Protected Overrides Sub Render(ByVal writer As System.Web.UI.HtmlTextWriter)
        Dim sHTML As String

        sHTML = String.Format("<INPUT Type=text Name={0} Value={1} >", Me.UniqueID, Me.Text)
        writer.Write(sHTML)
    End Sub

End Class

在頁面上拖曳 MyTextbox 及 MyButton 控制項,在 MyButton 的 Click 及 MyTextbox 的 TextChanged 事件撰寫如下測試程式碼。

    Protected Sub MyButton1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyButton1.Click
        Me.Page.Response.Write("MyButton Click 事件")
        Me.Page.Response.Write("<br/>")
    End Sub

    Protected Sub MyTextbox1_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyTextbox1.TextChanged
        Me.Page.Response.Write("MyTextbox TextChanged 事件")
        Me.Page.Response.Write("<br/>")
    End Sub

執行程式,在 MyTextbox 輸入 "A",再按下 MyButton,因為 MyTextbox 的值「空字串->"A"」,所以會引發 MyTextbox 的 TextChanged 事件及 MyButton 的 Click 事件。

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格

]]>
jeff377 2008-10-07 23:30:19
[ASP.NET 控制項實作 Day5] 屬性與 ViewState https://ithelp.ithome.com.tw/articles/10011745?sc=rss.iron https://ithelp.ithome.com.tw/articles/10011745?sc=rss.iron 在 ASP.NET 中,控制項的屬性與 ViewState 有著密不可分的關係,透過 ViewState 才有辨法維護控制項的屬性值。在本文中將介紹屬性與 ViewState 的關係,並說明屬性...]]> 在 ASP.NET 中,控制項的屬性與 ViewState 有著密不可分的關係,透過 ViewState 才有辨法維護控制項的屬性值。在本文中將介紹屬性與 ViewState 的關係,並說明屬性如何存取 ViewState 是比較有效率的方式。
當你加入一個「ASP.NET 伺服器控制項」時,類別中預設會有一個 Text 屬性寫法的範例如下所示,屬性的讀寫都是直接存取 ViewState,這是一般常見的控制項屬性寫法。可是這種屬性的寫法是沒有效率的,因為 ViewState 的成員是 Object 型別,每次讀取屬性時都是由 ViewState 取出指定鍵值的成員再轉型為屬性的型別,寫入屬性的動作也是直接寫入 ViewState 中。

    Property Text() As String
        Get
            Dim s As String = CStr(ViewState("Text"))
            If s Is Nothing Then
                Return String.Empty
            Else
                Return s
            End If
        End Get

        Set(ByVal Value As String)
            ViewState("Text") = Value
        End Set
    End Property

比較好的方式應該是讀取 ViewState 成員只做一次型別轉換的動作,而寫入 ViewState 的動作可以在 Render 前做批次寫入的動作即可。為了達到這樣的需求,我們可以覆寫 LoadViewState 及 SaveViewState 方法來處理屬性與 ViewState 的存取動作;當控制項初始化後會執行 LoadViewState 方法,來載入 ViewState 還原的控制項狀態,當控制項 Render 之前,會執行 SaveViewState 方法,將控制項的最終狀態存入 ViewState 中,也就是在此方法之後對控制項所做的任何變更都將會被忽略。

我們改寫屬性的寫法,不直接用 ViewState 來存取屬性,而是改用「屬性區域變數」來存取屬性,在 LoadViewState 時載入 ViewState 到屬性區域變數,而 SaveViewState 時再將屬性區域變數寫入 ViewState 中。我們依此方式將 Text 屬性改寫如下。

    Private FText As String

    Property Text() As String
        Get
            Return FText
        End Get
        Set(ByVal Value As String)
            FText = Value
        End Set
    End Property

    ''' <summary>
    ''' 載入 ViewState 還原控制項狀態。
    ''' </summary>
    Protected Overrides Sub LoadViewState(ByVal savedState As Object)
        If Not (savedState Is Nothing) Then
            ' Load State from the array of objects that was saved at vedViewState.
            Dim myState As Object() = CType(savedState, Object())

            If Not (myState(0) Is Nothing) Then
                MyBase.LoadViewState(myState(0))
            End If

            If Not (myState(1) Is Nothing) Then
                FText = CType(myState(1), String)
            End If
        End If
    End Sub

    ''' <summary>
    ''' 將控制項狀態寫入 ViewState 中。
    ''' </summary>
    Protected Overrides Function SaveViewState() As Object
        Dim baseState As Object = MyBase.SaveViewState()
        Dim myState(1) As Object
        myState(0) = baseState
        myState(1) = FText
        Return myState
    End Function

利用上述的方式,我們可以在 LoadViewState 批次載入所有屬性值,而在 SaveViewState 批次寫入屬性值,如此在讀取屬性就不用一直做型別轉換的動作以改善效率。

結語
雖然屬性一般都是儲存於 ViewState 中,不過若是一些無關緊要的屬性或是完全不會執行階段就變更的屬性,可以考慮不需要將這些屬性儲存於 ViewState 中;因為 ViewState 是個兩面刃,ViewState 可以很輕易幫我們維護屬性值,不過相對的也增加了面頁的傳輸量,所以可以視實際情形來決定屬性是否要儲存於 ViewState 中。

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/07/5601.aspx

]]>
jeff377 2008-10-06 21:17:20
[ASP.NET 控制項實作 Day4] 複合控制項 https://ithelp.ithome.com.tw/articles/10011633?sc=rss.iron https://ithelp.ithome.com.tw/articles/10011633?sc=rss.iron 複合控制項就是控制項可包含其他子控制項,複合控制項繼承至 System.Web.UI.WebControls.CompositeControl,例如 Login 及 Wizard 等控制項就是屬...]]> 複合控制項就是控制項可包含其他子控制項,複合控制項繼承至 System.Web.UI.WebControls.CompositeControl,例如 Login 及 Wizard 等控制項就是屬於複合控制項。我們常在網頁上常看到一種輸入日期的方式是年月日三個下拉清單,本文將利用複合控制項來實作這個年月日下拉清單控制項,示範如何實作複合控制項。
一、CompositeControl 類別的特性
CompositeControl 類別是抽象類別,它會實作 INamingContaner 介面,INamingContaner 介面會在子控制項的 ClinetID 加上父控制項的 ID,以確保頁面上控制項的 ClientID 是唯一的。繼承 CompositeControl 類別一般都是覆寫 CreateChildControls 方法,在此方法中將建立子控制項並加入 Controls 集合屬性中;當存取其子控制項時,若子控制項未建立,會執行 CreateChildControls 方法,以會確保所有子控制項皆已在存取 ControlCollection 之前建立。
二、日期下拉清單輸入器
我們繼承 CompositeControl 類別,命名為 TBDropDownDate。這個控制項會包含年月日三個下拉清單(DropDownList),所以我們只要在 CreateChildControls 方法中依序建立年月日的 DropDownList 子控制項,並加入 Controls 集合屬性中即可。

''' <summary>
''' 日期下拉清單輸入器。
''' </summary>
< _
ToolboxData("<{0}:TBDropDownDate runat=server></{0}:TBDropDownDate>") _
> _
Public Class TBDropDownDate
    Inherits System.Web.UI.WebControls.CompositeControl

    Protected Overrides Sub CreateChildControls()
        Dim oYear As DropDownList
        Dim oMonth As DropDownList
        Dim oDay As DropDownList
        Dim N1 As Integer

        '年下拉清單區間為 1950-2010 (年區間可以用屬性來設定)
        oYear = New DropDownList
        oYear.ID = "Year"
        For N1 = 1950 To 2010
            oYear.Items.Add(N1.ToString)
        Next
        Me.Controls.Add(oYear) '加入子控制項
        Me.Controls.Add(New LiteralControl("年"))

        '月下拉清單區間為 1-12
        oMonth = New DropDownList
        oMonth.ID = "Month"
        For N1 = 1 To 12
            oMonth.Items.Add(N1.ToString)
        Next
        Me.Controls.Add(oMonth) '加入子控制項
        Me.Controls.Add(New LiteralControl("月"))

        '日下拉清單區為為 1-31
        oDay = New DropDownList
        oDay.ID = "Day"
        For N1 = 1 To 12
            oDay.Items.Add(N1.ToString)
        Next
        Me.Controls.Add(oDay) '加入子控制項
        Me.Controls.Add(New LiteralControl("日"))

    End Sub
End Class

在設定階段拖曳 TBDropDownDate 到頁面上,就可以看到我們在 CreateChildControls 方法中所加入的子控制項。

執行程式,檢視它的 HTML 原始碼,會發現年月日的子控制項的 ClientID 都會在原 ID 前加上父控制項的 ID,這樣命名規則可以確保所有的控制項的 ClinetID 都是唯一值。

<span id="TBDropDownDate1">
<select name="TBDropDownDate1$Year" id="TBDropDownDate1_Year">

....省略

<select name="TBDropDownDate1$Month" id="TBDropDownDate1_Month">

....省略

<select name="TBDropDownDate1$Day" id="TBDropDownDate1_Day">
</span>

三、結語
我們已經看過三類伺服器控制項的簡單案例,不過這三個案例都只是簡單說明控制項 UI 的部分,一個完整的控制項需具備屬性、方法、事件、設計階段支援...等,在後面的文章中,我們將陸續針對這些部分做詳細的介紹。

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/05/5583.aspx

]]>
jeff377 2008-10-05 22:22:25
[ASP.NET 控制項實作 Day3] 擴展現有伺服器控制項功能 https://ithelp.ithome.com.tw/articles/10011562?sc=rss.iron https://ithelp.ithome.com.tw/articles/10011562?sc=rss.iron 相對於由無到有開發控制項,繼承現有現伺服器控制項是比較簡單且實用的方式;若希望在現有的控制項增加某些屬性或功能,直接繼承該控制項下來擴展功能是最快的方式,例如「按下 Button 會彈出詢問訊息...]]> 相對於由無到有開發控制項,繼承現有現伺服器控制項是比較簡單且實用的方式;若希望在現有的控制項增加某些屬性或功能,直接繼承該控制項下來擴展功能是最快的方式,例如「按下 Button 會彈出詢問訊息」、「TextBox 設為 ReadOnly 時,可以取得前端傳回的 Text 屬性」這類需求,都可以直接繼承原控制項下來,加上我們需要的功能即可。以下我們就以一個簡單的案例來說明如何繼承現有伺服器下來擴展功能。
一、擴展 Button 控制項:按鈕加上詢問訊息
按下按鈕執行某些動作前,有時會詢問使用者是否執行該動作;例如按下刪除鈕,會詢問使用者是否確定要執行刪除的動作。當然這只需要簡單的 JavaScript 就可以完成,不過相對於 .NET 的程式語言,JavaScript 是非常不易維護的用戶端指令碼,如果能讓開發人員完全用不到 JavaScript,那何樂不為呢? 那就由 Button 控制項本身提供加上詢問訊息的功能就可以,相關的 JavaScript 由控制項去處理。
一般要在 Button 加上詢問訊息,只要在 OnClientClick 屬性設定如下的 JavaScript 即可。我們的目的只是讓開發人員連設定 OnClientClick 屬性的 JavaScript 都省略,直接設定要詢問的訊息即可,接下來我們就要開始實作這個控制項。

<asp:Button ID="Button1" runat="server" Text="Button"  OnClientClick="if (confirm('確定執行嗎?')==false) {return false;}" />   

在 Bee.Web 專案中,加入「ASP.NET 伺服器控制項」,此控制項繼承 Button 下來命名為 TBButton (命名空間為 Bee.Web.WebControls)。在 TBButton 類別中加入 ConfirmMessage 屬性,用來設定詢問訊息的內容。然後在 Render 方法將詢問詢息的 JavaScript 設定到 OnClientClick 屬性即可。

Namespace WebControls
    < _
    Description("按鈕控制項"), _
    ToolboxData("<{0}:TBButton runat=server></{0}:TBButton>") _
    > _
    Public Class TBButton
        Inherits System.Web.UI.WebControls.Button

        <Description("詢問訊息")> _
        Public Property ConfirmMessage() As String
            Get
                Dim sConfirmMessage As String
                sConfirmMessage = CStr(ViewState("ConfirmMessage"))
                If sConfirmMessage Is Nothing Then
                    Return String.Empty
                Else
                    Return sConfirmMessage
                End If
            End Get
            Set(ByVal value As String)
                ViewState("ConfirmMessage") = value
            End Set
        End Property

        ''' <summary>
        ''' 覆寫 Render 方法。
        ''' </summary>
        Protected Overrides Sub Render(ByVal writer As System.Web.UI.HtmlTextWriter)
            Dim sScript As String
            Dim sConfirm As String

            '若有設定 ConfirmMessage 屬性,則在 OnClientClick 加入詢問訊息的 JavaScript
            If Me.ConfirmMessage <> String.Empty Then
                sScript = Me.OnClientClick
                '詢問訊息的 JavaScript
                sConfirm = String.Format("if (confirm('{0}')==false) {{return false;}}", Me.ConfirmMessage)
                If sScript = String.Empty Then
                    Me.OnClientClick = sConfirm
                Else
                    Me.OnClientClick = sConfirm & sScript
                End If
            End If
            MyBase.Render(writer)
        End Sub

    End Class
End Namespace

將 TBButton 拖曳到測試頁面,設定 ConfirmMessage 屬性。

<bee:TBButton ID="TBButton1" runat="server" ConfirmMessage="確定刪除此筆資料嗎?" Text="刪除" />

執行結果如下。

二、結語
筆者在開發 ASP.NET 的應用程式過程中,通常會習慣把所有現有控制項繼承下來,無論目前需不需要擴展控制項功能。這種方式對於開發大型系統是相當有幫助的,因為無法預期在系統開發的過程中會不會因為某些狀況,而臨時需要擴展控制項的功能,所以就先全部繼承下來以備不時之需,也為未來保留修改的彈性。

三、相關連結
擴展 CommandField 類別 - 刪除提示訊息
按鈕加上詢問訊息

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/04/5578.aspx

]]>
jeff377 2008-10-04 21:24:49
[ASP.NET 控制項實作 Day2] 建立第一個伺服器控制項 https://ithelp.ithome.com.tw/articles/10011523?sc=rss.iron https://ithelp.ithome.com.tw/articles/10011523?sc=rss.iron 上一篇中已經建立「ASP.NET 伺服器控制項」專案,接下來我們將學習來撰寫第一個伺服器控制項。
撰寫伺服器控制項大致分為下列三種方式
1.由無到有建立全新的控制項,一般...]]>
上一篇中已經建立「ASP.NET 伺服器控制項」專案,接下來我們將學習來撰寫第一個伺服器控制項。
撰寫伺服器控制項大致分為下列三種方式
1.由無到有建立全新的控制項,一般會繼承至 System.Web.UI.Control 或 System.Web.UI.WebControls.WebControl 類別。
2.繼承現有控制項,擴展原有控制項的功能,如繼承原有 TextBox 來擴展功能。
3.複合式控制項,將多個現有的控制項組合成為一個新的控制項,例如 TextBox 右邊加個 Button 整合成一個控制項,一般會繼承至 System.Web.UI.WebControls.CompositeControl 類別。

本文將先介紹第1種方式,由無到有來建立控制項,後面的文章中會陸續介紹第2、3種方式的控制項。要建立全新的控制項會繼承至 Control 或 WebControl,沒有 UI 的控制項可由 Control 繼承下來 (如 SqlDataSource),具 UI 的控制項會由 WebControl 繼承下來。接下來的範例中,我們將繼承 WebControl 來建立第一個 MyTextBox 控制項。

一、新增 MyTextBox 控制項
在 Bee.Web 專案按右鍵選單,執行「加入\新增項目」,選擇「ASP.NET 伺服器控制項」,在名稱文字框中輸入 MyTextbox,按下「確定」鈕,就會在專案中加入 MyTextbox 控制項類別。

新加入的控制項預設有一個 Text 屬性,以及覆寫 Render 方法。Render 方法是「將控制項呈現在指定的 HTML 寫入器中」,簡單的說就是在 Render 方法會將控制項對應的 HTML 碼輸出,用來呈現在用戶端的瀏覽器上。假設我們要撰寫一個網頁上的文字框,那就先去看一下文字框在網頁中對應的 HTML 碼,然後在 Render 方法中想辨法輸出這些 HTML 碼即可。

二、輸出控制項的 HTML 碼
你可以使用 FrontPage 之類的 HTML 編輯器,先編輯出控制項的呈現方式,進而去觀查它的 HTML 碼,再回頭去思考如何去撰寫這個伺服器控制項。假設 MyTextbox 控制項包含一個文字框及一個按鈕,那最終輸出的 HTML 碼應該如下。

<input id="Text1" type="text" />
<input id="Button1" type="button" value="button" />

我們在 MyTextbox 的 RenderContents 方法中輸出上述的 HTML 碼。

    Protected Overrides Sub RenderContents(ByVal writer As HtmlTextWriter)
        Dim sHTML As String

        sHTML = "<input id=""Text1"" type=""text"" />" & _
                "<input id=""Button1"" type=""button"" value=""button"" />"
        writer.Write(sHTML)
    End Sub

建置控制項專案,然後拖曳 MyTextbox 在測試頁面上,設計階段就會呈現出我們期望的結果。

執行程式,在瀏覽器看一下 MyTextbox 控制項輸出的結果,是不是跟我們預期的一樣呢。

三、屬性套用到控制項 HTML 碼
控制項不可能單純這樣輸出 HTML 碼而已,控制項的相關屬性設定,一般都影響到輸出的 HTML 碼。假設 MyTextbox 有 Text 及 ButtonText 二個屬性,分別對應到 文字框的內容及按鈕的文字,MyTextbox 本來就有 Text 屬性,依像畫蘆葫新增 ButtonText 屬性。

    < _
    Bindable(True), _
    Category("Appearance"), _
    DefaultValue(""), _
    Localizable(True)> _
    Property ButtonText() As String
        Get
            Dim s As String = CStr(ViewState("ButtonText"))
            If s Is Nothing Then
                Return String.Empty
            Else
                Return s
            End If
        End Get

        Set(ByVal Value As String)
            ViewState("ButtonText") = Value
        End Set
    End Property

RenderContents 方法改寫如下。

    Protected Overrides Sub RenderContents(ByVal writer As HtmlTextWriter)
        Dim sHTML As String

        sHTML = "<input id=""Text1"" type=""text"" value=""{0}""/>" & _
                "<input id=""Button1"" type=""button"" value=""{1}"" />"
        sHTML = String.Format(sHTML, Me.Text, Me.ButtonText)
        writer.Write(sHTML)
    End Sub

重新建置控制項專案,在頁面上測試 MyTextbox 的 Text 及 ButtonText 屬性。

四、使 ClientID (HTML 原始碼控制項的 ID) 是唯一值
在頁面上放置二個 MyTextbox 控制項,執行程式,在瀏覽器中檢查 MyTextbox 的 HTML 原始碼。你會發現 MyTextbox 會以一個 span 包住控制項的內容,而每個控制項的輸出的 ClientID 是唯一的。不過 MyTextbox 內含的文字框及按鈕卻會重覆,所以一般子控制項的 ClientID 會在前面包含父控制項的 ID。

<span id="MyTextbox1">
<input id="Text1" type="text" value="這是文字"/>
<input id="Button1" type="button" value="這是按鈕" />
</span>

<br />

<span id="MyTextbox2">
<input id="Text1" type="text" value="這是文字"/>
<input id="Button1" type="button" value="這是按鈕" />
</span>

所以我們再次修改 RenderContents 方法的程式碼

    Protected Overrides Sub RenderContents(ByVal writer As HtmlTextWriter)
        Dim sHTML As String

        sHTML = "<input id=""{0}_Text"" type=""text"" value=""{1}""/>" & _
                "<input id=""{0}_Button"" type=""button"" value=""{2}"" />"
        sHTML = String.Format(sHTML, Me.ID, Me.Text, Me.ButtonText)
        writer.Write(sHTML)
    End Sub

執行程式,再次檢視 HTML 原始碼,所有的 ClinetID 都會是唯一的。

<span id="MyTextbox1">
<input id="MyTextbox1_Text" type="text" value="這是文字"/>
<input id="MyTextbox1_Button" type="button" value="這是按鈕" />
</span>

<br />

<span id="MyTextbox2">
<input id="MyTextbox2_Text" type="text" value="這是文字"/>
<input id="MyTextbox2_Button" type="button" value="這是按鈕" />
</span>

五、控制項前置詞
自訂控制項的預設前置詞是 cc1,不過這是可以修改的,在專案中的 AssemblyInfo.vb 檔案中,加入如下定義即可。詳細的作法請參考筆者部落格中的「自訂伺服器控制項前置詞」一本有詳細介紹,在此不再累述。

'設定控制項的標記前置詞
<Assembly: TagPrefix("Bee.Web.WebControls", "bee")>

六、結語
本文中是用土法鍊鋼的方法在撰寫伺服器控制項,一般在實作控制項時會有更好的方式、更易維護的寫法,後續的文章中會陸續介紹相關作法。

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/03/5573.aspx

]]>
jeff377 2008-10-03 23:51:35
[ASP.NET 控制項實作 Day1] 建立 ASP.NET 伺服器控制項專案 https://ithelp.ithome.com.tw/articles/10011408?sc=rss.iron https://ithelp.ithome.com.tw/articles/10011408?sc=rss.iron 在 ASP.NET 開發環境中,我們常使用現成的控制項直接拖曳至頁面中使用,有沒有想過我們也可以開發自用的控制項呢?本文將本文以 VS2008 為開發工具,VB.NET 為開發程式語言,來說明如...]]> 在 ASP.NET 開發環境中,我們常使用現成的控制項直接拖曳至頁面中使用,有沒有想過我們也可以開發自用的控制項呢?本文將本文以 VS2008 為開發工具,VB.NET 為開發程式語言,來說明如何建立「伺服器控制項」專案,以及如何測試開發階段的的伺服器控制項。
一、建立「ASP.NET 伺服器控制項」專案
首先執行功能表「檔案\新增專案」,在專案類型中選擇 Visual Basic -> Web,選取「ASP.NET 伺服器控制項」範本,在名稱文字框中輸入專案名稱,也就是組件的檔案名稱,我們輸入 Bee.Web 為專案名稱,組件檔案為 Bee.Web.dll,按下「確定」鈕即會建立新的「ASP.NET 伺服器控制項」專案。

在新建立「ASP.NET 伺服器控制項」專案中,會預設加入一個伺服器控制項類別(ServerControl1.vb),這個伺服器控制項已經事件幫我們加入一些控制項的程式碼。目前暫不做任何修改,直接使用此控制項來做測試說明。

接下來執行功能表「專案\Bee.Web 屬性」,設定此組件的根命名空間,一般慣用的根命名空間都會與組件名稱相同,以方便加入參考時可以快速找到相關組件。

我們先儲存這個「ASP.NET 伺服器控制項」專案,指定儲存位置,按下「儲存」鈕。整個專案相關檔案,會儲存在以專案名稱的資料夾中。

二、加入測試網站
不要關閉目前「ASP.NET 伺服器控制項」專案,執行功能表「檔案\加入\新網站」,選擇「ASP.NET 網站」,會在方案中加入一個網站,來測試開發階段的伺服器控制項使用。

在測試網站加入參考,選擇「專案」頁籤,此頁籤中會列出該方案中其他可加入參考的專案,選取 Bee.Web 專案,按下「確定」鈕。

先在 Bee.Web 專案中執行「建置」動作,然後切換到測試網站的頁面設計,工具箱中就會出現 ServerControl1 伺服器控制項。這個控制項就可以直接拖曳至頁面中使用,這個控制項只是單純 Render 出 Text 屬性值,你可以在控制項屬性視窗中,更改 Text 屬性值為 "測試文字",就會看到這個控制項顯示 "測試文字"。將測試網站設為啟動專案,按下「F5」執行程式,就會看到該控制在執行階段的結果。

備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格
http://www.dotblogs.com.tw/jeff377/archive/2008/10/02/5562.aspx

]]>
jeff377 2008-10-02 23:16:29


https://matters.news/@twcctz500/undefined-健康是最好的禮物蛋黃油https-www-facebook-com-eggsoil-bafyreifu3vznb6tdpc5axcoyjkxkyoqxzodprbhhg67b4pofzvsilba5be

<?xml version="1.0" encoding="UTF-8" ?> <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"     xmlns:media="http://search.yahoo.com/mrss/">    <channel>        <title>ASP.NET 伺服器控制項開發 :: 2008 iT 邦幫忙鐵人賽</title>        <link>https://ithelp.ithome.com.tw/users/20007956/ironman</link>        <description><![CDATA[ASP.NET 是目前相當熱門的網站開發程式語言,市面上也有一大卡車的書籍在介紹 ASP.NET,不過卻非常少介紹「ASP.NET 伺服器控制項」方面的書籍。在此將透過一系列...]]></description>        <atom:link href="https://ithelp.ithome.com.tw/users/20007956/ironman" rel="self"></atom:link>                <language>zh-TW</language>        <lastBuildDate>Mon, 06 Jun 2022 20:19:06 +0800</lastBuildDate>                    <item>                <title>[ASP.NET 控制項實作 Day29] 解決 DropDownList 成員 Value 值相同產生的問題(續)</title>                <link>https://ithelp.ithome.com.tw/articles/10013458?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10013458?sc=rss.iron</guid>                <description><![CDATA[<p>接續上一文<br /> 接下來還要覆寫 LoadPostData 方法,取得 __EVENTARGUMENT 這個 HiddenField 的值,並判斷與原 SelectedIndex 屬性值是...]]></description>                                    <content:encoded><![CDATA[<p>接續上一文<br /> 接下來還要覆寫 LoadPostData 方法,取得 __EVENTARGUMENT 這個 HiddenField 的值,並判斷與原 SelectedIndex 屬性值是否不同,不同的話傳回 True,使其產生 SelectedIndexChanged 事件。</p> <pre><code>        Protected Overrides Function LoadPostData(ByVal postDataKey As String, ByVal postCollection As NameValueCollection) As Boolean            Dim values As String()            Dim iSelectedIndex As Integer            Me.EnsureDataBound()            values = postCollection.GetValues(postDataKey)            If (Not values Is Nothing) Then                iSelectedIndex = CInt(Me.Page.Request.Form(&quot;__EVENTARGUMENT&quot;))                If (Me.SelectedIndex &lt;&gt; iSelectedIndex) Then                    MyBase.SetPostDataSelection(iSelectedIndex)                    Return True                End If            End If            Return False        End Function </code></pre> <p><strong>四、測試程式</strong><br /> 在 TBDropDownList 的 SelectedIndexChanged 事件撰寫如下測試程式碼。</p> <pre><code>    Protected Sub DropDownList2_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles DropDownList2.SelectedIndexChanged        Dim sText As String        sText = String.Format(&quot;TBDropDownList: Index={0} Value={1}&quot;, DropDownList2.SelectedIndex, DropDownList2.SelectedValue)        Me.Response.Write(sText)    End Sub </code></pre> <p>執行程式,在 TBDropDownList 選取 &quot;王五&quot; 這個選項時,會正常顯示該成員的 SelectedIndex 及 SelectedValue 屬性值。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay29DropDownListValue_112DF/image_thumb_10.png" alt="" /></p> <p>接下選取 Value 值相同的 &quot;陳六&quot; 這個選項,也會正常引發 SelectedIndexChanged ,並顯示該成員的 SelectedIndex 及 SelectedValue 屬性值。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay29DropDownListValue_112DF/image_thumb_11.png" alt="" /></p> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/30/5830.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/30/5830.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-30 21:23:12</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day29] 解決 DropDownList 成員 Value 值相同產生的問題</title>                <link>https://ithelp.ithome.com.tw/articles/10013457?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10013457?sc=rss.iron</guid>                <description><![CDATA[<p>DropDownList 控制頁的成員清單中,若有 ListItem 的 Value 值是相同的情形時,會造成 DropDownList 無法取得正確的 SelectedIndex 屬性值、且無...]]></description>                                    <content:encoded><![CDATA[<p>DropDownList 控制頁的成員清單中,若有 ListItem 的 Value 值是相同的情形時,會造成 DropDownList 無法取得正確的 SelectedIndex 屬性值、且無法正確引發 SelectedIndexChanged 事件的問題;今天剛好在網路上看到有人在詢問此問題,所以本文將說明這個問題的源由,並修改 DropDownList 控制項來解決這個問題。<br /> 程式碼下載:<a href="http://files.dotblogs.com.tw/jeff377/0810/2008103021737321.rar" target="_blank">ASP.NET Server Control - Day29.rar</a></p> <p><strong>一、DropDownList 的成員 Value 值相同產生的問題</strong><br /> 我們先寫個測試程式來描述問題,在頁面上放置一個 DropDownList 控制項,設定 AutoPostBack=True,並加入四個 ListItem,其中 &quot;王五&quot; 及 &quot;陳六&quot; 二個 ListItem 的 Value 值相同。</p> <pre><code>    &lt;asp:DropDownList ID=&quot;DropDownList1&quot; runat=&quot;server&quot; AutoPostBack=&quot;True&quot;&gt;            &lt;asp:ListItem Value=&quot;0&quot;&gt;張三&lt;/asp:ListItem&gt;            &lt;asp:ListItem Value=&quot;1&quot;&gt;李四&lt;/asp:ListItem&gt;            &lt;asp:ListItem Value=&quot;2&quot;&gt;王五&lt;/asp:ListItem&gt;            &lt;asp:ListItem Value=&quot;2&quot;&gt;陳六&lt;/asp:ListItem&gt;    &lt;/asp:DropDownList&gt; </code></pre> <p>在 DropDownList 的 SelectedIndexChanged 事件,輸出 DropDownList 的 SelectedIndex 及 SelectedValue 屬性值。</p> <pre><code>    Protected Sub DropDownList1_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles DropDownList1.SelectedIndexChanged        Dim sText As String        sText = String.Format(&quot;DropDownList: Index={0} Value={1}&quot;, DropDownList1.SelectedIndex, DropDownList1.SelectedValue)        Me.Response.Write(sText)    End Sub </code></pre> <p>執行程式,在 DropDownList 選取 &quot;李四&quot; 這個選項時,會正常顯示該成員的 SelectedIndex 及 SelectedValue 屬性值。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay29DropDownListValue_112DF/image_thumb.png" alt="" /></p> <p>接下來選取 &quot;陳六&quot; 這個選項時,竟然發生奇怪的現象,DorpDownList 竟然顯示相同 Value 值的 &quot;王五&quot; 這個成員的 SelectedIndex 及 SelectedValue 屬性值。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay29DropDownListValue_112DF/image_thumb_6.png" alt="" /><br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay29DropDownListValue_112DF/image_thumb_7.png" alt="" /></p> <p><strong>二、問題發生的原因</strong><br /> 我們先看一下 DropDownList 輸出到用戶端的 HTML 原始碼。</p> <pre><code>&lt;select name=&quot;DropDownList1&quot; onchange=&quot;javascript:setTimeout('__doPostBack(\'DropDownList1\',\'\')', 0)&quot; id=&quot;DropDownList1&quot;&gt; &lt;option selected=&quot;selected&quot; value=&quot;0&quot;&gt;張三&lt;/option&gt; &lt;option value=&quot;1&quot;&gt;李四&lt;/option&gt; &lt;option value=&quot;2&quot;&gt;王五&lt;/option&gt; &lt;option value=&quot;2&quot;&gt;陳六&lt;/option&gt; &lt;/select&gt; </code></pre> <p>DropDownList 是呼叫 __doPostBack 函式,只傳入 eventTarget參數 (對應到 __EVENTTARGET 這個 HiddenField) 為 DropDownList 的 ClientID;當 PostBack 回伺服端時,在 DropDownList 的 LoadPostData 方法中,會取得用戶端選取的 SelectedValue 值,並去尋找對應的成員的 SelectedIndex 值。可是問題來了,因為 &quot;王五&quot; 與 &quot;陳六&quot; 的 Value 是相同的值,當在尋找符合 Value 值的成員時,前面的選項 &quot;王五&quot; 會先符合條件而傳回該 Index 值,所以先造成取得錯誤的 SelectedIndex 。</p> <pre><code>Protected Overridable Function LoadPostData(ByVal postDataKey As String, ByVal postCollection As NameValueCollection) As Boolean    Dim values As String() = postCollection.GetValues(postDataKey)    Me.EnsureDataBound    If (Not values Is Nothing) Then        MyBase.ValidateEvent(postDataKey, values(0))        Dim selectedIndex As Integer = Me.Items.FindByValueInternal(values(0), False)        If (Me.SelectedIndex &lt;&gt; selectedIndex) Then            MyBase.SetPostDataSelection(selectedIndex)            Return True        End If    End If    Return False End Function </code></pre> <p><strong>三、修改 DropDownList 控制項來解決問題</strong><br /> 要解決這個問題最好的方式就是直接修改 DropDownList 控制項,自行處理前端呼叫 __doPostBack 的動作,將用戶端 DropDownList 選擇 SelectedIndex 一併傳回伺服端。所以我們繼承 DropDownList 命名為 TBDropDownList,覆寫 AddAttributesToRender 來自行輸出 PostBack 的用戶端指令碼,我們會用一個變數記錄 AutoPostBack 屬性,並強制將 AutoPostBack 屬性值設為 False,這是為了不要 MyBase 產生 PostBack 的指令碼;然後再自行輸出 AutoPostBack 用戶端指令碼,其中 __doPostBack 的 eventArgument 參數 (對應到 __EVENTARGUMENT 這個 HiddenField) 傳入 this.selectedIndex。</p> <pre><code>        Protected Overrides Sub AddAttributesToRender(ByVal writer As HtmlTextWriter)            Dim bAutoPostBack As Boolean            Dim sScript As String            '記錄 AutoPostBack 值,並將 AutoPostBack 設為 False,不要讓 MyBase 產生 PostBack 的指令碼            bAutoPostBack = Me.AutoPostBack            Me.AutoPostBack = False            MyBase.AddAttributesToRender(writer)            If bAutoPostBack Then                MyBase.Attributes.Remove(&quot;onchange&quot;)                sScript = String.Format(&quot;__doPostBack('{0}',{1})&quot;, Me.ClientID, &quot;this.selectedIndex&quot;)                writer.AddAttribute(HtmlTextWriterAttribute.Onchange, sScript)                Me.AutoPostBack = True            End If        End Sub </code></pre> <p>在頁面上放置一個 TBDropDownList 控制項,設定與上述案例相同的成員清單。</p> <pre><code>        &lt;bee:TBDropDownList ID=&quot;DropDownList2&quot; runat=&quot;server&quot; AutoPostBack=&quot;True&quot;&gt;            &lt;asp:ListItem Value=&quot;0&quot;&gt;張三&lt;/asp:ListItem&gt;            &lt;asp:ListItem Value=&quot;1&quot;&gt;李四&lt;/asp:ListItem&gt;            &lt;asp:ListItem Value=&quot;2&quot;&gt;王五&lt;/asp:ListItem&gt;            &lt;asp:ListItem Value=&quot;2&quot;&gt;陳六&lt;/asp:ListItem&gt;        &lt;/bee:TBDropDownList&gt; </code></pre> <p>執行程式查看 TBDropDownList 控制項的 HTML 原始碼,呼叫 __doPostBack 函式的參數已經被修改,eventArgument 參數會傳入該控制項的 selectedIndex。</p> <pre><code>&lt;select name=&quot;DropDownList2&quot; id=&quot;DropDownList2&quot; onchange=&quot;__doPostBack('DropDownList2',this.selectedIndex)&quot;&gt; &lt;option selected=&quot;selected&quot; value=&quot;0&quot;&gt;張三&lt;/option&gt; &lt;option value=&quot;1&quot;&gt;李四&lt;/option&gt; &lt;option value=&quot;2&quot;&gt;王五&lt;/option&gt; &lt;option value=&quot;2&quot;&gt;陳六&lt;/option&gt; &lt;/select&gt; </code></pre> <p>[超過字數限制,下一篇接續本文]</p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-30 21:15:23</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day28] 圖形驗證碼控制項(續)</title>                <link>https://ithelp.ithome.com.tw/articles/10013365?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10013365?sc=rss.iron</guid>                <description><![CDATA[<p>接續一上文<br /> <strong>二、實作圖形驗證碼控制項</strong><br /> 雖然我們可以使用 Image 控制項來呈現 ValidateCode.aspx 頁面產生的驗證碼圖...]]></description>                                    <content:encoded><![CDATA[<p>接續一上文<br /> <strong>二、實作圖形驗證碼控制項</strong><br /> 雖然我們可以使用 Image 控制項來呈現 ValidateCode.aspx 頁面產生的驗證碼圖形,可是這樣只處理一半的動作,因為沒有處理「使用者輸入的驗證碼」是否與「圖形驗證碼」相符,所以我們將實作一個圖形驗證碼控制項,來處理掉所有相關動作。<br /> 即然上面的示範使用 Image 控制項來呈現驗證碼,所以圖形驗證碼控制項就繼承 Image 命名為 TBValidateCode。</p> <pre><code>    &lt; _    Description(&quot;圖形驗證碼控制項&quot;), _    ToolboxData(&quot;&lt;{0}:TBValidateCode runat=server&gt;&lt;/{0}:TBValidateCode&gt;&quot;) _    &gt; _    Public Class TBValidateCode        Inherits System.Web.UI.WebControls.Image        End </code></pre> <p>新增 ValidateCodeUrl 屬性,設定圖形驗證碼產生頁面的網址。</p> <pre><code>        ''' &lt;summary&gt;        ''' 圖形驗證碼產生頁面網址。        ''' &lt;/summary&gt;        &lt; _        Description(&quot;圖形驗證碼產生頁面網址&quot;), _        DefaultValue(&quot;&quot;) _        &gt; _        Public Property ValidateCodeUrl() As String            Get                Return FValidateCodeUrl            End Get            Set(ByVal value As String)                FValidateCodeUrl = value            End Set        End Property </code></pre> <p>覆寫 Render 方法,若未設定 ValidateCodeUrl 屬性,則預設為 ~/Page/ValidateCode.aspx 這個頁面。另外我們在圖形的 ondbclick 加上一段用戶端指令碼,其作用是讓用戶可以滑鼠二下來重新產生一個驗證碼圖形。</p> <pre><code>        Protected Overrides Sub Render(ByVal writer As System.Web.UI.HtmlTextWriter)            Dim sUrl As String            Dim sScript As String            sUrl = Me.ValidateCodeUrl            If String.IsNullOrEmpty(sUrl) Then                sUrl = &quot;~/Page/ValidateCode.aspx&quot;            End If            If Me.BorderWidth = Unit.Empty Then                Me.BorderWidth = Unit.Pixel(1)            End If            If Me.AlternateText = String.Empty Then                Me.AlternateText = &quot;圖形驗證碼&quot;            End If            Me.ToolTip = &quot;滑鼠點二下可重新產生驗證碼&quot;            Me.ImageUrl = sUrl            If Not Me.DesignMode Then                sScript = String.Format(&quot;this.src='{0}?flag='+Math.random();&quot;, Me.Page.ResolveClientUrl(sUrl))                Me.Attributes(&quot;ondblclick&quot;) = sScript            End If            Me.Style(HtmlTextWriterStyle.Cursor) = &quot;pointer&quot;            MyBase.Render(writer)        End Sub </code></pre> <p>另外新增一個 ValidateCode 方法,用來檢查輸入驗證碼是否正確。還記得我們在產生驗證碼圖形時,同時把該驗證碼的值寫入 Session(&quot;_ValidateCode&quot;) 中吧,所以這個方法只是把用戶輸入的值與 Seesion 中的值做比對。</p> <pre><code>        ''' &lt;summary&gt;        ''' 檢查輸入驗證碼是否正確。        ''' &lt;/summary&gt;        ''' &lt;param name=&quot;Code&quot;&gt;輸入驗證碼。&lt;/param&gt;        ''' &lt;returns&gt;驗證成功傳回 True,反之傳回 False。&lt;/returns&gt;        Public Function ValidateCode(ByVal Code As String) As Boolean            If Me.Page.Session(SessionKey) Is Nothing Then Return False            If SameText(CCStr(Me.Page.Session(SessionKey)), Code) Then                Return True            Else                Return False            End If        End Function </code></pre> <p><strong>三、測試程式</strong><br /> 在頁面放置一個 TBValidateCode 控制項,另外加一個文字框及按鈕,供使用者輸入驗證碼後按下「確定」鈕後到伺服端做輸入值比對的動作。</p> <pre><code>        &lt;bee:TBValidateCode ID=&quot;TBValidateCode1&quot; runat=&quot;server&quot; /&gt;        &lt;bee:TBTextBox ID=&quot;txtCode&quot; runat=&quot;server&quot;&gt;&lt;/bee:TBTextBox&gt;        &lt;bee:TBButton ID=&quot;TBButton1&quot; runat=&quot;server&quot; Text=&quot;確定&quot; /&gt; </code></pre> <p>在「確定」鈕的 Click 事件中,我們使用 TBValidateCode 控制項的 ValidateCode 方法判斷驗證碼輸入的正確性。</p> <pre><code>    Protected Sub TBButton1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles TBButton1.Click        If TBValidateCode1.ValidateCode(txtCode.Text) Then            Me.Response.Write(&quot;驗證碼輸入正確&quot;)        Else            Me.Response.Write(&quot;驗證碼輸入錯誤!&quot;)        End If    End Sub </code></pre> <p>執行程式,頁面就會隨機產生一個驗證碼圖形。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay28_1B7F/image_thumb.png" alt="" /></p> <p>輸入正確的值按「確定」鈕,就會顯示「驗證碼輸入正確」的訊息。因為我們在同一頁面測試的關係,你會發現 PostBack 後驗證碼圖形又會重新產生,一般正常的做法是驗證正確後就導向另一個頁面。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay28_1B7F/image_thumb_1.png" alt="" /></p> <p>當我們輸入錯誤的值,就會顯示「驗證碼輸入錯誤!」的訊息。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay28_1B7F/image_thumb_2.png" alt="" /></p> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/29/5818.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/29/5818.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-29 20:34:22</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day28] 圖形驗證碼控制項</title>                <link>https://ithelp.ithome.com.tw/articles/10013361?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10013361?sc=rss.iron</guid>                <description><![CDATA[<p>在網頁上常把圖形驗證碼應用在登入或貼文的頁面中,因為圖形驗證碼具有機器不易識別的特性,可以防止機器人程式惡意的存取網頁。在本文中將實作一個圖形驗證碼的伺服器控制項,透過簡單的屬性設定就可以輕易地...]]></description>                                    <content:encoded><![CDATA[<p>在網頁上常把圖形驗證碼應用在登入或貼文的頁面中,因為圖形驗證碼具有機器不易識別的特性,可以防止機器人程式惡意的存取網頁。在本文中將實作一個圖形驗證碼的伺服器控制項,透過簡單的屬性設定就可以輕易地在網頁上套用圖形驗證碼。<br /> 程式碼下載:<a href="http://files.dotblogs.com.tw/jeff377/0810/20081029202355938.rar" target="_blank">ASP.NET Server Control - Day28.rar</a></p> <p><strong>一、產生圖形驗證碼</strong><br /> 我們先準備一個產生圖形驗證碼的頁面 (ValidateCode.aspx),這個頁面主要是繪製驗證碼圖形,並將其寫入記憶體資料流,最後使用 Response.BinaryWrite 將圖形輸出傳遞到用戶端。當我們輸出此驗證碼圖形的同時,會使用 Session(&quot;_ValidateCode&quot;) 來記錄驗證碼的值,以便後續與使用者輸入驗證碼做比對之用。</p> <pre><code>Partial Class ValidateCode    Inherits System.Web.UI.Page    ''' &lt;summary&gt;    ''' 產生圖形驗證碼。    ''' &lt;/summary&gt;    Public Function CreateValidateCodeImage(ByRef Code As String, ByVal CodeLength As Integer, _        ByVal Width As Integer, ByVal Height As Integer, ByVal FontSize As Integer) As Bitmap        Dim sCode As String = String.Empty        '顏色列表,用於驗證碼、噪線、噪點        Dim oColors As Color() = { _            Drawing.Color.Black, Drawing.Color.Red, Drawing.Color.Blue, Drawing.Color.Green, _            Drawing.Color.Orange, Drawing.Color.Brown, Drawing.Color.Brown, Drawing.Color.DarkBlue}        '字體列表,用於驗證碼        Dim oFontNames As String() = {&quot;Times New Roman&quot;, &quot;MS Mincho&quot;, &quot;Book Antiqua&quot;, _                                      &quot;Gungsuh&quot;, &quot;PMingLiU&quot;, &quot;Impact&quot;}        '驗證碼的字元集,去掉了一些容易混淆的字元        Dim oCharacter As Char() = {&quot;2&quot;c, &quot;3&quot;c, &quot;4&quot;c, &quot;5&quot;c, &quot;6&quot;c, &quot;8&quot;c, _                                    &quot;9&quot;c, &quot;A&quot;c, &quot;B&quot;c, &quot;C&quot;c, &quot;D&quot;c, &quot;E&quot;c, _                                    &quot;F&quot;c, &quot;G&quot;c, &quot;H&quot;c, &quot;J&quot;c, &quot;K&quot;c, &quot;L&quot;c, _                                    &quot;M&quot;c, &quot;N&quot;c, &quot;P&quot;c, &quot;R&quot;c, &quot;S&quot;c, &quot;T&quot;c, _                                    &quot;W&quot;c, &quot;X&quot;c, &quot;Y&quot;c}        Dim oRnd As New Random()        Dim oBmp As Bitmap        Dim oGraphics As Graphics        Dim N1 As Integer        Dim oPoint1 As Drawing.Point        Dim oPoint2 As Drawing.Point        Dim sFontName As String        Dim oFont As Font        Dim oColor As Color        '生成驗證碼字串        For N1 = 0 To CodeLength - 1            sCode += oCharacter(oRnd.Next(oCharacter.Length))        Next        oBmp = New Bitmap(Width, Height)        oGraphics = Graphics.FromImage(oBmp)        oGraphics.Clear(Drawing.Color.White)        Try            For N1 = 0 To 4                '畫噪線                oPoint1.X = oRnd.Next(Width)                oPoint1.Y = oRnd.Next(Height)                oPoint2.X = oRnd.Next(Width)                oPoint2.Y = oRnd.Next(Height)                oColor = oColors(oRnd.Next(oColors.Length))                oGraphics.DrawLine(New Pen(oColor), oPoint1, oPoint2)            Next            For N1 = 0 To sCode.Length - 1                '畫驗證碼字串                sFontName = oFontNames(oRnd.Next(oFontNames.Length))                oFont = New Font(sFontName, FontSize, FontStyle.Italic)                oColor = oColors(oRnd.Next(oColors.Length))                oGraphics.DrawString(sCode(N1).ToString(), oFont, New SolidBrush(oColor), CSng(N1) * FontSize + 10, CSng(8))            Next            For i As Integer = 0 To 30                '畫噪點                Dim x As Integer = oRnd.Next(oBmp.Width)                Dim y As Integer = oRnd.Next(oBmp.Height)                Dim clr As Color = oColors(oRnd.Next(oColors.Length))                oBmp.SetPixel(x, y, clr)            Next            Code = sCode            Return oBmp        Finally            oGraphics.Dispose()        End Try    End Function    ''' &lt;summary&gt;    ''' 產生圖形驗證碼。    ''' &lt;/summary&gt;    Public Sub CreateValidateCodeImage(ByRef MemoryStream As MemoryStream, _        ByRef Code As String, ByVal CodeLength As Integer, _        ByVal Width As Integer, ByVal Height As Integer, ByVal FontSize As Integer)        Dim oBmp As Bitmap        oBmp = CreateValidateCodeImage(Code, CodeLength, Width, Height, FontSize)        Try            oBmp.Save(MemoryStream, ImageFormat.Png)        Finally            oBmp.Dispose()        End Try    End Sub    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load        Dim sCode As String = String.Empty        '清除該頁輸出緩存,設置該頁無緩存        Response.Buffer = True        Response.ExpiresAbsolute = System.DateTime.Now.AddMilliseconds(0)        Response.Expires = 0        Response.CacheControl = &quot;no-cache&quot;        Response.AppendHeader(&quot;Pragma&quot;, &quot;No-Cache&quot;)        '將驗證碼圖片寫入記憶體流,並將其以 &quot;image/Png&quot; 格式輸出        Dim oStream As New MemoryStream()        Try            CreateValidateCodeImage(oStream, sCode, 4, 100, 40, 18)            Me.Session(&quot;_ValidateCode&quot;) = sCode            Response.ClearContent()            Response.ContentType = &quot;image/Png&quot;            Response.BinaryWrite(oStream.ToArray())        Finally            '釋放資源            oStream.Dispose()        End Try    End Sub End Class </code></pre> <p>我們將此頁面置於 ~/Page/ValidateCode.aspx,當要使用此頁面的圖形驗證碼,只需要在使用 Image 控制項,設定 ImageUrl 為此頁面即可。</p> <pre><code>&lt;asp:Image ID=&quot;imgValidateCode&quot; runat=&quot;server&quot; ImageUrl=&quot;~/Page/ValidateCode.aspx&quot; /&gt; </code></pre> <p>[超過字數限制,下一篇接續本文]</p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-29 20:31:45</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day27] 控制項依 FormView CurrentMode 自行設定狀態(續2)</title>                <link>https://ithelp.ithome.com.tw/articles/10013241?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10013241?sc=rss.iron</guid>                <description><![CDATA[<p>接續上一文<br /> 接下來設定做為新增、編輯使用的 TBFormView 控制項,我們只使用 EditItemTemplate 來同時處理新增、刪除,所以 EditItemTemplate ...]]></description>                                    <content:encoded><![CDATA[<p>接續上一文<br /> 接下來設定做為新增、編輯使用的 TBFormView 控制項,我們只使用 EditItemTemplate 來同時處理新增、刪除,所以 EditItemTemplate 需要同時具有「新增」、「更新」、「取消」三個按鈕。其中 ProductID 為主索引欄位,所以我們使用 TBTextBox 來繫結 ProductID 欄位,設定 FormViewModeState.InsertMode=&quot;Enable&quot; 使控制項在新增模式時為可編輯,設定 FormViewModeState.EditMode=&quot;Disable&quot; 使控制項在修改模式是唯讀的。</p> <pre><code>        &lt;bee:TBFormView ID=&quot;TBFormView1&quot; runat=&quot;server&quot; DataKeyNames=&quot;ProductID&quot; DataSourceID=&quot;SqlDataSource1&quot;            DefaultMode=&quot;Edit&quot; SingleTemplate=&quot;EditItemTemplate&quot; BackColor=&quot;White&quot; BorderColor=&quot;#CCCCCC&quot;            BorderStyle=&quot;None&quot; BorderWidth=&quot;1px&quot; CellPadding=&quot;3&quot; GridLines=&quot;Both&quot; Visible=&quot;False&quot;&gt;            &lt;FooterStyle BackColor=&quot;White&quot; ForeColor=&quot;#000066&quot; /&gt;            &lt;RowStyle ForeColor=&quot;#000066&quot; /&gt;            &lt;EditItemTemplate&gt;                ProductID:                &lt;bee:TBTextBox ID=&quot;TextBox1&quot; runat=&quot;server&quot; Text='&lt;%# Bind(&quot;ProductID&quot;) %&gt;'&gt;                  &lt;FormViewModeState EditMode=&quot;Disable&quot; InsertMode=&quot;Enable&quot;&gt;                  &lt;/FormViewModeState&gt;                &lt;/bee:TBTextBox&gt;                '省略                &lt;asp:LinkButton ID=&quot;LinkButton1&quot; runat=&quot;server&quot; CausesValidation=&quot;True&quot; CommandName=&quot;Insert&quot;                    Text=&quot;新增&quot; /&gt;                 &lt;asp:LinkButton ID=&quot;UpdateButton&quot; runat=&quot;server&quot; CausesValidation=&quot;True&quot; CommandName=&quot;Update&quot;                    Text=&quot;更新&quot; /&gt;                 &lt;asp:LinkButton ID=&quot;UpdateCancelButton&quot; runat=&quot;server&quot; CausesValidation=&quot;False&quot;                    CommandName=&quot;Cancel&quot; Text=&quot;取消&quot; /&gt;            &lt;/EditItemTemplate&gt;        &lt;/bee:TBFormView&gt; </code></pre> <p><strong>2. 測試新增模式</strong><br /> 接下來執行程式,一開始為瀏覽模式,以 TBGridView 來呈現資料。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay27FormViewCurrentMode_E5A/image_thumb_2.png" alt="" /></p> <p>按下 Header 的「新增」鈕,就會隱藏 TBGridView,而切換到 TBFormView 的新增模式。其中繫結 ProductID 欄位的 TBTextBox 為可編輯模式,而下方的按鈕只會顯示「新增」及「取消」鈕。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay27FormViewCurrentMode_E5A/image_thumb_3.png" alt="" /></p> <p>在新增模式輸入完畢後,按下「新增」鈕,資料錄就會被寫入資料庫。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay27FormViewCurrentMode_E5A/image_thumb_4.png" alt="" /></p> <p><strong>3. 測試修改模式</strong><br /> 接下來測試修改模式,按下「編輯」鈕,就會隱藏 TBGridView,而切換到 TBFormView 的修改模式。其中繫結 ProductID 欄位的 TBTextBox 為唯讀模式,而下方的按鈕只會顯示「更新」及「取消」鈕。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay27FormViewCurrentMode_E5A/image_thumb_5.png" alt="" /></p> <p>在修改模式輸入完畢後,按下「更新」鈕,資料錄就會被寫入資料庫。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay27FormViewCurrentMode_E5A/image_thumb_6.png" alt="" /></p> <p><strong>4. 頁面程式碼</strong><br /> 示範了上述的操作後,接下來我們回頭看一下頁面的程式碼。你沒看錯,筆者也沒貼錯,真的是一行程式碼都沒有,因為所有相關動作都由控制項處理掉了。</p> <pre><code>Partial Class Day27    Inherits System.Web.UI.Page End Class </code></pre> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/28/5806.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/28/5806.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-28 13:57:23</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day27] 控制項依 FormView CurrentMode 自行設定狀態(續1)</title>                <link>https://ithelp.ithome.com.tw/articles/10013239?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10013239?sc=rss.iron</guid>                <description><![CDATA[<p>接續上一文<br /> <strong>二、讓 TextBox 控制項可自行維護狀態</strong><br /> 接下來擴展 TextBox 控制項,繼承 TextBox 命名為 TBText...]]></description>                                    <content:encoded><![CDATA[<p>接續上一文<br /> <strong>二、讓 TextBox 控制項可自行維護狀態</strong><br /> 接下來擴展 TextBox 控制項,繼承 TextBox 命名為 TBTextBox。新增 FormViewModeState 屬性 (TBFormViewModeState 型別),依 FormView Mode 來設定控制項狀。並覆寫 PreRender 方法,在此方法中呼叫 DoFormViewModeStatus 私有方法,依 FormView 的模式來處理控制項狀態。</p> <pre><code>    ''' &lt;summary&gt;    ''' 文字框控制項。    ''' &lt;/summary&gt;    &lt; _    Description(&quot;文字框控制項。&quot;), _    ToolboxData(&quot;&lt;{0}:TBTextBox runat=server&gt;&lt;/{0}:TBTextBox&gt;&quot;) _    &gt; _    Public Class TBTextBox        Inherits TextBox        Private FFormViewModeState As TBFormViewModeState        ''' &lt;summary&gt;        ''' 依 FormViewMode 來設定控制項狀態。        ''' &lt;/summary&gt;        &lt; _        Category(WebCommon.Category.Behavior), _        NotifyParentProperty(True), _        DesignerSerializationVisibility(DesignerSerializationVisibility.Content), _        PersistenceMode(PersistenceMode.InnerProperty), _        DefaultValue(&quot;&quot;) _        &gt; _        Public ReadOnly Property FormViewModeState() As TBFormViewModeState            Get                If FFormViewModeState Is Nothing Then                    FFormViewModeState = New TBFormViewModeState                End If                Return FFormViewModeState            End Get        End Property        ''' &lt;summary&gt;        ''' 處理控制項狀態。        ''' &lt;/summary&gt;        Private Sub DoControlStatus(ByVal ControlStatus As EControlState)            Select Case ControlStatus                Case EControlState.Enable                    Me.Enabled = True                Case EControlState.Disable                    Me.Enabled = False                Case EControlState.Hide                    Me.Visible = False            End Select        End Sub        ''' &lt;summary&gt;        ''' 依 FormView 的模式來處理控制項狀態。        ''' &lt;/summary&gt;        Private Sub DoFormViewModeStatus()            Dim oFormView As FormView            '若控制項置於 FormView 中,則依 FormView 的模式來處理控制項狀態            If TypeOf Me.BindingContainer Is FormView Then                oFormView = DirectCast(Me.BindingContainer, FormView)                Select Case oFormView.CurrentMode                    Case FormViewMode.Insert                        DoControlStatus(Me.FormViewModeState.InsertMode)                    Case FormViewMode.Edit                        DoControlStatus(Me.FormViewModeState.EditMode)                    Case FormViewMode.ReadOnly                        DoControlStatus(Me.FormViewModeState.BrowseMode)                End Select            End If        End Sub        ''' &lt;summary&gt;        ''' 覆寫。引發 PreRender 事件。        ''' &lt;/summary&gt;        Protected Overrides Sub OnPreRender(ByVal e As EventArgs)            MyBase.OnPreRender(e)            '依 FormView 的模式來處理控制項狀態            DoFormViewModeStatus()        End Sub    End Class </code></pre> <p><strong>三、測試程式</strong><br /> <strong>1. 設定控制項相關屬性</strong><br /> 我們使用 Northwnd 資料庫的 Products資料表為例,以 GridView+FormView 示範資料「新增/修改/刪除」的操作。在頁面拖曳 SqlDataSource 控制項後,在頁面上的使用 TBGridView 來顯示瀏覽資料。TBGridView 的 FormViewID 設為關連的 TBFormVIew 控制項;另外有使用到 TBCommandField,設定 ShowHeaderNewButton=True,讓命令列具有「新增」鈕。</p> <pre><code>        &lt;bee:TBGridView ID=&quot;TBGridView1&quot; runat=&quot;server&quot; AutoGenerateColumns=&quot;False&quot; DataKeyNames=&quot;ProductID&quot;            DataSourceID=&quot;SqlDataSource1&quot; FormViewID=&quot;TBFormView1&quot;&gt;            &lt;Columns&gt;                &lt;bee:TBCommandField ShowDeleteButton=&quot;True&quot; ShowEditButton=&quot;True&quot;                    ShowHeaderNewButton=&quot;True&quot; &gt;                &lt;/bee:TBCommandField&gt;                                '省略                            &lt;/Columns&gt;        &lt;/bee:TBGridView&gt; </code></pre> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/28/5806.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/28/5806.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-28 13:53:32</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day27] 控制項依 FormView CurrentMode 自行設定狀態</title>                <link>https://ithelp.ithome.com.tw/articles/10013233?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10013233?sc=rss.iron</guid>                <description><![CDATA[<p>在 <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/05/12/3936.aspx" target="_blank">GridV...]]></description>                                    <content:encoded><![CDATA[<p>在 <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/05/12/3936.aspx" target="_blank">GridView+FormView 示範資料 新增/修改/刪除(進階篇:伺服器控制項)</a> 一文中,示範了擴展 GridView 及 FormView 控制項,讓 GridView 可以透過屬性與 FormView 做關連來處理資料的「新增/修改/刪除」的動作。因為在該案例中,只使用 FormView 的 EditTemplate 同時處理「新增」及「修改」的動作,所以還需要自行撰寫部分程式碼去判斷控制項在新增或修改的啟用狀態,例如編號欄位在新增時為啟用,修改時就不啟用。在該文最後也提及其實有辨法讓這個案例達到零程式碼的目標,那就是讓控制項 (如 TextBox) 自行判斷所在的 FormView 的 CurrentMode,自行決定本身是否要「啟用/不啟用」、「顯示/隱藏」等狀態。本文以 TextBox 為例,說明如何修改 TextBox 讓它可以達到上述的需求。<br /> 程式碼下載:<a href="http://files.dotblogs.com.tw/jeff377/0810/20081028133154164.rar" target="_blank">ASP.NET Server Control - Day27.rar</a><br /> Northwnd 資料庫下載:<a href="http://files.dotblogs.com.tw/jeff377/0810/2008102364857537.rar" target="_blank">NORTHWND.rar</a></p> <p><strong>一、TBFormViewModeState 類別</strong><br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay27FormViewCurrentMode_E5A/image_thumb.png" alt="" /><br /> 我們先定義 EControlState (控制項狀態) 列舉,描述控制項在特定模式的狀態為何。</p> <pre><code>    ''' &lt;summary&gt;    ''' 控制項狀態列舉。    ''' &lt;/summary&gt;    Public Enum EControlState        ''' &lt;summary&gt;        ''' 不設定。        ''' &lt;/summary&gt;        NotSet = 0        ''' &lt;summary&gt;        ''' 啟用。        ''' &lt;/summary&gt;        Enable = 1        ''' &lt;summary&gt;        ''' 不啟用。        ''' &lt;/summary&gt;        Disable = 2        ''' &lt;summary&gt;        ''' 隱藏。        ''' &lt;/summary&gt;        Hide = 3    End Enum </code></pre> <p>再來定義 TBFormViewModeState 類別,用來設定控制項在各種 FormView 模式 (瀏覽、新增、修改) 中的控制項狀態。</p> <pre><code>''' &lt;summary&gt; ''' 依 FormViewMode 來設定控制項狀態。 ''' &lt;/summary&gt; &lt; _ Serializable(), _ TypeConverter(GetType(ExpandableObjectConverter)) _ &gt; _ Public Class TBFormViewModeState    Private FInsertMode As EControlState = EControlState.NotSet    Private FEditMode As EControlState = EControlState.NotSet    Private FBrowseMode As EControlState = EControlState.NotSet    ''' &lt;summary&gt;    ''' 在新增模式(FormViewMode=Insert)的控制項狀態。    ''' &lt;/summary&gt;    &lt; _    NotifyParentProperty(True), _    DefaultValue(GetType(EControlState), &quot;NotSet&quot;) _    &gt; _    Public Property InsertMode() As EControlState        Get            Return FInsertMode        End Get        Set(ByVal value As EControlState)            FInsertMode = value        End Set    End Property    ''' &lt;summary&gt;    ''' 在編輯模式(FormViewMode=Edit)的控制項狀態。    ''' &lt;/summary&gt;    &lt; _    NotifyParentProperty(True), _    DefaultValue(GetType(EControlState), &quot;NotSet&quot;) _    &gt; _    Public Property EditMode() As EControlState        Get            Return FEditMode        End Get        Set(ByVal value As EControlState)            FEditMode = value        End Set    End Property    ''' &lt;summary&gt;    ''' 在瀏覽模式(FormViewMode=ReadOnly)的控制項狀態。    ''' &lt;/summary&gt;    &lt; _    NotifyParentProperty(True), _    DefaultValue(GetType(EControlState), &quot;NotSet&quot;) _    &gt; _    Public Property BrowseMode() As EControlState        Get            Return FBrowseMode        End Get        Set(ByVal value As EControlState)            FBrowseMode = value        End Set    End Property End Class </code></pre> <p>定義為 TBFormViewModeState 型別的屬性是屬於複雜屬性,要套用 TypeConverter(GetType(ExpandableObjectConverter)),讓該屬性可在屬性視窗 (PropertyGrid) 擴展以便設定屬性值,如下圖所示。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay27FormViewCurrentMode_E5A/image_thumb_1.png" alt="" /></p> <p>[超過字數限制,下一篇接續本文]</p> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/28/5806.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/28/5806.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-28 13:45:43</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day26] 讓你的 GridView 與眾不同</title>                <link>https://ithelp.ithome.com.tw/articles/10013209?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10013209?sc=rss.iron</guid>                <description><![CDATA[<p>在網路上可以找到相當多擴展 GridView 控制項功能的文章,在筆者的部落格中也有多篇提及擴展 GridView、DataControlField、BoundFIeld 功能的相關文章,在本文...]]></description>                                    <content:encoded><![CDATA[<p>在網路上可以找到相當多擴展 GridView 控制項功能的文章,在筆者的部落格中也有多篇提及擴展 GridView、DataControlField、BoundFIeld 功能的相關文章,在本文將這些關於擴展 GridView 控制項功能及欄位類別的相關文章做一整理簡介,若需要擴展 GridView 相關功能時可以做為參考。<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/05/22/4105.aspx" target="_blank"><strong>1. 擴展 GridView 控制項 - 無資料時顯示標題列</strong></a><br /> 摘要:當 GridView 繫結的 DataSource 資料筆數為 0 時,會依 EmptyDataTemplate 及 EmptyDataText 的設定來顯示無資料的狀態。若我們希望 GridView 在無資料時,可以顯示欄位標題,有一種作法是在 EmptyDataTemplate 中手動在設定一個標題列,不過這種作法很麻煩。本文擴展 GridView 控制項,直接透過屬性設定就可以在無資料顯示欄位標題。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0805/GridView_DAA6/image_thumb.png" alt="" /></p> <p><a href="http://www.dotblogs.com.tw/jeff377/archive/2008/05/17/4028.aspx" target="_blank"><strong>2. 擴展 GridView 控制項 - 支援 Excel 及 Word 匯出</strong></a><br /> 摘要:GridView 匯出 Excel 及 Word 文件是蠻常使用的需求,此篇文章將擴展 GridView 控制項提供匯出 Excel 及 Word 文件的方法。一般在 GridView 匯出的常見下列問題也會在此一併被解決。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0805/GridViewExcelWord_14C22/image_thumb_1.png" alt="" /><br /> <img src="http://files.dotblogs.com.tw/jeff377/0805/GridViewExcelWord_14C22/image_thumb_2.png" alt="" /></p> <p><a href="http://www.dotblogs.com.tw/jeff377/archive/2008/05/12/3936.aspx" target="_blank"><strong>3. GridView+FormView 示範資料 新增/修改/刪除(進階篇:伺服器控制項)</strong></a><br /> 摘要:擴展 GridView 及 FormView 控制項,在 GridView 控制項中新增 FormViewID 屬性,關連至指定的 FormView 控制項 ID,就可以讓 GridView 結合 FormView 來做資料異動的動作。</p> <p><a href="http://www.dotblogs.com.tw/jeff377/archive/2008/03/17/1766.aspx" target="_blank"><strong>4. 擴展 CommandField 類別 - 刪除提示訊息</strong></a><br /> 摘要:新增 DeleteConfirmMessage 屬性,設定刪除提示確認訊息。<br /> <img src="http://blog.blueshop.com.tw/images/blog_blueshop_com_tw/jeff377/1525/r_Ex19.1.png" alt="" /></p> <p><a href="http://www.dotblogs.com.tw/jeff377/archive/2008/03/17/1767.aspx" target="_blank"><strong>5. 擴展 CommandField 類別 - 刪除提示訊息含欄位值</strong></a><br /> 摘要:設定刪除提示確認訊息中可包含指定 DataField 欄位值,明確提示要刪除的資料列。<br /> <img src="http://blog.blueshop.com.tw/images/blog_blueshop_com_tw/jeff377/1525/r_Ex20.1.png" alt="" /></p> <p><a href="http://www.dotblogs.com.tw/jeff377/archive/2008/03/17/1710.aspx" target="_blank"><strong>6. 讓 CheckBoxField 繫結非布林值(0 或 1)欄位</strong></a><br /> 摘要:CheckBoxField 若繫結的欄位值為 0 或 1 時 (非布林值) 會發生錯誤,本文擴展 CheckBoxField 類別,讓 CheckBoxField 有辨法繫結 0 或 1 的欄位值。</p> <p><a href="http://www.dotblogs.com.tw/jeff377/archive/2008/05/21/4093.aspx" target="_blank"><strong>7. 擴展 CheckBoxField 類別 - 支援非布林值的雙向繫結</strong></a><br /> 摘要:CheckBoxField 繫結的欄位值並無法直接使用 CBool 轉型為布林值,例如 &quot;T/F&quot;、&quot;是/否&quot; 之類的資料,若希望使用 CheckBoxField 來顯示就比較麻煩,一般的作法都是轉為 TemplateField,自行撰寫資料繫結的函式,而且只能支援單向繫結。在本文直接改寫 CheckBoxField 類別,讓 CheckBoxField 可以直接雙向繫結 &quot;T/F&quot; 或 &quot;是/否&quot; 之類的資料。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0805/CheckBoxField_1471C/image_thumb.png" alt="" /></p> <p><a href="http://www.dotblogs.com.tw/jeff377/archive/2008/05/13/3969.aspx" target="_blank"><strong>8. 擴展 CommandField 類別 - Header 加入新增鈕</strong></a><br /> 摘要:支援在 CommandField 的 Header 的部分加入「新增」鈕,執行新增鈕會引發 RowCommand 事件。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0805/CommandFieldHeader_13B3E/image_4.png" alt="" /></p> <p><a href="http://www.dotblogs.com.tw/jeff377/archive/2008/05/29/4169.aspx" target="_blank"><strong>9. GridView 自動編號欄位 - TBSerialNumberField</strong></a><br /> 摘要:繼承 DataControlField 來撰寫自動編號欄位,若 GridView 需要自動編號欄位時只需加入欄位即可。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0805/GridViewTBSerialNumberField_13347/image_2.png" alt="" /></p> <p><a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/24/5762.aspx" target="_blank"><strong>10. 自訂 GridVie 欄位類別 - 實作 TBDropDownField 欄位類別</strong></a><br /> 摘要:支援在 GridView 中顯示下拉清單的欄位類別。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay23DataControlField_67E8/image_thumb_1.png" alt="" /></p> <p><a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/26/5777.aspx" target="_blank"><strong>11. 自訂 GridView 欄位 - 日期欄位</strong></a><br /> 摘要:支援在 GridView 中顯示日期下拉選單編輯的欄位類別。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay25TBDropDownFieldItems_6B94/image_thumb_2.png" alt="" /></p> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/27/5793.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/27/5793.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-27 22:37:14</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day25] 自訂 GridView 欄位 - 日期欄位(續)</title>                <link>https://ithelp.ithome.com.tw/articles/10013091?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10013091?sc=rss.iron</guid>                <description><![CDATA[<p>接續上一文<br /> <strong>四、覆寫 ExtractValuesFromCell 方法 - 擷取儲存格的欄位值</strong><br /> 當用戶端使用 GridView 編輯後執...]]></description>                                    <content:encoded><![CDATA[<p>接續上一文<br /> <strong>四、覆寫 ExtractValuesFromCell 方法 - 擷取儲存格的欄位值</strong><br /> 當用戶端使用 GridView 編輯後執行更新動作時,會呼叫 ExtractValuesFromCell 方法,來取得儲存格的欄位值,以便寫入資料來源。所以我們要覆寫 ExtractValuesFromCell 方法,將 Cell 或 TDateEdit 控制項的值取出填入具 IOrderedDictionary 介面的物件。</p> <pre><code>        ''' &lt;summary&gt;        ''' 使用指定 DataControlFieldCell 的值填入指定的 IDictionary 物件。        ''' &lt;/summary&gt;        ''' &lt;param name=&quot;Dictionary&quot;&gt;用於儲存指定儲存格的值。&lt;/param&gt;        ''' &lt;param name=&quot;Cell&quot;&gt;包含要擷取值的儲存格。&lt;/param&gt;        ''' &lt;param name=&quot;RowState&quot;&gt;資料列的狀態。&lt;/param&gt;        ''' &lt;param name=&quot;IncludeReadOnly&quot;&gt;true 表示包含唯讀欄位的值,否則為 false。&lt;/param&gt;        Public Overrides Sub ExtractValuesFromCell( _            ByVal Dictionary As IOrderedDictionary, _            ByVal Cell As DataControlFieldCell, _            ByVal RowState As DataControlRowState, _            ByVal IncludeReadOnly As Boolean)            Dim oControl As Control = Nothing            Dim sDataField As String = Me.DataField            Dim oValue As Object = Nothing            Dim sNullDisplayText As String = Me.NullDisplayText            Dim oDateEdit As TBDateEdit            If (((RowState And DataControlRowState.Insert) = DataControlRowState.Normal) OrElse Me.InsertVisible) Then                If (Cell.Controls.Count &gt; 0) Then                    oControl = Cell.Controls.Item(0)                    oDateEdit = TryCast(oControl, TBDateEdit)                    If (Not oDateEdit Is Nothing) Then                        oValue = oDateEdit.Text                    End If                ElseIf IncludeReadOnly Then                    Dim s As String = Cell.Text                    If (s = &quot; &quot;) Then                        oValue = String.Empty                    ElseIf (Me.SupportsHtmlEncode AndAlso Me.HtmlEncode) Then                        oValue = HttpUtility.HtmlDecode(s)                    Else                        oValue = s                    End If                End If                If (Not oValue Is Nothing) Then                    If TypeOf oValue Is String Then                        If (CStr(oValue).Length = 0) AndAlso Me.ConvertEmptyStringToNull Then                            oValue = Nothing                        ElseIf (CStr(oValue) = sNullDisplayText) AndAlso (sNullDisplayText.Length &gt; 0) Then                            oValue = Nothing                        End If                    End If                    If Dictionary.Contains(sDataField) Then                        Dictionary.Item(sDataField) = oValue                    Else                        Dictionary.Add(sDataField, oValue)                    End If                End If            End If        End Sub </code></pre> <p><strong>五、測試程式</strong><br /> 我們使用 Northwnd 資料庫的 Employees 資料表為例,在 GridView 加入自訂的 TBDateField 欄位繫結 BirthDate 欄位,另外加入另一個 BoundField 的唯讀欄位,也同樣繫結 BirthDate 欄位來做比較。</p> <pre><code>            &lt;bee:TBDateField DataField=&quot;BirthDate&quot; HeaderText=&quot;BirthDate&quot;                SortExpression=&quot;BirthDate&quot; DataFormatString=&quot;{0:d}&quot;                ApplyFormatInEditMode=&quot;True&quot; CalendarStyle=&quot;Winter&quot; /&gt;                        &lt;asp:BoundField DataField=&quot;BirthDate&quot; HeaderText=&quot;BirthDate&quot;                SortExpression=&quot;BirthDate&quot; DataFormatString=&quot;{0:d}&quot;                ApplyFormatInEditMode=&quot;True&quot; ReadOnly=&quot;true&quot; /&gt; </code></pre> <p>執行程式,在編輯資料列時,TBDateField 就會以 TDateEdit 控制項來進行編輯。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay25TBDropDownFieldItems_6B94/image_thumb_2.png" alt="" /></p> <p>使用 TDateEdit 編輯欄位值後,按「更新」鈕,資料就會被寫回資料庫。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay25TBDropDownFieldItems_6B94/image_thumb_3.png" alt="" /></p> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/26/5777.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/26/5777.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-26 17:04:50</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day25] 自訂 GridView 欄位 - 日期欄位</title>                <link>https://ithelp.ithome.com.tw/articles/10013083?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10013083?sc=rss.iron</guid>                <description><![CDATA[<p>前二篇文章介紹了自訂 GridView 使用的下拉清單欄位 (TBDropDownField),對如何繼承 BoundField 類別下來改寫自訂欄位應該有進一步的了解。在 GridView 中...]]></description>                                    <content:encoded><![CDATA[<p>前二篇文章介紹了自訂 GridView 使用的下拉清單欄位 (TBDropDownField),對如何繼承 BoundField 類別下來改寫自訂欄位應該有進一步的了解。在 GridView 中輸入日期也常蠻常見的需求,在本文將再實作一個 GridView 使用的日期欄位,在欄位儲存格使用 TBDateEdit 控制項來編輯資料。<br /> 程式碼下載:<a href="http://files.dotblogs.com.tw/jeff377/0810/20081026164615771.rar" target="_blank">ASP.NET Server Control - Day25.rar</a><br /> Northwnd 資料庫下載:<a href="http://files.dotblogs.com.tw/jeff377/0810/2008102364857537.rar" target="_blank">NORTHWND.rar</a></p> <p><strong>一、繼承 TBBaseBoundField 實作 TDateField</strong><br /> GridView 的日期欄位需要繫結資料,一般的作法是由 BoundField 繼承下來改寫;不過我們之前已經有繼承 BoundField 製作一個 TBBaseBoundField 的自訂欄位基底類別 (詳見「 <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/24/5762.aspx" target="_blank">[ASP.NET 控制項實作 Day23] 自訂 GridVie 欄位類別 - 實作 TBDropDownField 欄位類別</a>」 一文),所以我們要實作的日期欄位直接繼承 TBBaseBoundField 命名為 TDateField,並覆寫 CreateField 方法,傳回 TDateField 物件。</p> <pre><code>    ''' &lt;summary&gt;    ''' 日期欄位。    ''' &lt;/summary&gt;    Public Class TBDateField        Inherits TBBaseBoundField        Protected Overrides Function CreateField() As DataControlField            Return New TBDateField()        End Function    End Class </code></pre> <p>自訂欄位類別主要是要覆寫 InitializeDataCell 方法做資料儲存格初始化、覆寫 OnDataBindField 方法將欄位值繫結至 BoundField 物件、覆寫 ExtractValuesFromCell 方法來擷取儲存格的欄位值,下面我們將針對這幾個需要覆寫的方法做一說明。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay25TBDropDownFieldItems_6B94/image_thumb.png" alt="" /></p> <p><strong>二、覆寫 InitializeDataCell 方法 - 資料儲存格初始化</strong><br /> 首先覆寫 InitializeDataCell 方法處理資料儲存格初始化,當唯讀狀態時使用 Cell 來呈現資料;若為編輯狀態時,則在 Cell 中加入 TBDateEdit 控制項,並將 TBDateField 的屬性設定給 TBDateEdit 控制項的相關屬性。然後將儲存格 (DataControlFieldCell) 或日期控制項 (TDateEdit) 的 DataBinding 事件導向 OnDataBindField 事件處理方法。</p> <pre><code>        ''' &lt;summary&gt;        ''' 資料儲存格初始化。        ''' &lt;/summary&gt;        ''' &lt;param name=&quot;Cell&quot;&gt;要初始化的儲存格。&lt;/param&gt;        ''' &lt;param name=&quot;RowState&quot;&gt;資料列狀態。&lt;/param&gt;        Protected Overrides Sub InitializeDataCell(ByVal Cell As DataControlFieldCell, ByVal RowState As DataControlRowState)            Dim oDateEdit As TBDateEdit            Dim oControl As Control            If Me.CellIsEdit(RowState) Then                '編輯狀態在儲存格加入 TBDateEdit 控制項                oDateEdit = New TBDateEdit()                oDateEdit.FirstDayOfWeek = Me.FirstDayOfWeek                oDateEdit.ShowWeekNumbers = Me.ShowWeekNumbers                oDateEdit.CalendarStyle = Me.CalendarStyle                oDateEdit.Lang = Me.Lang                oDateEdit.ShowTime = Me.ShowTime                oControl = oDateEdit                Cell.Controls.Add(oControl)            Else                oControl = Cell            End If            If (oControl IsNot Nothing) AndAlso MyBase.Visible Then                AddHandler oControl.DataBinding, New EventHandler(AddressOf Me.OnDataBindField)            End If        End Sub </code></pre> <p>TDateEdit 控制項為筆者自行撰寫的日期控制項,TDateEdit 控制項的相關細節可以參考筆者部落格下面幾篇文章有進一步說明。<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/03/17/1742.aspx" target="_blank">日期控制項實作教學(1) - 結合 JavaScript</a><br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/03/17/1743.aspx" target="_blank">日期控制項實作教學(2) - PostBack 與 事件</a><br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/03/17/1746.aspx" target="_blank">TBDateEdit 日期控制項 - 1.0.0.0 版 (Open Source)</a><br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay21_6429/image_thumb_1.png" alt="" /></p> <p><strong>三、覆寫 OnDataBindField 方法 - 將欄位值繫結至 BoundField 物件</strong><br /> 當 GridView 執行 DataBind 時,每個儲存格的 DataBinding 事件都會被導向 OnDataBindField 方法,此方法中我們會由資料來源取得指定欄位值,處理此欄位值的格式化時,將欄位值呈現在 Cell 或 TDateEdit 控制項上。</p> <pre><code>        ''' &lt;summary&gt;        ''' 將欄位值繫結至 BoundField 物件。        ''' &lt;/summary&gt;        Protected Overrides Sub OnDataBindField(ByVal sender As Object, ByVal e As EventArgs)            Dim oControl As Control            Dim oDateEdit As TBDateEdit            Dim oNamingContainer As Control            Dim oDataValue As Object            '欄位值            Dim bEncode As Boolean              '是否編碼            Dim sText As String                 '格式化字串            oControl = DirectCast(sender, Control)            oNamingContainer = oControl.NamingContainer            oDataValue = Me.GetValue(oNamingContainer)            bEncode = ((Me.SupportsHtmlEncode AndAlso Me.HtmlEncode) AndAlso TypeOf oControl Is TableCell)            sText = Me.FormatDataValue(oDataValue, bEncode)            If TypeOf oControl Is TableCell Then                If (sText.Length = 0) Then                    sText = &quot; &quot;                End If                DirectCast(oControl, TableCell).Text = sText            Else                If Not TypeOf oControl Is TBDateEdit Then                    Throw New HttpException(String.Format(&quot;{0}: Wrong Control Type&quot;, Me.DataField))                End If                oDateEdit = DirectCast(oControl, TBDateEdit)                If Me.ApplyFormatInEditMode Then                    oDateEdit.Text = sText                ElseIf (Not oDataValue Is Nothing) Then                    oDateEdit.Text = oDataValue.ToString                End If            End If        End Sub </code></pre> <p>[超過字數限制,下一篇接續本文]</p> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/25/5772.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/25/5772.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-26 16:56:36</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day24] TBDropDownField 的 Items 屬性的資料繫結(續)</title>                <link>https://ithelp.ithome.com.tw/articles/10013047?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10013047?sc=rss.iron</guid>                <description><![CDATA[<p>接續上一文<br /> <strong>三、由關連的資料來源擷取資料</strong><br /> 再來就是重點就是要處理 PerformSelecrt 私有方法,來取得 Items 屬性的成員...]]></description>                                    <content:encoded><![CDATA[<p>接續上一文<br /> <strong>三、由關連的資料來源擷取資料</strong><br /> 再來就是重點就是要處理 PerformSelecrt 私有方法,來取得 Items 屬性的成員清單內容。PerformSelect 方法的作用是去尋找頁面上的具 IDataSource 介面的控制項,並執行此資料來源的 Select 方法,以取得資料來設定 Items 的清單內容。<br /> <strong>step1. 尋找資料來源控制項</strong><br /> PerformSelect 方法中有使用 FindControlEx 方法,它是自訂援尋控制項的多載方法,是取代 FindControl 進階方法。程式碼中使用 FindControlEx 去是頁面中以遞迴方式尋找具有 IDataSource 介面的控制項,且 ID 屬性值為 TBDropDownList.ID 的屬性值。<br /> <strong>step2. 執行資料來源控制項的 Select 方法</strong><br /> 當找到資料來源控制項後 (如 SqlDataSource、ObjectDataSource ...等等),執行其 DataSourceView.Select 方法,此方法需入一個 DataSourceViewSelectCallback 函式當作參數,當資料來源控制項取得資料後回呼我們指定的 OnDataSourceViewSelectCallback 函式中做後序處理。<br /> <strong>step3. 將取得的資料來設定生 Items 的清單內容</strong><br /> 在 OnDataSourceViewSelectCallback 函式中接到回傳的具 IEnumerable 介面的資料,有可能是 DataView、DataTable ...等型別的資料。利用 DataBinder.GetPropertyValue 來取得 DataTextField 及 DataValueField 設定的欄位值,逐一建立 ListItem 項目,並加入 Items 集合屬性中。</p> <pre><code>        ''' &lt;summary&gt;        ''' 從關聯的資料來源擷取資料。        ''' &lt;/summary&gt;        Private Sub PerformSelect()            Dim oControl As Control            Dim oDataSource As IDataSource            Dim oDataSourceView As DataSourceView            '若未設定 DataSourceID 屬性則離開            If StrIsEmpty(Me.DataSourceID) Then Exit Sub            '找到具 IDataSource 介面的控制項            oControl = FindControlEx(Me.Control.Page, GetType(IDataSource), &quot;ID&quot;, Me.DataSourceID)            If oControl Is Nothing Then Exit Sub            oDataSource = DirectCast(oControl, IDataSource)            oDataSourceView = oDataSource.GetView(String.Empty)            oDataSourceView.Select(DataSourceSelectArguments.Empty, _                        New DataSourceViewSelectCallback(AddressOf Me.OnDataSourceViewSelectCallback))        End Sub        ''' &lt;summary&gt;        ''' 擷取資料的回呼函式。        ''' &lt;/summary&gt;        ''' &lt;param name=&quot;data&quot;&gt;取得的資料。&lt;/param&gt;        Private Sub OnDataSourceViewSelectCallback(ByVal data As IEnumerable)            Dim oCollection As ICollection            Dim oValue As Object            Dim oItem As ListItem            Me.Items.Clear()            If data Is Nothing Then Exit Sub            oCollection = TryCast(data, ICollection)            Me.Items.Capacity = oCollection.Count            For Each oValue In data                oItem = New ListItem()                If StrIsNotEmpty(Me.DataTextField) Then                    oItem.Text = DataBinder.GetPropertyValue(oValue, DataTextField, Nothing)                End If                If StrIsNotEmpty(Me.DataValueField) Then                    oItem.Value = DataBinder.GetPropertyValue(oValue, DataValueField, Nothing)                End If                Me.Items.Add(oItem)            Next        End Sub </code></pre> <p><strong>四、測試程式</strong><br /> 使用上篇中同一個案例做測試,同樣以 Northwnd 資料庫的 Products 資料表為例。在 GridView 加入自訂的 TBDropDownField 欄位繫結 CategoryID 欄位,並設定 DataSourceID、DataTextField、DataValueField 屬性;另外加入另一個 BoundField 的唯讀欄位,也同樣繫結 CategoryID 欄位來做比較。</p> <pre><code>                &lt;bee:TBDropDownField  HeaderText=&quot;CategoryID&quot;                      SortExpression=&quot;CategoryID&quot; DataField=&quot;CategoryID&quot;                    DataTextField=&quot;CategoryName&quot; DataValueField=&quot;CategoryID&quot; DataSourceID=&quot;SqlDataSource2&quot;&gt;                &lt;/bee:TBDropDownField&gt;                &lt;asp:BoundField DataField=&quot;CategoryID&quot; HeaderText=&quot;CategoryID&quot;                    SortExpression=&quot;CategoryID&quot;  ReadOnly=&quot;true&quot; /&gt; </code></pre> <p>執行程式,在 GridView 瀏覽的模式時,TBDropDownField 的儲存格已經會呈現 Items 對應成員的顯示文字。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay24TBDropDownField_73B8/image_thumb_1.png" alt="" /></p> <p>執行資料列編輯時,也可以正常顯示下拉清單的內容。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay24TBDropDownField_73B8/image_thumb_2.png" alt="" /></p> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/25/5772.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/25/5772.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-25 18:11:28</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day24] TBDropDownField 的 Items 屬性的資料繫結</title>                <link>https://ithelp.ithome.com.tw/articles/10013041?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10013041?sc=rss.iron</guid>                <description><![CDATA[<p>上篇中我們實作了 GridView 的 TBDropDownField 欄位類別,不過眼尖的讀者不知有沒有發覺我們並處理 Items 屬性取得成員清單的動作,而是直接設定儲存格內含的 TBDro...]]></description>                                    <content:encoded><![CDATA[<p>上篇中我們實作了 GridView 的 TBDropDownField 欄位類別,不過眼尖的讀者不知有沒有發覺我們並處理 Items 屬性取得成員清單的動作,而是直接設定儲存格內含的 TBDropDownList 控制項相關屬性 (DataSourceID、DataTextField、DataValueField 屬性) 後,就由 TDropDownList 控制項自行處理 Items 屬性的資料繫結。當 GridView 的資料列是編輯狀態時,下拉清單會顯示出 Items 的文字內容;可是瀏覽狀態的資料列,卻是顯示欄位原始值,無法呈現 Items 的文字內容。本文將說明如何自行處理 TBDropDownField 的 Items 屬性的資料繫結動作,並使唯讀狀態的資料列也可以呈現 Items 的文字內容。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay24TBDropDownField_73B8/image_thumb.png" alt="" /><br /> 程式碼下載:<a href="http://files.dotblogs.com.tw/jeff377/0810/20081025163920497.rar" target="_blank">ASP.NET Server Control - Day24.rar</a><br /> Northwnd 資料庫下載:<a href="http://files.dotblogs.com.tw/jeff377/0810/2008102364857537.rar" target="_blank">NORTHWND.rar</a></p> <p><strong>一、Items 屬性的問題</strong><br /> 我們重新看一次原本 TBDropDownField 類別在處理 Items 屬性的資料繫結取得清單內容的程式碼,在覆寫 InitializeDataCell 方法中,當儲存格為編輯模式時,會呈現 TBDropDownList 控制項並設定取得 Items 清單內容的相關屬性,讓 TBDropDownList 自行去處理它的 Items 屬性的清單內容。</p> <pre><code>'由資料來源控制項取得清單項目 oDropDownList.DataSourceID = Me.DataSourceID oDropDownList.DataTextField = Me.DataTextField oDropDownList.DataValueField = Me.DataValueField </code></pre> <p>不知你有沒有發覺,我們無論在 InitializeDataCell 及 OnDataBindField 方法中,都沒有針對 TBDropDownList 控制項做任何 DataBind 動作,那它是怎麼從 DataSourceID 關聯的資料來源擷取資料呢?因為 GridView 在執行 DataBind 時,就會要求所有的子控制項做 DataBind,所以我們只要設定好 BDropDownList 控制項相關屬性後,當 TBDropDownList 自動被要求資料繫結時就會取得 Items 的清單內容。<br /> 當然使用 TBDropDownList 控制項去處理 Items 的資料繫結動作最簡單,可是這樣唯讀的儲存格只能顯示原始欄位值,無法呈現 Items 中對應成員的文字;除非無論唯讀或編輯狀態,都要建立 TBDropDownList 控制項去取得 Items 清單內容,而唯讀欄位使用 TBDropDownList.Items 去找到對應成員的顯示文字,不過這樣的作法會怪怪的,而且沒有執行效能率。所以比較好的辨法,就是由 TBDropDownField 類別自行處理 Items 的資料繫結,同時提供給唯讀狀態的<br /> DataControlFieldCell 及編輯狀態的 TBDropDownList 使用。</p> <p><strong>二、由 TBDropDownField 類別處理 Items 屬性的資料繫結</strong><br /> 我們要自行處理 Items 屬性來取得成員清單,在 InitializeDataCell 方法中無須處理 Items 屬性,只需產生儲存格需要的子控制項,未來在執行子控制項的 DataBinding 時的 OnDataBindField 方法中再來處理 Items 屬性。</p> <pre><code>        Protected Overrides Sub InitializeDataCell( _            ByVal Cell As DataControlFieldCell, _            ByVal RowState As DataControlRowState)            Dim oDropDownList As TBDropDownList            Dim oControl As Control            If Me.CellIsEdit(RowState) Then                oDropDownList = New TBDropDownList()                oControl = oDropDownList                Cell.Controls.Add(oControl)            Else                oControl = Cell            End If            If (oControl IsNot Nothing) AndAlso MyBase.Visible Then                AddHandler oControl.DataBinding, New EventHandler(AddressOf Me.OnDataBindField)            End If        End Sub </code></pre> <p>在 OnDataBindField 方法中,我們加上一段處理 Items 屬性的程式碼如下,會利用 PerformSelecrt 私有方法,由關聯的資料來源 (即 DataSrouceID 指定的資料來源控制項) 擷取資料並產生 Items 的成員清單,在後面會詳細講解 PerformSelecrt 方法處理擷取資料的細節。因為 TBDropDownField 每個資料儲存格都會執行 OnDataBindField 方法,但 Items 取得成員清單的動作只需做一次即可,所以會以 FIsPerformSelect 區域變數來判斷是否已取得 Items 的成員清單,若已取過就不重新取得,這樣比較有執行效能。</p> <pre><code>            If Not Me.DesignMode Then                If Not FIsPerformSelect Then                    '從關聯的資料來源擷取資料                    PerformSelect()                    FIsPerformSelect = True                End If            End If </code></pre> <p>當取得儲存儲的對應的欄位值時,依此欄位值由 Items 集合去取得對應的 ListItem 成員,並以此 ListItem.Text 的文字內容來做顯示。</p> <pre><code>            '由 Items 去取得對應成員的顯示內容            oListItem = Me.Items.FindByValue(CCStr(sText))            If oListItem IsNot Nothing Then                sText = oListItem.Text            End If </code></pre> <p>若是由 TBDropDownList 所引發的 OnDataBindField 方法時,使用 SetItems 私有方法將 TBDropDownField.Items 屬性複製給 TBDropDownList.Item 屬性。</p> <pre><code>                ODropDownList = DirectCast(oControl, TBDropDownList)                SetItems(ODropDownList) </code></pre> <p>SetItems 私有方法的程式碼如下。</p> <pre><code>        Private Sub SetItems(ByVal DropDownList As TBDropDownList)            Dim oItems() As ListItem            If Not Me.DesignMode Then                ReDim oItems(Me.Items.Count - 1)                Me.Items.CopyTo(oItems, 0)                DropDownList.Items.AddRange(oItems)            End If        End Sub </code></pre> <p>[超過字數限制,下一篇接續本文]</p> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/25/5772.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/25/5772.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-25 18:09:12</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day23] 自訂GridVie欄位-實作TBDropDownField欄位(續3)</title>                <link>https://ithelp.ithome.com.tw/articles/10012977?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10012977?sc=rss.iron</guid>                <description><![CDATA[<p>接續上一文<br /> <strong>四、測試程式</strong><br /> 辛苦寫好 TBDropDownField 欄位類別時,接下來就是驗收成果的時候。我們以 Northwnd 資料...]]></description>                                    <content:encoded><![CDATA[<p>接續上一文<br /> <strong>四、測試程式</strong><br /> 辛苦寫好 TBDropDownField 欄位類別時,接下來就是驗收成果的時候。我們以 Northwnd 資料庫的 Products 資料表為例,將 TBDropDownList .DataField 設為 CategoryID 欄位來做測試。首先我們測試沒有 DataSoruceID 的情況,在 GridView 加入自訂的 TBDropDownField 欄位繫結 CategoryID 欄位,另外加入另一個 BoundField 的唯讀欄位,也同樣繫結 CategoryID 欄位來做比較。</p> <pre><code>                &lt;bee:TBDropDownField  HeaderText=&quot;CategoryID&quot;                      SortExpression=&quot;CategoryID&quot; DataField=&quot;CategoryID&quot; &gt;                    &lt;Items&gt;                    &lt;asp:ListItem Value=&quot;&quot;&gt;未對應&lt;/asp:ListItem&gt;                    &lt;asp:ListItem Value=&quot;2&quot;&gt;Condiments&lt;/asp:ListItem&gt;                    &lt;asp:ListItem Value=&quot;3&quot;&gt;Confections&lt;/asp:ListItem&gt;                    &lt;/Items&gt;                &lt;/bee:TBDropDownField&gt;                &lt;asp:BoundField DataField=&quot;CategoryID&quot; HeaderText=&quot;CategoryID&quot;                    SortExpression=&quot;CategoryID&quot;  ReadOnly=&quot;true&quot; /&gt; </code></pre> <p>執行程式,在 GridView 在唯讀模式,TBDropDownFIeld 可以正確的繫結 CategoryID 欄位值。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay23DataControlField_67E8/image_thumb.png" alt="" /></p> <p>編輯某筆資料列進入編輯狀態,就會顯示 TBDropDownList 控制項,清單成員為我們在 Items 設定的內容。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay23DataControlField_67E8/image_thumb_1.png" alt="" /></p> <p>使用 TBDropDownList 來做編輯欄位值,按下更新鈕,這時會執行 TBDropDownField.ExtractValuesFromCell 方法,取得儲存格中的值;最後由資料來源控制項將欄位值寫回資料庫。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay23DataControlField_67E8/image_thumb_2.png" alt="" /></p> <p>接下來測試設定 TBDropDownField.DataSourceID 的情況,把 DataSourcID 指向含 Categories 資料表內容的 SqlDataSoruce 控制項。</p> <pre><code>                &lt;bee:TBDropDownField  HeaderText=&quot;CategoryID&quot;                      SortExpression=&quot;CategoryID&quot; DataField=&quot;CategoryID&quot;                    DataTextField=&quot;CategoryName&quot; DataValueField=&quot;CategoryID&quot; DataSourceID=&quot;SqlDataSource2&quot;&gt;                &lt;/bee:TBDropDownField&gt; </code></pre> <p>執行程式查看結果,可以發現 TBDropDownList 控制項的清單內容也可以正常顯示 SqlDataSoruce 控制項取得資料。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay23DataControlField_67E8/image_thumb_3.png" alt="" /></p> <p>[超過字數限制,下一篇接續本文]</p> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/24/5762.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/24/5762.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-24 00:32:30</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day23] 自訂GridVie欄位-實作TBDropDownField欄位(續2)</title>                <link>https://ithelp.ithome.com.tw/articles/10012973?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10012973?sc=rss.iron</guid>                <description><![CDATA[<p>接續上一文<br /> <strong>step4. 處理資料繫結</strong><br /> 當 GridView 控制項在執行資料繫結時,儲存格的控制項就會引發 DataBinding 事...]]></description>                                    <content:encoded><![CDATA[<p>接續上一文<br /> <strong>step4. 處理資料繫結</strong><br /> 當 GridView 控制項在執行資料繫結時,儲存格的控制項就會引發 DataBinding 事件,而這些事件會被導向 OnDataBindField 方法來統一處理儲存格中控制項的繫結動作。</p> <pre><code>       ''' &lt;summary&gt;        ''' 將欄位值繫結至 BoundField 物件。        ''' &lt;/summary&gt;        ''' &lt;param name=&quot;sender&quot;&gt;控制項。&lt;/param&gt;        ''' &lt;param name=&quot;e&quot;&gt;事件引數。&lt;/param&gt;        Protected Overrides Sub OnDataBindField(ByVal sender As Object, ByVal e As EventArgs)            Dim oControl As Control            Dim ODropDownList As TBDropDownList            Dim oNamingContainer As Control            Dim oDataValue As Object            '欄位值            Dim bEncode As Boolean              '是否編碼            Dim sText As String                 '格式化字串            oControl = DirectCast(sender, Control)            oNamingContainer = oControl.NamingContainer            oDataValue = Me.GetValue(oNamingContainer)            bEncode = ((Me.SupportsHtmlEncode AndAlso Me.HtmlEncode) AndAlso TypeOf oControl Is TableCell)            sText = Me.FormatDataValue(oDataValue, bEncode)            If TypeOf oControl Is TableCell Then                If (sText.Length = 0) Then                    sText = &quot; &quot;                End If                DirectCast(oControl, TableCell).Text = sText            Else                If Not TypeOf oControl Is TBDropDownList Then                    Throw New HttpException(String.Format(&quot;{0}: Wrong Control Type&quot;, Me.DataField))                End If                ODropDownList = DirectCast(oControl, TBDropDownList)                If Me.ApplyFormatInEditMode Then                    ODropDownList.Text = sText                ElseIf (Not oDataValue Is Nothing) Then                    ODropDownList.Text = oDataValue.ToString                End If            End If        End Sub </code></pre> <p><strong>step5. 取得儲存格中的值</strong><br /> 另外我們還需要覆寫 ExtractValuesFromCell 方法,取得儲存格中的值。這個方法是當 GridView 的編輯資料要準備寫入資料庫時,會經由 ExtractValuesFromCell 方法此來取得每個儲存格的值,並將這些欄位值加入 Dictionary 參數中,這個準備寫入的欄位值集合,可以在 DataSource 控制項的寫入資料庫的相關方法中取得使用。</p> <pre><code>        ''' &lt;summary&gt;        ''' 使用指定 DataControlFieldCell 物件的值填入指定的 System.Collections.IDictionary 物件。        ''' &lt;/summary&gt;        ''' &lt;param name=&quot;Dictionary&quot;&gt;用於儲存指定儲存格的值。&lt;/param&gt;        ''' &lt;param name=&quot;Cell&quot;&gt;包含要擷取值的儲存格。&lt;/param&gt;        ''' &lt;param name=&quot;RowState&quot;&gt;資料列的狀態。&lt;/param&gt;        ''' &lt;param name=&quot;IncludeReadOnly&quot;&gt;true 表示包含唯讀欄位的值,否則為 false。&lt;/param&gt;        Public Overrides Sub ExtractValuesFromCell( _            ByVal Dictionary As IOrderedDictionary, _            ByVal Cell As DataControlFieldCell, _            ByVal RowState As DataControlRowState, _            ByVal IncludeReadOnly As Boolean)            Dim oControl As Control = Nothing            Dim sDataField As String = Me.DataField            Dim oValue As Object = Nothing            Dim sNullDisplayText As String = Me.NullDisplayText            Dim oDropDownList As TBDropDownList            If (((RowState And DataControlRowState.Insert) = DataControlRowState.Normal) OrElse Me.InsertVisible) Then                If (Cell.Controls.Count &gt; 0) Then                    oControl = Cell.Controls.Item(0)                    oDropDownList = TryCast(oControl, TBDropDownList)                    If (Not oDropDownList Is Nothing) Then                        oValue = oDropDownList.Text                    End If                ElseIf IncludeReadOnly Then                    Dim s As String = Cell.Text                    If (s = &quot; &quot;) Then                        oValue = String.Empty                    ElseIf (Me.SupportsHtmlEncode AndAlso Me.HtmlEncode) Then                        oValue = HttpUtility.HtmlDecode(s)                    Else                        oValue = s                    End If                End If                If (Not oValue Is Nothing) Then                    If TypeOf oValue Is String Then                        If (CStr(oValue).Length = 0) AndAlso Me.ConvertEmptyStringToNull Then                            oValue = Nothing                        ElseIf (CStr(oValue) = sNullDisplayText) AndAlso (sNullDisplayText.Length &gt; 0) Then                            oValue = Nothing                        End If                    End If                    If Dictionary.Contains(sDataField) Then                        Dictionary.Item(sDataField) = oValue                    Else                        Dictionary.Add(sDataField, oValue)                    End If                End If            End If        End Sub </code></pre> <p>[超過字數限制,下一篇接續本文]</p> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/24/5762.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/24/5762.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-24 00:31:32</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day23] 自訂GridVie欄位-實作TBDropDownField欄位(續1)</title>                <link>https://ithelp.ithome.com.tw/articles/10012971?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10012971?sc=rss.iron</guid>                <description><![CDATA[<p>接續上一文<br /> <strong>step2. 加入 TBBaseBoundField 的屬性</strong><br /> TBBaseBoundField 類別會內含 DropDown...]]></description>                                    <content:encoded><![CDATA[<p>接續上一文<br /> <strong>step2. 加入 TBBaseBoundField 的屬性</strong><br /> TBBaseBoundField 類別會內含 DropDownList 控制項,所以加入設定 DropDownList 控制項的對應屬性;我們在 TBBaseBoundField 類別加入了 Items 、DataSourceID、DataTextField、DataValueField 屬性。其中 Items 屬性的型別與 DropDownList.Items 屬性相同,都是 ListItemCollection 集合類別,且 Items 屬性會儲存於 ViewState 中。</p> <pre><code>        ''' &lt;summary&gt;        ''' 清單項目集合。        ''' &lt;/summary&gt;        &lt; _        Description(&quot;清單項目集合。&quot;), _        DefaultValue(CStr(Nothing)), _        PersistenceMode(PersistenceMode.InnerProperty), _        DesignerSerializationVisibility(DesignerSerializationVisibility.Content), _        Editor(GetType(ListItemsCollectionEditor), GetType(UITypeEditor)), _        MergableProperty(False), _        Category(&quot;Default&quot;)&gt; _        Public Overridable ReadOnly Property Items() As ListItemCollection            Get                If (FItems Is Nothing) Then                    FItems = New ListItemCollection()                    If MyBase.IsTrackingViewState Then                        CType(FItems, IStateManager).TrackViewState()                    End If                End If                Return FItems            End Get        End Property        ''' &lt;summary&gt;        ''' 資料來源控制項的 ID 屬性。        ''' &lt;/summary&gt;        Public Property DataSourceID() As String            Get                Return FDataSourceID            End Get            Set(ByVal value As String)                FDataSourceID = value            End Set        End Property        ''' &lt;summary&gt;        ''' 提供清單項目文字內容的資料來源的欄位。        ''' &lt;/summary&gt;        &lt; _        Description(&quot;提供清單項目文字內容的資料來源的欄位。&quot;), _        DefaultValue(&quot;&quot;) _        &gt; _        Public Property DataTextField() As String            Get                Return FDataTextField            End Get            Set(ByVal value As String)                FDataTextField = value            End Set        End Property        ''' &lt;summary&gt;        ''' 提供清單項目值的資料來源的欄位。        ''' &lt;/summary&gt;        Public Property DataValueField() As String            Get                Return FDataValueField            End Get            Set(ByVal value As String)                FDataValueField = value            End Set        End Property </code></pre> <p><strong>step3.建立儲存格內含的控制項</strong><br /> GridView 是以儲存格 (DataControlFieldCell) 為單位,我們要覆寫 InitializeDataCell 方法來建立儲存格中的控制項;當儲存格為可編輯狀態時,就建立 DropDownList 控制項並加入儲存格中,在此使用上篇文章提及的 TBDropDownList 控制項來取代,以解決清單成員不存在造成錯誤的問題。若未設定 DataSourceID 屬性時,則由 Items 屬性取得自訂的清單項目;若有設定 DataSourceID 屬性,則由資料來源控制項 (如 SqlDataSource、ObjectDataSource 控制項) 來取得清單項目。<br /> 當建立儲存格中的控制項後,需要以 AddHeadler 的方法,將此控制項的 DataBinding 事件導向 OnDataBindField 這個事件處理方法,我們要在 OnDataBindField 處理資料繫結的動作。</p> <pre><code>        ''' &lt;summary&gt;        ''' 資料儲存格初始化。        ''' &lt;/summary&gt;        ''' &lt;param name=&quot;Cell&quot;&gt;要初始化的儲存格。&lt;/param&gt;        ''' &lt;param name=&quot;RowState&quot;&gt;資料列狀態。&lt;/param&gt;        Protected Overrides Sub InitializeDataCell( _            ByVal Cell As DataControlFieldCell, _            ByVal RowState As DataControlRowState)            Dim oDropDownList As TBDropDownList            Dim oItems() As ListItem            Dim oControl As Control            If Me.CellIsEdit(RowState) Then                oDropDownList = New TBDropDownList()                oControl = oDropDownList                Cell.Controls.Add(oControl)                If Not Me.DesignMode Then                    If StrIsEmpty(Me.DataSourceID) Then                        '自訂清單項目                        ReDim oItems(Me.Items.Count - 1)                        Me.Items.CopyTo(oItems, 0)                        oDropDownList.Items.AddRange(oItems)                    Else                        '由資料來源控制項取得清單項目                        oDropDownList.DataSourceID = Me.DataSourceID                        oDropDownList.DataTextField = Me.DataTextField                        oDropDownList.DataValueField = Me.DataValueField                    End If                End If            Else                oControl = Cell            End If            If (oControl IsNot Nothing) AndAlso MyBase.Visible Then                AddHandler oControl.DataBinding, New EventHandler(AddressOf Me.OnDataBindField)            End If        End Sub </code></pre> <p>[超過字數限制,下一篇接續本文]</p> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/24/5762.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/24/5762.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-24 00:25:02</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day23] 自訂GridVie欄位-實作TBDropDownField欄位</title>                <link>https://ithelp.ithome.com.tw/articles/10012965?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10012965?sc=rss.iron</guid>                <description><![CDATA[<p>GridView 是 ASP.NET 中一個相當常用的控制項,在 GridView 可加入 BoundField、CheckBoxField、CommandField、TemplateField...]]></description>                                    <content:encoded><![CDATA[<p>GridView 是 ASP.NET 中一個相當常用的控制項,在 GridView 可加入 BoundField、CheckBoxField、CommandField、TemplateField ... 等不同型別的欄位,可是偏偏沒有提供在 GridView 中可呈現 DropDownList 的欄位型別;遇到這類需求時,一般的作法都是使用 TemplateField 來處理。雖然 TemplateField 具有相當好的設計彈性。可是在當 GridView 需要動態產生欄位的需求時,TemplateField 就相當麻煩,要寫一堆程式碼自行去處理資料繫結的動作。相互比較起來,BoundField、CheckBoxField ...等這類事先定義類型的欄位,在 GridView 要動態產生這些欄位就相當方便。如果我們可以把一些常用的 GridView 的欄位,都做成類似 BoundField 一樣,只要設定欄位的屬性就好,這樣使用上就會方便許多,所以在本文將以實作 DropDownList 欄位為例,讓大家了解如何去自訂 GridView 的欄位類別。<br /> 程式碼下載:<a href="http://files.dotblogs.com.tw/jeff377/0810/2008102321355642.rar" target="_blank">ASP.NET Server Control - Day23.rar </a><br /> Northwnd 資料庫下載:<a href="http://files.dotblogs.com.tw/jeff377/0810/2008102364857537.rar" target="_blank">NORTHWND.rar</a></p> <p><strong>一、選擇合適的父類別</strong><br /> 一般自訂 GridView 的欄位類別時,大都是由 DataControlField 或 BoundField 繼承下來改寫。若是欄位不需繫結資料(如 CommandFIeld),可以由 DataControlFIeld 繼承下來,若是欄位需要做資料繫結時(如 CheckBoxFIld,可以直接由 BoundField 繼承下來改寫比較方便。<br /> DataControlField 類別是所有類型欄位的基底類別,BoundField 類別也是由 DataControlField 類別繼承下來擴展了資料繫結部分的功能,所以我們要實作含 DropDownList 的欄位,也是由 BoundField 繼承下來改寫。</p> <p><strong>二、自訂欄位基底類別</strong><br /> 在此我們不直接繼承 BoundFIeld,而是先撰寫一個繼承 BoundField 命名為 TBBaseBoundField 的基底類別,此類別提供一些通用的屬性及方法,使我們更方便去撰寫自訂的欄位類別。</p> <pre><code>    ''' &lt;summary&gt;    ''' 資料欄位基礎類別。    ''' &lt;/summary&gt;    Public MustInherit Class TBBaseBoundField        Inherits BoundField        Private FRowIndex As Integer = 0        ''' &lt;summary&gt;        ''' 資料列是否為編輯模式。        ''' &lt;/summary&gt;        ''' &lt;param name=&quot;RowState&quot;&gt;資料列狀態。&lt;/param&gt;        Public Function RowStateIsEdit(ByVal RowState As DataControlRowState) As Boolean            Return (RowState And DataControlRowState.Edit) &lt;&gt; DataControlRowState.Normal        End Function        ''' &lt;summary&gt;        ''' 資料列是否為新增模式。        ''' &lt;/summary&gt;        ''' &lt;param name=&quot;RowState&quot;&gt;資料列狀態。&lt;/param&gt;        Public Function RowStateIsInsert(ByVal RowState As DataControlRowState) As Boolean            Return (RowState And DataControlRowState.Insert) &lt;&gt; DataControlRowState.Normal        End Function        ''' &lt;summary&gt;        ''' 資料列是否為編輯或新增模式。        ''' &lt;/summary&gt;        ''' &lt;param name=&quot;RowState&quot;&gt;資料列狀態。&lt;/param&gt;        Public Function RowStateIsEditOrInsert(ByVal RowState As DataControlRowState) As Boolean            Return RowStateIsEdit(RowState) OrElse RowStateIsInsert(RowState)        End Function        ''' &lt;summary&gt;        ''' 判斷儲存格是否可編輯(新增/修改)。        ''' &lt;/summary&gt;        ''' &lt;param name=&quot;RowState&quot;&gt;資料列狀態。&lt;/param&gt;        Friend Function CellIsEdit(ByVal RowState As DataControlRowState) As Boolean            Return (Not Me.ReadOnly) AndAlso RowStateIsEditOrInsert(RowState)        End Function        ''' &lt;summary&gt;        ''' 資料列索引。        ''' &lt;/summary&gt;        Friend ReadOnly Property RowIndex() As Integer            Get                Return FRowIndex            End Get        End Property        ''' &lt;summary&gt;        ''' 儲存格初始化。        ''' &lt;/summary&gt;        ''' &lt;param name=&quot;Cell&quot;&gt;要初始化的儲存格。&lt;/param&gt;        ''' &lt;param name=&quot;CellType&quot;&gt;儲存格類型。&lt;/param&gt;        ''' &lt;param name=&quot;RowState&quot;&gt;資料列狀態。&lt;/param&gt;        ''' &lt;param name=&quot;RowIndex&quot;&gt;資料列之以零起始的索引。&lt;/param&gt;        Public Overrides Sub InitializeCell(ByVal Cell As DataControlFieldCell, ByVal CellType As DataControlCellType, _            ByVal RowState As DataControlRowState, ByVal RowIndex As Integer)            FRowIndex = RowIndex            MyBase.InitializeCell(Cell, CellType, RowState, RowIndex)        End Sub        ''' &lt;summary&gt;        ''' 是否需要執行資料繫結。        ''' &lt;/summary&gt;        ''' &lt;param name=&quot;RowState&quot;&gt;資料列狀態。&lt;/param&gt;        Friend Function RequiresDataBinding(ByVal RowState As DataControlRowState) As Boolean            If MyBase.Visible AndAlso StrIsNotEmpty(MyBase.DataField) AndAlso RowStateIsEdit(RowState) Then                Return True            Else                Return False            End If        End Function    End Class </code></pre> <p><strong>三、實作 TBDropDownField 欄位類別</strong><br /> <strong>step1. 繼承 TBBaseBoundField 類別</strong><br /> 首先新增一個類別,繼承 TBBaseBoundField 命名為 TBDropDownFIeld 類別,覆寫 CreateField 方法,傳回 TBDropDownFIeld 物件。</p> <pre><code>    Public Class TBDropDownField        Inherits TBBaseBoundField        Protected Overrides Function CreateField() As System.Web.UI.WebControls.DataControlField            Return New TBDropDownField()        End Function    End Class </code></pre> <p>[超過字數限制,下一篇接續本文]</p> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/24/5762.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/24/5762.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-24 00:19:12</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day22] 讓 DropDownList 不再因項目清單不存在而造成錯誤(續)</title>                <link>https://ithelp.ithome.com.tw/articles/10012915?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10012915?sc=rss.iron</guid>                <description><![CDATA[<p>接續上篇文章內容<br /> <strong>三、解決 TBDropDownList 設定 DataSourceID 造成資料無法繫結的問題</strong><br /> 要解決上述 TBDro...]]></description>                                    <content:encoded><![CDATA[<p>接續上篇文章內容<br /> <strong>三、解決 TBDropDownList 設定 DataSourceID 造成資料無法繫結的問題</strong><br /> 要解決上述 TBDropDownList 設定 DataSourceID 問題,需在設定 SelectedValue 屬性時,若 Items.Count=0 先用一個 FCachedSelectedValue 變數將正確的值先暫存下來,然後覆寫 PerformDataBinding 方法,當 DorpDownList 取得 DataSoruceID 所對應的項目清單內容後,因為這時 Items 的內容才會完整取回,再去設定一次 SelectedValue 屬性就可以正確的繫結資料。</p> <pre><code>    Public Class TBDropDownList        Inherits DropDownList        Private FCachedSelectedValue As String        ''' &lt;summary&gt;        ''' 覆寫 SelectedValue 屬性。        ''' &lt;/summary&gt;        Public Overrides Property SelectedValue() As String            Get                Return MyBase.SelectedValue            End Get            Set(ByVal value As String)                If Me.Items.Count &lt;&gt; 0 Then                    Dim oItem As ListItem = Me.Items.FindByValue(value)                    If (oItem Is Nothing) Then                        Me.SelectedIndex = -1 '當 Items 不存在時                    Else                        MyBase.SelectedValue = value                    End If                Else                    FCachedSelectedValue = value                End If            End Set        End Property        Protected Overrides Sub PerformDataBinding(ByVal data As System.Collections.IEnumerable)            MyBase.PerformDataBinding(data)            'DataSoruceID 資料繫結後再設定 SelectedValue 屬性值            If (Not FCachedSelectedValue Is Nothing) Then                Me.SelectedValue = FCachedSelectedValue            End If        End Sub    End Class </code></pre> <p>重新執行程式,切換到編輯模式時,TBDropDownList 就可以正確的繫結欄位值了。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay22DropDownList_14F78/image_thumb_5.png" alt="" /></p> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/22/5749.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/22/5749.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-23 07:03:54</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day22] 讓 DropDownList 不再因項目清單不存在而造成錯誤</title>                <link>https://ithelp.ithome.com.tw/articles/10012909?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10012909?sc=rss.iron</guid>                <description><![CDATA[<p>DropDownList 控制項常常會因為項目清單中不存在繫結的欄位,而發生以下的錯誤訊息。因為繫結資料的不完整或異常就會造成這樣的異常錯誤,在設計上實在是相當困擾,而且最麻煩的是這個錯誤在頁面...]]></description>                                    <content:encoded><![CDATA[<p>DropDownList 控制項常常會因為項目清單中不存在繫結的欄位,而發生以下的錯誤訊息。因為繫結資料的不完整或異常就會造成這樣的異常錯誤,在設計上實在是相當困擾,而且最麻煩的是這個錯誤在頁面的程式碼也無法使用 Try ... Catch 方式來略過錯誤。其實最簡單的方式就去直接去修改 DropDownList 控制項,讓 DropDownList 控制項繫結資料時,就算欄位值不存在清單項目中也不要釋出錯誤,本文就要說明如何繼承 DorpDownList 下來修改,來有效解決這個問題。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay22DropDownList_14F78/image_thumb.png" alt="" /><br /> 程式碼下載:<a href="http://files.dotblogs.com.tw/jeff377/0810/2008102365119295.rar" target="_blank">ASP.NET Server Control - Day22.rar</a><br /> Northwnd 資料庫下載:<a href="http://files.dotblogs.com.tw/jeff377/0810/2008102364857537.rar" target="_blank">NORTHWND.rar</a></p> <p><strong>一、覆寫 SelectedValue 屬性解決資料繫結的問題</strong><br /> DropDownList 控制項繫結錯誤的原因,可以由上圖的錯誤訊息可以大概得知是寫入 SelectedValue 屬性時發生的錯誤;所以我們繼承 DorpDownList 下來命名為 TBDropDownList,並覆寫 SelectedValue 屬性來解決這個問題。解決方式是在寫入 SelectedValue 屬性時,先判斷準備寫入的值是否存在項目清單中,存在的話才寫入 SelectedValue 屬性,若不存在則直接設定 SelectedIndex 屬性為 -1。</p> <pre><code>    Public Class TBDropDownList        Inherits DropDownList        ''' &lt;summary&gt;        ''' 覆寫 SelectedValue 屬性。        ''' &lt;/summary&gt;        Public Overrides Property SelectedValue() As String            Get                Return MyBase.SelectedValue            End Get            Set(ByVal value As String)                Dim oItem As ListItem = Me.Items.FindByValue(value)                If (oItem Is Nothing) Then                    Me.SelectedIndex = -1 '當 Items 不存在時                    Exit Property                Else                    MyBase.SelectedValue = value                End If            End Set        End Property    End Class </code></pre> <p>我們以 Northwnd 資料庫的 Products 資料表做為測試資料,事先定義 DropDownList 的 Items 內容,其中第一個加入 &quot;未對應&quot; 的項目,將 SelectedValue 屬性繫結至 CategoryID 欄位。</p> <pre><code>                &lt;bee:TBDropDownList ID=&quot;DropDownList1&quot; runat=&quot;server&quot;                    SelectedValue='&lt;%# Bind(&quot;CategoryID&quot;) %&gt;'&gt;                    &lt;asp:ListItem Value=&quot;&quot;&gt;未對應&lt;/asp:ListItem&gt;                    &lt;asp:ListItem Value=&quot;2&quot;&gt;Condiments&lt;/asp:ListItem&gt;                    &lt;asp:ListItem Value=&quot;3&quot;&gt;Confections&lt;/asp:ListItem&gt;                &lt;/bee:TBDropDownList&gt; </code></pre> <p>當資料的 CategoryID 欄位值不存在於 DropDownList 的 Items 集合屬性中時,就會顯示第一個 &quot;未對應&quot; 的項目。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay22DropDownList_14F78/image_thumb_1.png" alt="" /></p> <p><strong>二、TBDropDownList 設定 DataSoruceID 產生的問題</strong><br /> 上述的解決方法在筆者的「讓 DropDownList DataBind 不再發生錯誤」一文中已經有提及,不過有讀者發現另一個問題,就是當 DropDownList 設定 DataSourceID 時卻會發生資料無法正常繫結,以下就來解決這個問題。<br /> 我們設定 TBDropDownList 的 DataSoruceID 來取得項目清單的內容,將 DataSourceID 設定為另一個取得 Categories 資料表內容的 SqlDataSource 控制項。</p> <pre><code>                &lt;bee:TBDropDownList ID=&quot;DropDownList1&quot; runat=&quot;server&quot;                    SelectedValue='&lt;%# Bind(&quot;CategoryID&quot;) %&gt;' DataSourceID=&quot;SqlDataSource2&quot;                    DataTextField=&quot;CategoryName&quot; DataValueField=&quot;CategoryID&quot;&gt;                &lt;/bee:TBDropDownList&gt;                &lt;asp:SqlDataSource ID=&quot;SqlDataSource2&quot; runat=&quot;server&quot;                    ConnectionString=&quot;&lt;%$ ConnectionStrings:Northwnd %&gt;&quot;                    SelectCommand=&quot;SELECT CategoryID, CategoryName, Description, Picture FROM Categories&quot;                    ProviderName=&quot;&lt;%$ ConnectionStrings:Northwnd.ProviderName %&gt;&quot; &gt;                &lt;/asp:SqlDataSource&gt; </code></pre> <p>當執行程式時,FormView 原本在瀏覽模式時的 CategoryID 欄位值為 7 (CategoryName 應為 Product)。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay22DropDownList_14F78/image_thumb_3.png" alt="" /><br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay22DropDownList_14F78/image_thumb_2.png" alt="" /></p> <p>當按下「編輯」時切換到 EditItemTemplate 時,改用 TBDropDownList 繫結 CategoryID 欄位值,可以這時欲無法繫結正確的值。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay22DropDownList_14F78/image_thumb_4.png" alt="" /></p> <p>[超過字數限制,下一篇接續本文]</p> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/22/5749.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/22/5749.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-23 06:59:56</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day21] 實作控制項智慧標籤(續)</title>                <link>https://ithelp.ithome.com.tw/articles/10012897?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10012897?sc=rss.iron</guid>                <description><![CDATA[<p>接續 [ASP.NET 控制項實作 Day21] 實作控制項智慧標籤 一文<br /> <strong>step2. 在智慧標籤面板加入屬性項目</strong><br /> DesignerA...]]></description>                                    <content:encoded><![CDATA[<p>接續 [ASP.NET 控制項實作 Day21] 實作控制項智慧標籤 一文<br /> <strong>step2. 在智慧標籤面板加入屬性項目</strong><br /> DesignerActionPropertyItem 類別是設定智慧標籤面上的屬性項目,DesignerActionPropertyItem 建構函式的第一個參數(memberName) 為屬性名稱,這個屬性指的是 TBDateEditActionList 類別中的屬性,所以要在 TBDateEditActionList 新增一個對應的屬性。<br /> 例如在智慧標籤中加入 AutoPostBack 屬性項目,則在 TBDateEditActionList 類別需有一個對應 AutoPostBack 屬性。</p> <pre><code>            oItems.Add(New DesignerActionPropertyItem(&quot;AutoPostBack&quot;, _                &quot;AutoPostBack&quot;, &quot;Behavior&quot;, &quot;是否引發 PostBack 動作。&quot;)) </code></pre> <p>TBDateEditActionList.AutoPostBack 屬性如下,其中 Me.Component 指的是目前的 TDateEdit 控制項,透過 GetPropertyValue 及 SetPropertyValue 方法來存取控制項的指定屬性。</p> <pre><code>        ''' &lt;summary&gt;        ''' 是否引發 PostBack 動作。        ''' &lt;/summary&gt;        Public Property AutoPostBack() As Boolean            Get                Return CType(GetPropertyValue(Me.Component, &quot;AutoPostBack&quot;), Boolean)            End Get            Set(ByVal value As Boolean)                SetPropertyValue(Me.Component, &quot;AutoPostBack&quot;, value)            End Set        End Property    ''' &lt;summary&gt;    ''' 設定物件的屬性值。    ''' &lt;/summary&gt;    ''' &lt;param name=&quot;Component&quot;&gt;屬性值將要設定的物件。&lt;/param&gt;    ''' &lt;param name=&quot;PropertyName&quot;&gt;屬性名稱。&lt;/param&gt;    ''' &lt;param name=&quot;Value&quot;&gt;新值。&lt;/param&gt;    Public Shared Sub SetPropertyValue(ByVal Component As Object, ByVal PropertyName As String, ByVal Value As Object)        Dim Prop As PropertyDescriptor = TypeDescriptor.GetProperties(Component).Item(PropertyName)        Prop.SetValue(Component, Value)    End Sub    ''' &lt;summary&gt;    ''' 取得物件的屬性值。    ''' &lt;/summary&gt;    ''' &lt;param name=&quot;Component&quot;&gt;具有要擷取屬性的物件。&lt;/param&gt;    ''' &lt;param name=&quot;PropertyName&quot;&gt;屬性名稱。&lt;/param&gt;    Public Shared Function GetPropertyValue(ByVal Component As Object, ByVal PropertyName As String) As Object        Dim Prop As PropertyDescriptor = TypeDescriptor.GetProperties(Component).Item(PropertyName)        Return Prop.GetValue(Component)    End Function </code></pre> <p><strong>step3. 在智慧標籤面板加入方法項目</strong><br /> DesignerActionMethodItem 類別是設定智慧標籤面上的方法項目,DesignerActionPropertyItem 建構函式的第二個參數(memberName) 為方法名稱,這個方法指的是 TBDateEditActionList 類別中的方法,所以要在 TBDateEditActionList 新增一個對應的方法。<br /> 例如在智慧標籤中加入 About 方法項目,則在 TBDateEditActionList 類別需有一個對應 About 方法。</p> <pre><code>            oItems.Add(New DesignerActionMethodItem(Me, &quot;About&quot;, _                &quot;關於 TDateEdit 控制項&quot;, &quot;About&quot;, _                &quot;關於 TDateEdit 控制項。&quot;, True)) </code></pre> <p>TBDateEditActionList 的 About 方法只是單純顯示一個訊息視窗,一般你可以在這方法加入任何想在設計階段處理的動作。例如自動產生 GridView 的欄位、在 FormView 加入控制項並自動排版,這些都可以在此實現的。</p> <pre><code>        Public Sub About()            MsgBox(&quot;TDateEdit 是結合 The Coolest DHTML Calendar 日期選擇器實作的控制項&quot;)        End Sub </code></pre> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/22/5749.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/22/5749.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-22 18:02:28</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day21] 實作控制項智慧標籤</title>                <link>https://ithelp.ithome.com.tw/articles/10012896?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10012896?sc=rss.iron</guid>                <description><![CDATA[<p>控制項通常會把常用屬性或功能顯示在智慧標籤中,提供使用者更簡便的快速設定,例如下圖為 GridView 的智慧。若要製作控制項的智慧標籤,需實作控制項的 ActionList 加入智慧標籤中要顯...]]></description>                                    <content:encoded><![CDATA[<p>控制項通常會把常用屬性或功能顯示在智慧標籤中,提供使用者更簡便的快速設定,例如下圖為 GridView 的智慧。若要製作控制項的智慧標籤,需實作控制項的 ActionList 加入智慧標籤中要顯示的項目,在本文將以 TDateEdit 控制項為例,進一步說明控制項的智慧標籤的實作方式。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay21_6429/image_thumb.png" alt="" /><br /> 程式碼下載:<a href="http://files.dotblogs.com.tw/jeff377/0810/2008102217453969.rar" target="_blank">ASP.NET Server Control - Day21.rar</a></p> <p><strong>一、TDateEdit 控制項介紹</strong><br /> TDateEdit 控制項是筆者之前在部落格中實作的一個日期控制項,如下圖所示。它是結合 JavaScript 的 The Coolest DHTML Calendar 日期選擇器實作的控制項,我已將 TDateEdit 控制項的相關程式碼含入 Bee.Web.dll 組件中。TDateEdit 控制項的相關細節可以參考筆者部落格下面幾篇文章有進一步說明,本文將以 TDateEdit 控制項為例,只針對實作智慧標籤的部分做進一步說明。<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/03/17/1742.aspx" target="_blank">日期控制項實作教學(1) - 結合 JavaScript</a><br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/03/17/1743.aspx" target="_blank">日期控制項實作教學(2) - PostBack 與 事件</a><br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/03/17/1746.aspx" target="_blank">TBDateEdit 日期控制項 - 1.0.0.0 版 (Open Source)</a><br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay21_6429/image_thumb_1.png" alt="" /></p> <p><strong>二、控制項加入智慧標籤</strong><br /> 控制項要加入智慧標籤要實作控制項的 Designer,我們繼承 ControlDesigner 命名為 TBDateEditDesigner,然後覆寫 ActionLists 屬性,此屬性即是傳回智慧標籤中所包含的項目清單集合。在 ActionLists 屬性中一般會先加入父類別的 ActionLists 屬性,再加入自訂的 ActionList 類別,這樣才可以保留原父類別中智慧標籤的項目清單。</p> <pre><code>    ''' &lt;summary&gt;    ''' TBDateEdit 控制項的設計模式行為。    ''' &lt;/summary&gt;    Public Class TBDateEditDesigner        Inherits System.Web.UI.Design.ControlDesigner        ''' &lt;summary&gt;        ''' 取得控制項設計工具的動作清單集合。        ''' &lt;/summary&gt;        Public Overrides ReadOnly Property ActionLists() As DesignerActionListCollection            Get                Dim oActionLists As New DesignerActionListCollection()                oActionLists.AddRange(MyBase.ActionLists)                oActionLists.Add(New TBDateEditActionList(Me))                Return oActionLists            End Get        End Property    End Class </code></pre> <p>我們自訂的 ActionList 為 TBDateEditActionList 類別,它在智慧標籤呈現的項目清單如下圖所示,接下去我們會說明 TBDateEditActionList 類別的內容。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay21_6429/image_thumb_2.png" alt="" /></p> <p><strong>三、自訂智慧標籤面板的項目清單集合</strong><br /> DesignerActionList 類別定義用於建立智慧標籤面板的項目清單的基底類別,所以我們首先繼承 DesignerActionList 命名為 TBDateEditActionList。</p> <pre><code>    ''' &lt;summary&gt;    ''' 定義 TBDateEdit 控制項智慧標籤面板的項目清單集合。    ''' &lt;/summary&gt;    Public Class TBDateEditActionList        Inherits DesignerActionList        ''' &lt;summary&gt;        ''' 建構函式。        ''' &lt;/summary&gt;        Public Sub New(ByVal owner As ControlDesigner)            MyBase.New(owner.Component)        End Sub    End Class </code></pre> <p>接下來要覆寫 GetSortedActionItems 方法,它會回傳 DesignerActionItemCollection 集合型別,此集合中會傳回要顯示在智慧標籤面板的項目清單集合,所以我們要在 DesignerActionItemCollection 集合中加入我們要呈現的項目清單內容。</p> <pre><code>        ''' &lt;summary&gt;        ''' 傳回要顯示在智慧標籤面板的項目清單集合。        ''' &lt;/summary&gt;        Public Overrides Function GetSortedActionItems() As System.ComponentModel.Design.DesignerActionItemCollection            Dim oItems As New DesignerActionItemCollection()            '在此加入智慧標籤面板的項目清單                      Return oItems        End Function </code></pre> <p><strong>step1. 在智慧標籤面板加入靜態標題項目</strong><br /> 首先介紹 DesignerActionHeaderItem 類別,它是設定靜態標題項目,例如我們在 TDateEdit 的智慧標籤中加入「行為」、「外觀」二個標題項目,其中 DesignerActionHeaderItem 建構函式的 category 參數是群組名稱,我們可以將相關的項目歸類到同一個群組。</p> <pre><code>Dim oItems As New DesignerActionItemCollection() oItems.Add(New DesignerActionHeaderItem(&quot;行為&quot;, &quot;Behavior&quot;)) oItems.Add(New DesignerActionHeaderItem(&quot;外觀&quot;, &quot;Appearance&quot;)) </code></pre> <p>[超過字數限制,下一篇接續本文]</p> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/22/5749.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/22/5749.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-22 18:01:29</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day20] 偵錯設計階段的程式碼</title>                <link>https://ithelp.ithome.com.tw/articles/10012807?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10012807?sc=rss.iron</guid>                <description><![CDATA[<p>上篇我們介紹了自訂 Designer 來輸出控制項設計階段的 HTML 碼,可是若你去對針 Designer 的程式碼下中斷點,你會發覺根本無法偵錯。因為程式在執行階段時期,根本不會執行 Des...]]></description>                                    <content:encoded><![CDATA[<p>上篇我們介紹了自訂 Designer 來輸出控制項設計階段的 HTML 碼,可是若你去對針 Designer 的程式碼下中斷點,你會發覺根本無法偵錯。因為程式在執行階段時期,根本不會執行 Designer 相關類別,所以你在 Designer 類別中下的中斷點完全無效;當然不可能這樣寫程式碼而用感覺去偵錯,本文將告訴你如何去偵錯設計階段的程式碼。<br /> <strong>一、設計階段程式碼的錯誤</strong><br /> 如果撰寫 Designer、Editor、ActionList 等設計階段的程式碼,當這些設計階段的程式碼發生錯誤,可能會發生設計頁面中控制項的錯誤情形,如下圖所示。因為控制項專案本身非啟動專案,在測試網站的設計頁面若控制項發生異常時會直接釋出錯誤,無法偵錯設計階段的程式碼;若真得要偵錯誤設計階段的問題,就要使用另一個 VS2008 來偵錯。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay20_E7AA/image_thumb_1.png" alt="" /></p> <p><strong>二、設定起始外部程式</strong><br /> 要偵錯控制項設計階段的程式碼,要先將控制項專案(Bee.Web)設定為啟時專案。然後設定控制項專案的「屬性」,在「偵錯」頁籤中的起始動作選擇「起始外部程式」,選擇 VS2008 的執行檔位置,預設為 C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\devenv.exe。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay20_E7AA/image_thumb.png" alt="" /></p> <p><strong>三、開始偵錯設計階段程式碼</strong><br /> <strong>step1. 控制項專案開始偵錯</strong><br /> 在設計階要偵錯的程式碼下中斷點,在控制項專案按下 F5 開始偵錯,這時會啟動另一個新的 VS2008 執行檔。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay20_E7AA/image_thumb_2.png" alt="" /></p> <p><strong>step2. 在新的 VS2008 的工具箱加入控制項</strong><br /> 在新的 VS2008 中新增一個測試網站,在工具箱按右鍵執行「選擇項目」開啟「選擇工具箱項目」視窗,然後按「瀏覽」鈕按選擇控制項組件(Bee.Web.dll),將要偵錯的控制項加入工具箱中。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay20_E7AA/image_thumb_4.png" alt="" /><br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay20_E7AA/image_thumb_5.png" alt="" /><br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay20_E7AA/image_thumb_6.png" alt="" /></p> <p><strong>step3. 將控制項拖曳至頁面做設計動作</strong><br /> 在新的 VS2008 中,將控制項拖曳至頁面,就會開始執行設計階段的程式碼,特定的設計動作就會執行到相對的設計階段程式碼,當執行到之前下的中斷點時就可以開始偵錯了。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay20_E7AA/image_thumb_7.png" alt="" /></p> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/21/5741.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/21/5741.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-21 00:28:45</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day19] 控制項設計階段的外觀</title>                <link>https://ithelp.ithome.com.tw/articles/10012682?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10012682?sc=rss.iron</guid>                <description><![CDATA[<p>有一些控制項在執行階段是不會呈現,也就是說控制項本身在執行階段不會 Render 出 HTML 碼,例如 SqlDataSoruce、ScriptManager 這類控制項;那它們在設計階段的頁...]]></description>                                    <content:encoded><![CDATA[<p>有一些控制項在執行階段是不會呈現,也就是說控制項本身在執行階段不會 Render 出 HTML 碼,例如 SqlDataSoruce、ScriptManager 這類控制項;那它們在設計階段的頁面是如何呈現出來呢?本文將針對控制項設計階段的外觀做進一步的說明。<br /> 程式碼下載:ASP.NET Server Control - Day19.rar<br /> <strong>一、控制項設計階段的 HTML 碼</strong><br /> Web 伺服器控制項的設計模式行為都是透過 ControlDesigner 來處理,連設計階段時控制項的外觀也是如此;控制項在設計階段與執行執行時呈現的外觀不一定相同,當然大部分會儘量一致,使其能所見即所得。<br /> 控制項在設計階段的 HTML 碼是透 ControlDesigner.GetDesignTimeHtml 方法來處理,在 ControlDesigner.GetDesignTimeHtml 預設會執行控制項的 RenderControl 方法,所以大部分的情況下設計階段與執行階段輸出的 HTML 碼會相同。當控制項的 Visible=False 時,執行階段是完全不會輸出 HTML 碼,可是在設計階段時會特別將控制項設定 Visible=True,使控制項能完整呈現。</p> <p>ControlDesigner.GetDesignTimeHtml 方法</p> <pre><code>Public Overridable Function GetDesignTimeHtml() As String    Dim writer As New StringWriter(CultureInfo.InvariantCulture)    Dim writer2 As New DesignTimeHtmlTextWriter(writer)    Dim errorDesignTimeHtml As String = Nothing    Dim flag As Boolean = False    Dim visible As Boolean = True    Dim viewControl As Control = Nothing    Try        viewControl = Me.ViewControl        visible = viewControl.Visible        If Not visible Then            viewControl.Visible = True            flag = Not Me.UsePreviewControl        End If        viewControl.RenderControl(writer2)        errorDesignTimeHtml = writer.ToString    Catch exception As Exception        errorDesignTimeHtml = Me.GetErrorDesignTimeHtml(exception)    Finally        If flag Then            viewControl.Visible = visible        End If    End Try    If ((Not errorDesignTimeHtml Is Nothing) AndAlso (errorDesignTimeHtml.Length &lt;&gt; 0)) Then        Return errorDesignTimeHtml    End If    Return Me.GetEmptyDesignTimeHtml End Function </code></pre> <p><strong>二、自訂控制項的 Designer</strong><br /> 以 TBToolbar 為例,若我們在 RenderContents 方法未針對 Items.Count=0 做輸出 HTML 的處理,會發現未設定 Items 屬性時,在設計頁面上完全看不到 TBToolbar 控制項;像這種控制項設計階段的 HTML 碼,就可以自訂控制項的 Designer 來處理。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay19_1ACC/image_thumb.png" alt="" /></p> <p>繼承 ControlDesigner 命名為 TBToolbarDesigner,這個類別是用來擴充 TBToolbar 控制項的設計模式行為。我們可以覆寫 GetDesignTimeHtml 方法,處理設計階段表示控制項的 HTML 標記,此方法回傳的 HTML 原始碼就是控制項呈現在設計頁面的外觀。所以我們可以在 TBToolbar.Items.Count=0 時,輸出一段提示的 HTML 碼,這樣當 TBToolbar 未設定 Items 屬性時一樣可以在設計頁面上呈現控制項。</p> <pre><code>    ''' &lt;summary&gt;    ''' 擴充 TBToolbar 控制項的設計模式行為。    ''' &lt;/summary&gt;    Public Class TBToolbarDesigner        Inherits System.Web.UI.Design.ControlDesigner        ''' &lt;summary&gt;        ''' 用來在設計階段表示控制項的 HTML 標記。        ''' &lt;/summary&gt;        Public Overrides Function GetDesignTimeHtml() As String            Dim sHTML As String            Dim oControl As TBToolbar            oControl = CType(ViewControl, TBToolbar)            If oControl.Items.Count = 0 Then                sHTML = &quot;&lt;div style=&quot;&quot;background-color: #C0C0C0; border:solid 1px; width:200px&quot;&quot;&gt;請設定 Items 屬性&lt;/div&gt;&quot;            Else                sHTML = MyBase.GetDesignTimeHtml()            End If            Return sHTML        End Function    End Class </code></pre> <p>在 TBToolbar 控制項套用 DesignerAttribute 設定自訂的 TBToolbarDesigner 類別。</p> <pre><code>    &lt;Designer(GetType(TBToolbarDesigner))&gt; _    Public Class TBToolbar        Inherits WebControl    End Class </code></pre> <p>重建控制項組件,切換到設計頁面上的看 TBToolbar 控制項未設定 Items 屬性時的外觀,就是我們在 TBToolbarDesigner.GetDesignTimeHtml 方法回傳的 HTML 碼。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay19_1ACC/image_thumb_1.png" alt="" /></p> <p>如果你覺得上述設計階段的控制項有點太陽春,我們也可以輸出類似 SqlDataSource 控制項的外觀,將未設定 Items 屬性時輸出 HTML 改呼叫 CreatePlaceHolderDesignTimeHtml 方法。</p> <pre><code>            If oControl.Items.Count = 0 Then                sHTML = MyBase.CreatePlaceHolderDesignTimeHtml(&quot;請設定 Items 屬性&quot;)            Else                sHTML = MyBase.GetDesignTimeHtml()            End If </code></pre> <p>來看一下這樣修改後的結果,是不是比較專業一點了呢。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay19_1ACC/image_thumb_2.png" alt="" /></p> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/20/5726.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/20/5726.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-20 02:25:29</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day18] 修改集合屬性編輯器</title>                <link>https://ithelp.ithome.com.tw/articles/10012636?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10012636?sc=rss.iron</guid>                <description><![CDATA[<p>上篇我們實作了「集合屬性包含不同型別的成員」,不過若有去使用屬性視窗編輯 TBToolbar 的 Items 屬性,你會發覺這個集合屬性編輯器無法加入我們定義不同型別的成員,只能加入最原始的集合...]]></description>                                    <content:encoded><![CDATA[<p>上篇我們實作了「集合屬性包含不同型別的成員」,不過若有去使用屬性視窗編輯 TBToolbar 的 Items 屬性,你會發覺這個集合屬性編輯器無法加入我們定義不同型別的成員,只能加入最原始的集合成員。是不是只能在 aspx 程式碼中手動去輸入呢?當然不需要這樣人工作業,只要改掉集合屬性編輯器就可以達到我們的需求,本文將介紹修改集合屬性編輯器的相關作法。<br /> 程式碼下載:<a href="http://files.dotblogs.com.tw/jeff377/0810/200810190138285.rar" target="_blank">ASP.NET Server Control - Day18.rar</a></p> <p><strong>一、自訂集合屬性編輯器</strong><br /> 我們先看一下 TBToolbar.Items 屬性套用的 EditorAttribute,它是使用 CollectionEditor 類別來當作屬性編輯器,所以我們就是要繼承 CollectionEditor 類別下來修改成自訂的屬性編輯器。</p> <pre><code>&lt; _ Editor(GetType(CollectionEditor), GetType(UITypeEditor)) _ &gt; _ Public ReadOnly Property Items() As TBToolbarItemCollection </code></pre> <p>新增一個繼承 CollectionEditor 的 TBToolbarItemCollectionEditor 類別,並加入建構函式。此類別屬於 Bee.WebControls.Design 命名空間,通常我們會把設計階段使用的類別歸類到特別的命名空間便於管理及使用。</p> <pre><code>Namespace WebControls.Design    Public Class TBToolbarItemCollectionEditor        Inherits CollectionEditor        ''' &lt;summary&gt;        ''' 建構函式。        ''' &lt;/summary&gt;        ''' &lt;param name=&quot;Type&quot;&gt;型別。&lt;/param&gt;        Public Sub New(ByVal Type As Type)            MyBase.New(Type)        End Sub    End Class End Namespace </code></pre> <p>我們可以先修改 Items 屬性的 EditorAttribute,看看我們自訂的 TBToolbarItemCollectionEditor 是否能正常運作。不過這個屬性編輯器跟原本的沒什麼差異,因為我們只是單純繼承下來沒做任何異動,接下去我們就要開始來修改這個屬性編輯器。</p> <pre><code>&lt; _ Editor(GetType(TBToolbarItemCollectionEditor), GetType(UITypeEditor)) _ &gt; _ Public ReadOnly Property Items() As TBToolbarItemCollection </code></pre> <p><strong>二、加入不同型別的集合成員</strong><br /> 再來我們就要著手修改集合屬性編輯器,讓它可以加入不同型別的集合成員。覆寫 CollectionEditor 的 CanSelectMultipleInstances 方法傳回 True,這個方法是設定 CollectionEditor 是否允許加入多種不同型別的集合成員。</p> <pre><code>        Protected Overrides Function CanSelectMultipleInstances() As Boolean            Return True        End Function </code></pre> <p>再來覆寫 CreateNewItemTypes 方法,這個方法是取得這個集合編輯器可包含的資料型別,將集合可包含的資料型別以陣列傳回。</p> <pre><code>        ''' &lt;summary&gt;        ''' 取得這個集合編輯器可包含的資料型別。        ''' &lt;/summary&gt;        ''' &lt;returns&gt;這個集合可包含的資料型別陣列。&lt;/returns&gt;        Protected Overrides Function CreateNewItemTypes() As System.Type()            Dim ItemTypes(2) As System.Type            ItemTypes(0) = GetType(TBToolbarButton)            ItemTypes(1) = GetType(TBToolbarTextbox)            ItemTypes(2) = GetType(TBToolbarLabel)            Return ItemTypes        End Function </code></pre> <p>重建控制項組件,使用 Items 的集合屬性編輯器,就可以發現「加入」鈕的下拉清單就會出現我們所定義的三種型別的集合成員,如此可以加入不同型別的成員了。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay18_6E6C/image_2.png" alt="" /></p> <p><strong>三、設定清單項目的顯示文字</strong><br /> 在成員清單項目中預設會顯示成員含命名空間的型別,若我們要修改成比較有識別的顯示文字,例如 TBToolbarButton(Key=Add) 可以顯示「按鈕-Add」,這時可以覆寫 GetDisplayText 方法來設定清單項目的顯示文字。</p> <pre><code>        ''' &lt;summary&gt;        ''' 取出指定清單項目的顯示文字。        ''' &lt;/summary&gt;        Protected Overrides Function GetDisplayText(ByVal value As Object) As String            If TypeOf value Is TBToolbarButton Then                Return String.Format(&quot;按鈕 - {0}&quot;, CType(value, TBToolbarButton).Key)            ElseIf TypeOf value Is TBToolbarTextbox Then                Return &quot;文字框&quot;            ElseIf TypeOf value Is TBToolbarLabel Then                Return String.Format(&quot;標籤 - {0}&quot;, CType(value, TBToolbarLabel).Text)            Else                Return value.GetType.Name            End If        End Function </code></pre> <p><img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay18_6E6C/image_4.png" alt="" /></p> <p><strong>四、集合編輯器的屬性視窗的屬性描述</strong><br /> 一般屬性視窗下面都會有屬性描述,可以集合屬性編輯器中的屬性視窗下面竟沒有屬性描述。若我們要讓它的屬性描述可以顯示,可以覆寫 CreateCollectionForm 方法,取得集合屬性編輯表單,再去設定表單上的 PropertyGrid.HelpVisible<br /> = True 即可。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay18_6E6C/image_6.png" alt="" /></p> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/19/5721.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/19/5721.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-19 00:13:21</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day17] 集合屬性包含不同型別的成員</title>                <link>https://ithelp.ithome.com.tw/articles/10012600?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10012600?sc=rss.iron</guid>                <description><![CDATA[<p>我們知道在 GridView 的 Columns 集合屬性中,可以包含不同型別的欄位,如 BoundFIeld、CheckBoxField、HyperLinkField ...等不同型別的欄位。...]]></description>                                    <content:encoded><![CDATA[<p>我們知道在 GridView 的 Columns 集合屬性中,可以包含不同型別的欄位,如 BoundFIeld、CheckBoxField、HyperLinkField ...等不同型別的欄位。如果我們希望工具列中不只包含按鈕,可以包含其他不同類型的子控制項,那該怎麼做呢?本文就以上篇中的 TBToolbar 控制項為案例,讓 Items 集合屬性可以加入 Button、TextBox、Label ...等不同的子控制項。<br /> 程式碼下載:<a href="http://files.dotblogs.com.tw/jeff377/0810/20081017235034673.rar" target="_blank">ASP.NET Server Control - Day17.rar</a><br /> <strong>一、不同型別的集合成員</strong><br /> 我們的需求是讓工具列可以加入 Button、TextBox、Label 三種子控制項,所以繼承原來的 TBToolbarItem (只保留 Enabled 屬性),新增了 TBToolbarButton、TBToolbarTextbox、TBToolbarLabel 三個類別。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay17_1430A/image_6.png" alt="" /></p> <p>這些新增的成員類別都是繼承至 TBToolbarItem,所以在 aspx 程式碼中,手動輸入 Items 的成員時,就會列出這幾種定義的成員型別。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay17_1430A/image_2.png" alt="" /></p> <p><strong>二、建立不同型別集合成員的子控制項</strong><br /> 因為 Items 屬性的成員具不同型別,所以我們要改寫 RenderContents 方法,判斷成員型別來建立對應類型的子控制項。若為 TBToolbarButton 型別建立 Button 控制項、若為 TBToolbarTextbox 型別則建立 TextBox 控制項、若為 TBToolbarLabel 型別則建立 Label 控制項。其中 TBToolbarButton 建立的控制項為 TBButton,這個控制項是我們在「 <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/04/5578.aspx" target="_blank">[ASP.NET 控制項實作 Day3] 擴展現有伺服器控制項功能</a>」一文中實作的具詢問訊息的按鈕控制項。</p> <pre><code>        ''' &lt;summary&gt;        ''' 覆寫 RenderContents 方法。        ''' &lt;/summary&gt;        Protected Overrides Sub RenderContents(ByVal writer As System.Web.UI.HtmlTextWriter)            Dim oItem As TBToolbarItem            Dim oControl As Control            For Each oItem In Me.Items                If TypeOf oItem Is TBToolbarButton Then                    '建立 Button 控制項                    oControl = CreateToolbarButton(CType(oItem, TBToolbarButton))                ElseIf TypeOf oItem Is TBToolbarTextbox Then                    '建立 Textbox 控制項                    oControl = CreateToolbarTextbox(CType(oItem, TBToolbarTextbox))                Else                    '建立 Label 控制項                    oControl = CreateToolbarLabel(CType(oItem, TBToolbarLabel))                End If                Me.Controls.Add(oControl)            Next            MyBase.RenderContents(writer)        End Sub        ''' &lt;summary&gt;        ''' 建立工具列按鈕。        ''' &lt;/summary&gt;        Private Function CreateToolbarButton(ByVal Item As TBToolbarButton) As Control            Dim oButton As TBButton            Dim sScript As String            oButton = New TBButton()            oButton.Text = Item.Text            oButton.Enabled = Item.Enabled            oButton.ID = Item.Key            oButton.ConfirmMessage = Item.ConfirmMessage            sScript = Me.Page.ClientScript.GetPostBackEventReference(Me, Item.Key)            oButton.OnClientClick = sScript            Return oButton        End Function        ''' &lt;summary&gt;        ''' 建立工具列文字框。        ''' &lt;/summary&gt;        Private Function CreateToolbarTextbox(ByVal Item As TBToolbarTextbox) As Control            Dim oTextBox As TextBox            oTextBox = New TextBox            Return oTextBox        End Function        ''' &lt;summary&gt;        ''' 建立工具列標籤。        ''' &lt;/summary&gt;        Private Function CreateToolbarLabel(ByVal Item As TBToolbarLabel) As Control            Dim oLabel As Label            oLabel = New Label()            oLabel.Text = Item.Text            Return oLabel        End Function </code></pre> <p>我們手動在 aspx 程式碼中輸入不同型別的成員,TBToolbar 控制項就會呈現對應的子控制項。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay17_1430A/image_8.png" alt="" /></p> <p><strong>三、執行程式</strong><br /> 執行程式,就可以在瀏覽器看到呈現的工具列,當按下「刪除」時也會出現我們定義的詢問訊息。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay17_1430A/image_4.png" alt="" /></p> <p>輸出的 HTML 碼如下</p> <pre><code>&lt;span id=&quot;TBToolbar1&quot;&gt; &lt;input type=&quot;submit&quot; name=&quot;TBToolbar1$Add&quot; value=&quot;新增&quot; onclick=&quot;__doPostBack('TBToolbar1','Add');&quot; id=&quot;TBToolbar1_Add&quot; /&gt; &lt;input type=&quot;submit&quot; name=&quot;TBToolbar1$Edit&quot; value=&quot;修改&quot; onclick=&quot;__doPostBack('TBToolbar1','Edit');&quot; id=&quot;TBToolbar1_Edit&quot; /&gt; &lt;input type=&quot;submit&quot; name=&quot;TBToolbar1$Delete&quot; value=&quot;刪除&quot; onclick=&quot;if (confirm('確定刪除嗎?')==false) {return false;}__doPostBack('TBToolbar1','Delete');&quot; id=&quot;TBToolbar1_Delete&quot; /&gt; &lt;span&gt;關鍵字&lt;/span&gt; &lt;input name=&quot;TBToolbar1$ctl01&quot; type=&quot;text&quot; /&gt; &lt;input type=&quot;submit&quot; name=&quot;TBToolbar1$Search&quot; value=&quot;搜尋&quot; onclick=&quot;__doPostBack('TBToolbar1','Search');&quot; id=&quot;TBToolbar1_Search&quot; /&gt; &lt;/span&gt; </code></pre> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/18/5718.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/18/5718.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-18 00:05:57</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day16] 繼承 WebControl 實作 Toolbar 控制項</title>                <link>https://ithelp.ithome.com.tw/articles/10012507?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10012507?sc=rss.iron</guid>                <description><![CDATA[<p>前面我們討論過「繼承 CompositeControl 實作 Toolbar 控制項」,本文將繼承 WebControl 來實作同樣功能的 Toolbar 控制項,用不同的方式來實作同一個控制項...]]></description>                                    <content:encoded><![CDATA[<p>前面我們討論過「繼承 CompositeControl 實作 Toolbar 控制項」,本文將繼承 WebControl 來實作同樣功能的 Toolbar 控制項,用不同的方式來實作同一個控制項,進而比較二者之間的差異。<br /> 程式碼下載:<a href="http://files.dotblogs.com.tw/jeff377/0810/20081016225639603.rar" target="_blank">ASP.NET Server Control - Day16.rar</a></p> <p><strong>一、繼承 WebControl 實作 TBToolbar 控制項</strong><br /> <strong>step1. 新增繼承 WebControl 的 TBToolbar 控制項</strong><br /> 新增繼承 WebControl 的 TBToolbar 控制項,你也可以直接原修改原 TBToolbar 控制項,繼承對象由 CompositeControl 更改為 WebControl即可。跟之前一樣在 TBToolbar 控制項加入 Items 屬性及 Click 事件。<br /> 另外 TBToolbar 控制項需實作 INamingContainer 界面,此界面很特殊沒有任何屬性或方法,INamingContainer 界面的作用是子控制項的 ClientID 會在前面加上父控制項的 ClickID,使每個子控制項有唯一的 ClientID。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay15WebControlToolbar_12C6D/image_thumb_3.png" alt="" /></p> <p><strong>step2. 建立工具列按鈕集合</strong><br /> 覆寫 RenderContents 方法,將原本 TBToolbar (複合控制項) 的 CreateChildControls 方法中建立工具列按鈕程式碼,搬移至 RenderContents 方法即可。</p> <pre><code>        Private Sub ButtonClickEventHandler(ByVal sender As Object, ByVal e As EventArgs)            Dim oButton As Button            Dim oEventArgs As ClickEventArgs            oButton = CType(sender, Button)            oEventArgs = New ClickEventArgs()            oEventArgs.Key = oButton.ID            OnClick(oEventArgs)        End Sub        ''' &lt;summary&gt;        ''' 覆寫 RenderContents 方法。        ''' &lt;/summary&gt;        Protected Overrides Sub RenderContents(ByVal writer As System.Web.UI.HtmlTextWriter)            Dim oItem As TBToolbarItem            Dim oButton As Button            For Each oItem In Me.Items                oButton = New Button()                oButton.Text = oItem.Text                oButton.Enabled = oItem.Enabled                oButton.ID = oItem.Key                AddHandler oButton.Click, AddressOf ButtonClickEventHandler                Me.Controls.Add(oButton)            Next            If Me.Items.Count = 0 AndAlso Me.DesignMode Then                oButton = New Button()                oButton.Text = &quot;請設定 Items 屬性。&quot;                Me.Controls.Add(oButton)            End If            MyBase.RenderContents(writer)        End Sub </code></pre> <p>上述的直接搬移過來的程式碼還有個問題,就是原來的使用 AddHandler 來處理按鈕事件的方式變成沒有作用了?因為現在不是複合式控制項,當前端的按鈕 PostBack 傳回伺服端時,TBToolbar 不會事先建立子控制槓,所以機制會找不到原來產生的按鈕,也就無法使用 AddHandler 來處理事件了。</p> <pre><code>AddHandler oButton.Click, AddressOf ButtonClickEventHandler </code></pre> <p><strong>step3. 處理 Click 事件</strong><br /> 因為不能使用 AddHandler 來處理按鈕事件,所以我們就自行使用 Page.ClientScript.GetPostBackEventReference 方法來產生 PostBack 動作的用戶端指令碼,按鈕的 OnClientClick 去執行 PostBack 的動作。</p> <pre><code>            For Each oItem In Me.Items                oButton = New Button()                oButton.Text = oItem.Text                oButton.Enabled = oItem.Enabled                oButton.ID = oItem.Key                sScript = Me.Page.ClientScript.GetPostBackEventReference(Me, oItem.Key)                oButton.OnClientClick = sScript                Me.Controls.Add(oButton)            Next </code></pre> <p>TBToolar 控制項輸出的 HTML 碼如下</p> <pre><code>&lt;span id=&quot;TBToolbar1&quot;&gt; &lt;input type=&quot;submit&quot; name=&quot;TBToolbar1$Add&quot; value=&quot;新增&quot; onclick=&quot;__doPostBack('TBToolbar1','Add');&quot; id=&quot;TBToolbar1_Add&quot; /&gt; &lt;input type=&quot;submit&quot; name=&quot;TBToolbar1$Edit&quot; value=&quot;修改&quot; onclick=&quot;__doPostBack('TBToolbar1','Edit');&quot; id=&quot;TBToolbar1_Edit&quot; /&gt; &lt;input type=&quot;submit&quot; name=&quot;TBToolbar1$Delete&quot; value=&quot;刪除&quot; onclick=&quot;__doPostBack('TBToolbar1','Delete');&quot; id=&quot;TBToolbar1_Delete&quot; /&gt; &lt;/span&gt; </code></pre> <p>要自行處理 PostBack 的事件,需實作 IPostBackEventHandler 介面,在 RaisePostBackEvent 方法來引發 TBToolbar 的 Click 事件。</p> <pre><code>    Public Class TBToolbar        Inherits WebControl        Implements INamingContainer        Implements IPostBackEventHandler        Public Sub RaisePostBackEvent(ByVal eventArgument As String) Implements System.Web.UI.IPostBackEventHandler.RaisePostBackEvent            Dim oEventArgs As ClickEventArgs            oEventArgs = New ClickEventArgs()            oEventArgs.Key = eventArgument            Me.OnClick(oEventArgs)        End Sub    End Class </code></pre> <p><strong>二、測試程式</strong><br /> 在測試頁面上放置 TBToolbar 控制項,在 Click 事件撰寫測試程式碼。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay15WebControlToolbar_12C6D/image_thumb.png" alt="" /></p> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/17/5706.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/17/5706.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-17 00:05:40</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day15] 複合控制項隱藏的問題</title>                <link>https://ithelp.ithome.com.tw/articles/10012425?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10012425?sc=rss.iron</guid>                <description><![CDATA[<p>上一篇我們使用複合控制項(繼承 CompositeControl)的方式來實作 TBToolbar 控制項,本文將針對複合控制項做一些測試,說明在使用複合控制項要注意的一些問題。<br /> 程...]]></description>                                    <content:encoded><![CDATA[<p>上一篇我們使用複合控制項(繼承 CompositeControl)的方式來實作 TBToolbar 控制項,本文將針對複合控制項做一些測試,說明在使用複合控制項要注意的一些問題。<br /> 程式碼下載:<a href="http://files.dotblogs.com.tw/jeff377/0810/2008101612954661.rar" target="_blank">ASP.NET Server Control - Day15.rar</a><br /> <strong>一、複合控制項建立子控制項的時機</strong><br /> 還記得我們之前介紹複合控制項時有談到 CompositeControl 類別會確保我們存取子控制項時,它的子控制項一定會事先建立;也就是當我們使用 Controls 屬性去存取子控制項時,一定會執行 CreateChildControls 方法,以確保子控制項事先被建立。我們看一下 CompositeControl 類別的 Controls 屬性的寫法就可以了解其中的原由,在存取 CompositeControl.Controls 屬性時,它會先執行 Control.EnsureChildControls 方法;而 EnsureChildControls 方法會去判斷子控制項是否已建立,若未建立會去執行 CreateChildControls 方法,這也就是為什麼 CompositeControl 有辨法確保子控制項事先被建立的原因。</p> <p>CompositeControl.Controls 屬性如下</p> <pre><code>Public Overrides ReadOnly Property Controls As ControlCollection    Get        Me.EnsureChildControls        Return MyBase.Controls    End Get End Property </code></pre> <p>Control.EnsureChildControls 方法如下</p> <pre><code>Protected Overridable Sub EnsureChildControls()    If (Not Me.ChildControlsCreated AndAlso Not Me.flags.Item(&amp;H100)) Then        Me.flags.Set(&amp;H100)        Try            Me.ResolveAdapter            If (Not Me._adapter Is Nothing) Then                Me._adapter.CreateChildControls            Else                Me.CreateChildControls            End If            Me.ChildControlsCreated = True        Finally            Me.flags.Clear(&amp;H100)        End Try    End If End Sub </code></pre> <p><strong>二、複合控制項隱藏的問題</strong><br /> 我們以上篇的 TBToolbar 控制項為例,撰寫一些測試案例來說明複合控制項的問題。在撰寫測試案例之前,我們先修改一下 TBToolbar 控制項,覆寫 LoadViewState 及 SaveViewState 方法,將 Items 屬性儲存於 ViewState 中以維持狀態。</p> <p>在測試頁面上放置「測試一」、「測試二」、「PostBack」三個按鈕,這三個按鈕的動作如下。<br /> 「測試一」按鈕:在工具列直接新增一個按鈕。<br /> 「測試二」按鈕:先使用 FindControl 取得工具列的按鈕,然後在在工具列再新增一個按鈕。<br /> 「PostBack」按鈕:單純執行 PostBack,不撰寫程式碼。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay15_E8C/image_thumb.png" alt="" /></p> <p>三個按鈕的程式碼如下所示。</p> <pre><code>    Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click        Dim oItem As TBToolbarItem        '加入新按鈕        oItem = New TBToolbarItem()        oItem.Text = &quot;新按鈕&quot;        oItem.Key = &quot;NewButton&quot;        TBToolbar1.Items.Add(oItem)        Me.Response.Write(&quot;「測試一」按鈕&quot;)    End Sub    Protected Sub Button2_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button2.Click        Dim oItem As TBToolbarItem        Dim oButton As Button        '先執行 FindControl 去取得 ID=&quot;Add&quot; 的按鈕        oButton = TBToolbar1.FindControl(&quot;Add&quot;)        '再加入新按鈕        oItem = New TBToolbarItem()        oItem.Text = &quot;新按鈕&quot;        oItem.Key = &quot;NewButton&quot;        TBToolbar1.Items.Add(oItem)        Me.Response.Write(&quot;「測試二」按鈕&quot;)    End Sub    Protected Sub Button3_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button3.Click        '單純 PostBack,無程式碼        Me.Response.Write(&quot;「PostBack」按鈕&quot;)    End Sub </code></pre> <p>案例一:執行「測試一」按鈕,在工具列直接新增一個按鈕。<br /> 當按下「測試一」按鈕時,工具列可以正常加入我們新增的按鈕。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay15_E8C/image_thumb_1.png" alt="" /></p> <p>案例二:執行「測試二」按鈕,先使用 FindControl 取得工具列的按鈕,然後在在工具列再新增一個按鈕。<br /> 重新執行程式,當按下「測試二」按鈕時,你會發現奇怪的現象,工具列竟然沒有加入我們新增的按鈕?<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay15_E8C/image_thumb_2.png" alt="" /></p> <p>此時再按下「PostBack」按鈕,工具列才會出現我們剛剛加入的按鈕。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay15_E8C/image_thumb_3.png" alt="" /></p> <p>為什麼會發生這種怪現象呢?其實原因很簡單,因為 FindControl 時會去存取 Controls 屬性,而這時子控制項已經被建立了;而之前再用 Items 屬性加入新按鈕,它已經不會在重建子控制項,導致第一時間沒有加入新按鈕。不過 Items 屬性會被存在 ViewState 中,所以當執行「PostBack」按鈕時,就會出現我們剛剛新增的按鈕。</p> <p><strong>三、解決方式</strong><br /> 要解決上述「測試二」的問題,只要覆寫 TBToolbar 控制項的 Render 方法,在 Render 前執行 RecreateChildControls 方法,強制重建子控制項。</p> <pre><code>        ''' &lt;summary&gt;        ''' 覆寫 Render 方法。        ''' &lt;/summary&gt;        Protected Overrides Sub Render(ByVal writer As System.Web.UI.HtmlTextWriter)            Me.RecreateChildControls()            MyBase.Render(writer)        End Sub </code></pre> <p>再一次執行「測試二」的動作,就會發現執行結果就會正常了。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay15_E8C/image_thumb_5.png" alt="" /></p> <p><strong>四、結語</strong><br /> 在複合控制項的 Render 前執行 RecreateChildControls 方法可以強制重建子控制項,可是這樣又會引發另一個問題,那就是當直接存取子控制項去修改子控制項的屬性後,一旦在 Render 又重建子控制項,那之前設定子控制項狀態又被全部重建了,所以需特別注意有這樣的情形。另外複合控制項有可能重覆執行建立子控制的動作,在執行效能上也比較不佳。</p> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/16/5695.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/16/5695.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-16 00:14:12</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day14] 繼承 CompositeControl 實作 Toolbar 控制項</title>                <link>https://ithelp.ithome.com.tw/articles/10012339?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10012339?sc=rss.iron</guid>                <description><![CDATA[<p>之前我們簡單介紹過繼承 CompositeControl 來實作複合控制項,在本文我們將以 Toolbar 控制項為例,以複合控制項的作法(繼承 CompositeControl )來實作 To...]]></description>                                    <content:encoded><![CDATA[<p>之前我們簡單介紹過繼承 CompositeControl 來實作複合控制項,在本文我們將以 Toolbar 控制項為例,以複合控制項的作法(繼承 CompositeControl )來實作 Toolbar 控制項,此工具列控制項包含 Items 屬性來描述工具列項目集合,依 Items 屬性的設定來建立工具列按鈕,另外包含 Click 事件可以得知使用按了那個按鈕。<br /> 程式碼下載:<a href="http://files.dotblogs.com.tw/jeff377/0810/20081014234924792.rar" target="_blank">ASP.NET Server Control - Day14.rar</a><br /> <strong>一、工具列項目集合類別</strong><br /> 工具列包含多個按鈕,新增 TBToolbarItem 類別來描述工具列項目,TBToolbarItem 類別包含 Key、Text、Enabled 三個屬性;而 TBToolbarItemCollection 為 TBToolbarItem 的集合類別來描述工具列按鈕集合。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay14CompositeControlToolbar_12481/image_thumb.png" alt="" /></p> <p><strong>二、實作 TBToolbar 控制項</strong><br /> <strong>step1. 新增繼承 CompositeControl 的 TBToolbar 控制項</strong></p> <pre><code>    &lt; _    Description(&quot;工具列控制項。&quot;), _    ParseChildren(True, &quot;Items&quot;), _    ToolboxData(&quot;&lt;{0}:TBToolbar runat=server &gt;&lt;/{0}:TBToolbar&gt;&quot;) _    &gt; _    Public Class TBToolbar        Inherits CompositeControl    End Class </code></pre> <p><strong>step2. 新增 Items 屬性,描述工具列項目集合</strong></p> <pre><code>        ''' &lt;summary&gt;        ''' 工具列項目集合。        ''' &lt;/summary&gt;        &lt; _        Description(&quot;工具列項目集合。&quot;), _        PersistenceMode(PersistenceMode.InnerProperty), _        DesignerSerializationVisibility(DesignerSerializationVisibility.Content), _        Editor(GetType(CollectionEditor), GetType(UITypeEditor)) _        &gt; _        Public ReadOnly Property Items() As TBToolbarItemCollection            Get                If FItems Is Nothing Then                    FItems = New TBToolbarItemCollection()                End If                Return FItems            End Get        End Property </code></pre> <p><strong>step3. 新增 Click 事件</strong><br /> TBToolbar 類別新增 Click 事件,當按下按鈕時會引發 Click 事件,由 Click 的事件引數 e.Key 可以得知使用者按了那個按鈕。</p> <pre><code>        ''' &lt;summary&gt;        ''' Click 事件引數。        ''' &lt;/summary&gt;        Public Class ClickEventArgs            Inherits System.EventArgs            Private FKey As String = String.Empty            ''' &lt;summary&gt;            ''' 項目鍵值。            ''' &lt;/summary&gt;            Public Property Key() As String                Get                    Return FKey                End Get                Set(ByVal value As String)                    FKey = value                End Set            End Property        End Class        ''' &lt;summary&gt;        ''' 按下工具列按鈕所引發的事件。        ''' &lt;/summary&gt;        &lt; _        Description(&quot;按下工具列按鈕所引發的事件。&quot;) _        &gt; _        Public Event Click(ByVal sender As Object, ByVal e As ClickEventArgs)        ''' &lt;summary&gt;        ''' 引發 Click 事件。        ''' &lt;/summary&gt;        Protected Overridable Sub OnClick(ByVal e As ClickEventArgs)            RaiseEvent Click(Me, e)        End Sub </code></pre> <p><strong>step4. 建立工具列按鈕集合</strong><br /> 覆寫 CreateChildControls 方法,依 Items 屬性的設定,來建立工具列中的按鈕集合。每個按鈕的 Click 事件都導向 ButtonClickEventHandler 方法,來處理所有按鈕的 Click 動作,並引發 TBToolbar 的 Click 事件。</p> <pre><code>        Private Sub ButtonClickEventHandler(ByVal sender As Object, ByVal e As EventArgs)            Dim oButton As Button            Dim oEventArgs As ClickEventArgs            oButton = CType(sender, Button)            oEventArgs = New ClickEventArgs()            oEventArgs.Key = oButton.ID            OnClick(oEventArgs)        End Sub        ''' &lt;summary&gt;        ''' 建立子控制項。        ''' &lt;/summary&gt;        Protected Overrides Sub CreateChildControls()            Dim oItem As TBToolbarItem            Dim oButton As Button            For Each oItem In Me.Items                oButton = New Button()                oButton.Text = oItem.Text                oButton.Enabled = oItem.Enabled                oButton.ID = oItem.Key                AddHandler oButton.Click, AddressOf ButtonClickEventHandler                Me.Controls.Add(oButton)            Next            MyBase.CreateChildControls()        End Sub </code></pre> <p><strong>三、測試程式</strong><br /> 在頁面拖曳 TBToolbar 控制項,並設定 Items 屬性,如入新增、修改、刪除三個按鈕。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay14CompositeControlToolbar_12481/image_thumb_1.png" alt="" /></p> <p>在 TBToolbar 控制項的 Click 事件加入測試程式碼,輸出引發 Click 事件的 e.Key。</p> <pre><code>    Protected Sub TBToolbar1_Click(ByVal sender As Object, ByVal e As Bee.Web.WebControls.TBToolbar.ClickEventArgs) Handles TBToolbar1.Click        Me.Response.Write(String.Format(&quot;您按了 {0}&quot;, e.Key))    End Sub </code></pre> <p>執行程式,當按了工具列上的按鈕時,就會引發 Click 事件,並輸出該按鈕對應的 Key。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay14CompositeControlToolbar_12481/image_thumb_2.png" alt="" /></p> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/15/5687.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/15/5687.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-15 00:13:50</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day13] Flash 控制項</title>                <link>https://ithelp.ithome.com.tw/articles/10012267?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10012267?sc=rss.iron</guid>                <description><![CDATA[<p>Flash 也是網頁常用的 ActiveX 插件,在本文中將繼承 TBActiveX 下來撰寫 TBFlash 控制項,用來輸出網頁套用 Flash 的相關 HTML 碼。<br /> 程式碼下...]]></description>                                    <content:encoded><![CDATA[<p>Flash 也是網頁常用的 ActiveX 插件,在本文中將繼承 TBActiveX 下來撰寫 TBFlash 控制項,用來輸出網頁套用 Flash 的相關 HTML 碼。<br /> 程式碼下載:<a href="http://files.dotblogs.com.tw/jeff377/0810/2008101323519608.rar" target="_blank">ASP.NET Server Control - Day13.rar</a></p> <p><strong>一、網頁 Flash 的原始 HTML 碼</strong><br /> 我們先觀查在網頁中套用 Flash 插件的原始 HTML 碼,以點部落首頁抬頭的 Flash 原始碼為例如下,其中 &lt;object&gt; tag 的 codebase attribute 是指 Flash 插件的下載位置及版本。</p> <pre><code>&lt;object id=&quot;ShockwaveFlash2&quot; height=&quot;90&quot; width=&quot;728&quot;  codebase=&quot;http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,29,0&quot;  classid=&quot;clsid:D27CDB6E-AE6D-11cf-96B8-444553540000&quot;&gt; &lt;param value=&quot;http://files.dotblogs.com.tw/dotjum/ad/debug.swf&quot; name=&quot;movie&quot;/&gt; &lt;param value=&quot;high&quot; name=&quot;quality&quot;/&gt; &lt;param value=&quot;#000000&quot; name=&quot;bgcolor&quot;/&gt; &lt;embed height=&quot;90&quot; width=&quot;728&quot; type=&quot;application/x-shockwave-flash&quot;  pluginspage=&quot;http://www.macromedia.com/go/getflashplayer&quot; quality=&quot;high&quot;  src=&quot;http://files.dotblogs.com.tw/dotjum/ad/debug.swf&quot;/&gt; &lt;/object&gt; </code></pre> <p>在 &lt;object&gt; tag 中必要的 attribute 為 classid、codebase、movie、width、height,而 &lt;embed&gt; tag 的必要 attribute 為 src、pluginspage、width、height,其他選擇性的 attribute 可參閱以下網頁。</p> <p>Flash OBJECT and EMBED tag attributes<br /> <a href="http://kb.adobe.com/selfservice/viewContent.do?externalId=tn_12701" target="_blank"><a href="http://kb.adobe.com/selfservice/viewContent.do?externalId=tn%5C_12701" target="_blank">http://kb.adobe.com/selfservice/viewContent.do?externalId=tn\_12701</a></a></p> <p><strong>二、實作 TFlash 控制項</strong><br /> 了解 Flash 的原始 HTML 碼後,我們就可以開始著手撰寫 TBFlash 控制項,想辨法來輸出所需要的 HTML 碼。</p> <p><strong>step1. 新增 TBFlash 控制項繼承至 TBActiveX</strong><br /> 我們先在 TBActiveX 控制項新增一個 CodeBase 屬性,用來設定 ActiveX 插入的下載位置及版本,然後新增 TBFlash 控制項繼承至 TBActiveX,並在建構函式中設定 MyBase.ClassId 及 MyBase.CodeBase 屬性。</p> <pre><code>    Public Class TBFlash        Inherits TBActiveX        ''' &lt;summary&gt;        ''' 建構函式。        ''' &lt;/summary&gt;        Sub New()            MyBase.ClassId = &quot;D27CDB6E-AE6D-11CF-96B8-444553540000&quot;            MyBase.CodeBase = &quot;http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,29,0&quot;        End Sub    End Class </code></pre> <p><strong>step2. 加入相關屬性</strong><br /> 在 TBFlash 加入 MovieUrl 及 Quality 屬性,MovieUrl 為 Flash 檔案來源,Quality 為影音品質。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay13Flash_13AEC/image_2.png" alt="" /></p> <p><strong>step3. 輸出 Flash 相關參數</strong><br /> 覆寫 CreateChildControls 方法,輸出 MovieUrl 及 Quality 屬性對應的參數,以及在 Params 集合屬性設定的參數。</p> <pre><code>        ''' &lt;summary&gt;        ''' 加入 MediaPlayer 參數。        ''' &lt;/summary&gt;        ''' &lt;param name=&quot;Name&quot;&gt;參數名稱。&lt;/param&gt;        ''' &lt;param name=&quot;Value&quot;&gt;參數值。&lt;/param&gt;        Private Sub AddParam(ByVal Name As String, ByVal Value As String)            Dim oParam As TBActiveXParam            oParam = New TBActiveXParam(Name, Value)            Me.Params.Add(oParam)        End Sub        ''' &lt;summary&gt;        ''' 建立 Embed 標記。        ''' &lt;/summary&gt;        Private Function CreateEmbed() As HtmlControls.HtmlGenericControl            Dim oEmbed As HtmlControls.HtmlGenericControl            Dim oParam As TBActiveXParam            oEmbed = New HtmlControls.HtmlGenericControl()            oEmbed.TagName = &quot;embed&quot;            oEmbed.Attributes(&quot;src&quot;) = Me.ResolveClientUrl(Me.MovieUrl)            oEmbed.Attributes(&quot;pluginspage&quot;) = &quot;http://www.macromedia.com/go/getflashplayer&quot;            oEmbed.Attributes(&quot;height&quot;) = Me.Height.ToString            oEmbed.Attributes(&quot;width&quot;) = Me.Width.ToString            'Embed 的 Attributes 加入 Params 集合屬性的設定            For Each oParam In Me.Params                If oParam.Name &lt;&gt; &quot;movie&quot; Then                    oEmbed.Attributes(oParam.Name) = oParam.Value                End If            Next            Return oEmbed        End Function        ''' &lt;summary&gt;        ''' 建立子控制項。        ''' &lt;/summary&gt;        Protected Overrides Sub CreateChildControls()            Dim oEmbed As HtmlControls.HtmlGenericControl            '加入 movie 參數            AddParam(&quot;movie&quot;, Me.ResolveClientUrl(Me.MovieUrl))            '加入 quality 參數            If Me.Quality &lt;&gt; EQuality.NotSet Then                AddParam(&quot;quality&quot;, Me.Quality.ToString.ToLower)            End If            MyBase.CreateChildControls()            oEmbed = CreateEmbed()            Me.Controls.Add(oEmbed)        End Sub </code></pre> <p><strong>三、測試程式</strong><br /> 在頁面拖曳 TBFlash 控制項,設定 MovieUrl 及 Quality 屬性,若有需要加入其他參數,可自行設定 Params 集合屬性。執行程式就可以在頁面上看到呈現出來的 Flash。</p> <pre><code>        &lt;bee:TBFlash ID=&quot;TBFlash1&quot; runat=&quot;server&quot; Height=&quot;90px&quot;            MovieUrl=&quot;http://files.dotblogs.com.tw/dotjum/ad/debug.swf&quot; Quality=&quot;High&quot;            Width=&quot;728px&quot;&gt;        &lt;/bee:TBFlash&gt; </code></pre> <p><img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay13Flash_13AEC/image_4.png" alt="" /></p> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/14/5674.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/14/5674.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-14 00:16:30</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day12] 繼承 TBActiveX 重新改寫 TBMediaPlayer 控制項</title>                <link>https://ithelp.ithome.com.tw/articles/10012196?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10012196?sc=rss.iron</guid>                <description><![CDATA[<p>上篇介紹的 TBActiveX 控制項,它可以支援網頁 Media Player 的設定,這跟前面提及的 TBMediaPlayer 功能相同。TBActiveX 具有網頁設定 ActiveX ...]]></description>                                    <content:encoded><![CDATA[<p>上篇介紹的 TBActiveX 控制項,它可以支援網頁 Media Player 的設定,這跟前面提及的 TBMediaPlayer 功能相同。TBActiveX 具有網頁設定 ActiveX 通用屬性,所以 TBMediaPlayer 基本上是可以由 TBActiveX 繼承下來,再加入 Media Player 特有的屬性即可。本文將原來的 TBMediaPlayer 控制項,繼承的父類別由 WebControl 改為 TBActiveX 類別,重新改寫 TBMediaPlayer 控制項。<br /> 程式碼下載:<a href="http://files.dotblogs.com.tw/jeff377/0810/200810130325962.rar" target="_blank">ASP.NET Server Control - Day12.rar</a></p> <p><strong>一、改寫 TBMediaPlayer 控制項</strong><br /> TBMediaPlayer 控制項原本是繼承 WebControl,現改繼承對象為 TBActiveX,來重新改寫 TBMediaPlayer 控制項。</p> <p><strong>step1. TBMediaPlayer 繼承至 TBActiveX</strong><br /> 新增 TBMediaPlayer 控制項,繼承至 TBActiveX,並在建構函式設定 Media Player ActiveX 的 ClassId。</p> <pre><code>    Public Class TBMediaPlayer        Inherits TBActiveX        ''' &lt;summary&gt;        ''' 建構函式。        ''' &lt;/summary&gt;        Sub New()            MyBase.ClassId = &quot;6BF52A52-394A-11D3-B153-00C04F79FAA6&quot;        End Sub    End Class </code></pre> <p><strong>step2. 加入相關屬性</strong><br /> 跟原來的 TBMediaPlayer 控制項一樣,加入 Url、AutoStart、UIMode 三個屬性,可視情形加入需要設定的屬性。</p> <p><strong>step3. 加入 Media Player 參數</strong><br /> 覆寫 CreateChildControls 方法,動態依屬性設定在 Params 集合屬性加入參數。雖然 TBMediaPlayer 控制項目前只有 Url、AutoStart、UIMode 三個屬性,但是父類別 TBActiveX 具有 Params 集合屬性,所以開發人員可以視需求加入其他未定義的參數。</p> <pre><code>        ''' &lt;summary&gt;        ''' 加入 MediaPlayer 參數。        ''' &lt;/summary&gt;        ''' &lt;param name=&quot;Name&quot;&gt;參數名稱。&lt;/param&gt;        ''' &lt;param name=&quot;Value&quot;&gt;參數值。&lt;/param&gt;        Private Sub AddParam(ByVal Name As String, ByVal Value As String)            Dim oParam As TBActiveXParam            oParam = New TBActiveXParam(Name, Value)            Me.Params.Add(oParam)        End Sub        ''' &lt;summary&gt;        ''' 覆寫 CreateChildControls 方法。        ''' &lt;/summary&gt;        Protected Overrides Sub CreateChildControls()            '加入 Url 參數            If Me.Url &lt;&gt; String.Empty Then                AddParam(&quot;URL&quot;, Me.ResolveClientUrl(Me.Url))            End If            '加入 autoStart 參數            If Me.AutoStart Then                AddParam(&quot;autoStart&quot;, &quot;true&quot;)            End If            '加入 uiMode 參數            If Me.UIMode &lt;&gt; EUIMode.NotSet Then                AddParam(&quot;uiMode&quot;, Me.UIMode.ToString)            End If            MyBase.CreateChildControls()        End Sub </code></pre> <p><strong>二、執行程式</strong><br /> 在頁面拖曳 TBMediaPlayer 控制項,設定 Url、AutoStart、UIMode 屬性,若有需要加入其他參數,可自行設定 Params 集合屬性。執行程式就可以在頁面上看到呈現出來的 Media Player。</p> <pre><code>        &lt;bee:TBMediaPlayer ID=&quot;TBMediaPlayer1&quot; runat=&quot;server&quot; AutoStart=&quot;True&quot;            Height=&quot;249px&quot; Url=&quot;D:\Movie_01.wmv&quot; Width=&quot;250px&quot;&gt;        &lt;/bee:TBMediaPlayer&gt; </code></pre> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/13/5663.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/13/5663.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-13 00:13:29</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day11] ActiveX 伺服器控制項</title>                <link>https://ithelp.ithome.com.tw/articles/10012159?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10012159?sc=rss.iron</guid>                <description><![CDATA[<p>Media Player 與 Flash 之類在網頁上執行的外掛控制項,都是屬於 ActiveX 控制項,它們套用在 HTML 碼中的方式差不多,除了要指定 ClassID 以外,ActiveX...]]></description>                                    <content:encoded><![CDATA[<p>Media Player 與 Flash 之類在網頁上執行的外掛控制項,都是屬於 ActiveX 控制項,它們套用在 HTML 碼中的方式差不多,除了要指定 ClassID 以外,ActiveX 使用的參數(相當於 ActiveX 控制項的屬性)以 Param Tag 來表示。本文標題命名為「ActiveX 伺服器控制項」就是避免誤解為 ActiveX 控制項,而是在 ASP.NET 中輸出 ActiveX 相關 HTML 碼的伺服器控制項;我們可透過 ActiveX 伺服器控制項可以用來輸出網頁上引用 ActiveX 的通用 HTML 碼,另外 ActiveX 的參數會以集合屬性來呈現,所以也會一併學習到集合屬性的撰寫方式。<br /> 程式碼下載:<a href="http://files.dotblogs.com.tw/jeff377/0810/200810124846794.rar" target="_blank">ASP.NET Server Control - Day11.rar</a></p> <p><strong>一、集合屬性</strong><br /> ActiveX 的 Param 參數是集合屬性,所以我們定義了 TBActiveParam 類別描述 ActiveX 參數,包含 Name 及 Value 屬性;而 TBActiveXParamCollection 為 TBActiveParam 的集合類別,用來描述 ActiveX 參數集合。TBActiveXParamCollection 繼承 CollectionBase,加入操作集合的 Add、Insert、Remove、IndexOf、Contains 等方法,關於集合屬性的用法可以參閱筆者在部落格的「<a href="http://www.dotblogs.com.tw/jeff377/archive/2008/03/17/1747.aspx" target="_blank">撰寫伺服器控制項的集合屬性 (CollectionBase)</a>」一文中有詳細說明。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay11ActiveX_166/image_thumb_1.png" alt="" /></p> <p><strong>二、實作 ActiveX 伺服器控制項</strong><br /> <strong>step1. 新增繼承 WebControl 的 TBActiveX</strong></p> <p><strong>step2. 覆寫 TagKey 屬性,傳回 object 的 Tag</strong></p> <pre><code>        Protected Overrides ReadOnly Property TagKey() As HtmlTextWriterTag            Get                Return HtmlTextWriterTag.Object            End Get        End Property </code></pre> <p><strong>step3. 新增 ClassId 屬性,描述 ActiveX 的 ClassId</strong><br /> 定義 ClassId 屬性,並覆寫 AddAttributesToRender 來輸出此屬性。</p> <pre><code>        ''' &lt;summary&gt;        ''' 覆寫 AddAttributesToRender 方法。        ''' &lt;/summary&gt;        Protected Overrides Sub AddAttributesToRender(ByVal writer As HtmlTextWriter)            '加入 MediaPlayer ActiveX 元件的 classid            writer.AddAttribute(&quot;classid&quot;, String.Format(&quot;clsid:{0}&quot;, Me.ClassId))            MyBase.AddAttributesToRender(writer)        End Sub </code></pre> <p><strong>step4. 新增 Params 屬性,描述 ActiveX 的參數集合</strong><br /> 定義 Params 屬性,型別為 TBActiveXParamCollection 類別,套用 EditorAttribute 設定 CollectionEditor 為集合編輯器。</p> <pre><code>        ''' &lt;summary&gt;        ''' ActiveX 控制項參數集合。        ''' &lt;/summary&gt;        &lt; _        Description(&quot;控制項參數集合。&quot;), _        PersistenceMode(PersistenceMode.InnerProperty), _        DesignerSerializationVisibility(DesignerSerializationVisibility.Content), _        Editor(GetType(CollectionEditor), GetType(UITypeEditor)) _        &gt; _        Public ReadOnly Property Params() As TBActiveXParamCollection            Get                If FParams Is Nothing Then                    FParams = New TBActiveXParamCollection()                End If                Return FParams            End Get        End Property </code></pre> <p>當編輯 Params 時,會使用的 CollectionEditor 集合編輯器。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay11ActiveX_166/image_thumb_2.png" alt="" /></p> <p><strong>step5. 輸出 ActiveX 參數</strong><br /> 覆寫 CreateChildControls 方法,在此方法依 Params 集合屬性定義依序來輸出 ActiveX 的參數集合。</p> <pre><code>        Private Sub AddParam(ByVal Name As String, ByVal Value As String)            Dim oParam As HtmlControls.HtmlGenericControl            oParam = New HtmlControls.HtmlGenericControl(&quot;param&quot;)            oParam.Attributes.Add(&quot;name&quot;, Name)            oParam.Attributes.Add(&quot;value&quot;, Value)            Me.Controls.Add(oParam)        End Sub        ''' &lt;summary&gt;        ''' 建立子控制項。        ''' &lt;/summary&gt;        Protected Overrides Sub CreateChildControls()            Dim oParam As TBActiveXParam            '加入 ActiveX 參數集合            For Each oParam In Me.Params                AddParam(oParam.Name, oParam.Value)            Next            MyBase.CreateChildControls()        End Sub </code></pre> <p><strong>三、執行程式</strong><br /> 上一篇我們使用 TBMediaPlayer 控制項來設定 Media Player,在此我們改用 TBActiveX 控制項來設定 Media Player,一樣可以呈現相同的結果。</p> <pre><code>        &lt;bee:TBActiveX ID=&quot;TBActiveX1&quot; runat=&quot;server&quot;            ClassId=&quot;6BF52A52-394A-11D3-B153-00C04F79FAA6&quot; Height=&quot;250px&quot; Width=&quot;250px&quot;&gt;            &lt;Params&gt;                &lt;bee:TBActiveXParam Name=&quot;URL&quot; Value=&quot;d:/Movie_01.wmv&quot; /&gt;                &lt;bee:TBActiveXParam Name=&quot;autoStart&quot; Value=&quot;true&quot; /&gt;            &lt;/Params&gt;        &lt;/bee:TBActiveX&gt; </code></pre> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/12/5659.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/12/5659.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-12 04:20:27</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day10] Media Player 控制項</title>                <link>https://ithelp.ithome.com.tw/articles/10012142?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10012142?sc=rss.iron</guid>                <description><![CDATA[<p>我們在前面幾篇文章中,已經簡要的對伺服器控制項做了基本介紹,接下來的幾篇文章中我們要開始實作伺服器控制項。在網頁上常使用 Media Player 來撥放影片,在 ASP.NET 中沒有現成的控...]]></description>                                    <content:encoded><![CDATA[<p>我們在前面幾篇文章中,已經簡要的對伺服器控制項做了基本介紹,接下來的幾篇文章中我們要開始實作伺服器控制項。在網頁上常使用 Media Player 來撥放影片,在 ASP.NET 中沒有現成的控制項來處理 Media Player,只能在 aspx 中加入 Media Player 相關的程式碼;本文將示範如何製作一個 Media Player 控制項,讓我們在 ASP.NET 中更方便的使用 Media Player。<br /> 程式碼下載:<a href="http://Files.Dotblogs.com.tw/jeff377%5C0810%5C2008101122230798.rar" target="_blank">ASP.NET Server Control - Day10.rar</a></p> <p><strong>一、Media Player 原始 HTML 碼</strong><br /> 在製作 Media Player 控制項之前,你需要先了解 Media Player 原本的 HTML 碼,控制項的作用就是想辨法把這些寫在 aspx 中的 HTML 碼交由控制項來輸出而已,以下為網頁中加入 Media Player 的 HTML 碼範例。</p> <pre><code>&lt;OBJECT id=&quot;VIDEO&quot; width=&quot;320&quot; height=&quot;240&quot; style=&quot;position:absolute; left:0;top:0;&quot; CLASSID=&quot;CLSID:6BF52A52-394A-11d3-B153-00C04F79FAA6&quot; type=&quot;application/x-oleobject&quot;&gt; &lt;PARAM NAME=&quot;URL&quot; VALUE=&quot;your file or url&quot;&gt; &lt;PARAM NAME=&quot;SendPlayStateChangeEvents&quot; VALUE=&quot;True&quot;&gt; &lt;PARAM NAME=&quot;AutoStart&quot; VALUE=&quot;True&quot;&gt; &lt;PARAM name=&quot;uiMode&quot; value=&quot;none&quot;&gt; &lt;PARAM name=&quot;PlayCount&quot; value=&quot;9999&quot;&gt; &lt;/OBJECT&gt; </code></pre> <p>在下面的網頁有 Media Player 相關參數說明。<br /> <a href="http://www.mioplanet.com/rsc/embed_mediaplayer.htm" target="_blank"><a href="http://www.mioplanet.com/rsc/embed%5C_mediaplayer.htm" target="_blank">http://www.mioplanet.com/rsc/embed\_mediaplayer.htm</a></a></p> <p><strong>二、實作 Media Player 控制項</strong><br /> <strong>step1.首先新增由 WebControl 繼承下來的 TBMediaPlayer 類別。</strong></p> <pre><code>    Public Class TBMediaPlayer        Inherits WebControl    End Class </code></pre> <p><strong>step2.覆寫 TagKey 屬性,傳回 object 的 Tag。</strong></p> <pre><code>        Protected Overrides ReadOnly Property TagKey() As System.Web.UI.HtmlTextWriterTag            Get                Return HtmlTextWriterTag.Object            End Get        End Property </code></pre> <p><strong>step3.輸出 HTML Tag 的 Attribute</strong><br /> 在 object Tag 中包含 style、classid、type 二個 Attribute,WebControl 本身會處理 style,所以我們只需覆寫 AddAttributesToRender 方法,處理 classid 及 type 二個 Attribute,記得覆寫 AddAttributesToRender 方法時最後要加入 MyBase.AddAttributesToRender(writer),才會執行父類別的 AddAttributesToRender 方法。</p> <pre><code>        ''' &lt;summary&gt;        ''' 覆寫 AddAttributesToRender 方法。        ''' &lt;/summary&gt;        Protected Overrides Sub AddAttributesToRender(ByVal writer As System.Web.UI.HtmlTextWriter)            '加入 MediaPlayer ActiveX 元件的 classid            writer.AddAttribute(&quot;classid&quot;, &quot;clsid:6BF52A52-394A-11D3-B153-00C04F79FAA6&quot;)            writer.AddAttribute(&quot;type&quot;, &quot;application/x-oleobject&quot;)            MyBase.AddAttributesToRender(writer)        End Sub </code></pre> <p><strong>step4.加入 Url 屬性</strong><br /> 加入指定播放檔案來源的 Url 屬性,其中套用 EditorAttribute 設定 UrlEditor,使用 Url 專用的編輯器來設定屬性。</p> <pre><code>        ''' &lt;summary&gt;        ''' 播放檔案來源。        ''' &lt;/summary&gt;        &lt; _        Description(&quot;播放檔案來源&quot;), _        Bindable(True), _        Category(&quot;Appearance&quot;), _        Editor(GetType(UrlEditor), GetType(UITypeEditor)), _        UrlProperty(), _        DefaultValue(&quot;&quot;) _        &gt; _        Public Property Url() As String            Get                Return FUrl            End Get            Set(ByVal value As String)                FUrl = value            End Set        End Property </code></pre> <p><strong>step5.輸出 Url 參數</strong><br /> 接下來覆寫 CreateChildControls 方法,輸出 Url 參數。</p> <pre><code>        ''' &lt;summary&gt;        ''' 加入參數。        ''' &lt;/summary&gt;        ''' &lt;param name=&quot;Name&quot;&gt;參數名稱。&lt;/param&gt;        ''' &lt;param name=&quot;Value&quot;&gt;參數值。&lt;/param&gt;        Private Sub AddParam(ByVal Name As String, ByVal Value As String)            Dim oParam As HtmlControls.HtmlGenericControl            oParam = New HtmlControls.HtmlGenericControl(&quot;param&quot;)            oParam.Attributes.Add(&quot;name&quot;, Name)            oParam.Attributes.Add(&quot;value&quot;, Value)            Me.Controls.Add(oParam)        End Sub        Protected Overrides Sub CreateChildControls()            '加入 Url 參數            AddParam(&quot;url&quot;, Me.ResolveClientUrl(Me.Url))            MyBase.CreateChildControls()        End Sub </code></pre> <p><strong>step6.輸出 Media Player 其他參數</strong><br /> 你可以將 Media Player 的參數設定皆使用相對應的屬性來設定,然後使用 step5 的方式來輸出所有設定的參數值。</p> <p><strong>三、Media Player 控制項程式碼</strong><br /> Media Player 控制項的完整程式碼如下,此控制項只加入 URL、AutoStart、UIMode 三個參數,你可以視需求情形將使用到的參數定義為屬性來做設定即可。<br /> 因為此處有字元數限制,完整的程式碼請參閱筆者部落格相同文章<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/11/5655.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/11/5655.aspx</a></p> <p><strong>四、執行程式</strong><br /> 把 TBMediaPlayer 控制項拖曳至頁面,設定好屬性後,執行程式就可以在頁面上看到呈現出來的 Media Player。</p> <pre><code>        &lt;bee:TBMediaPlayer ID=&quot;TBMediaPlayer1&quot; runat=&quot;server&quot; Height=&quot;250px&quot;            Width=&quot;250px&quot; Url=&quot;~/test.wmv&quot; /&gt; </code></pre> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/11/5655.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/11/5655.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-11 19:08:27</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day9] 控制項常用 Attribute 介紹(2)</title>                <link>https://ithelp.ithome.com.tw/articles/10012060?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10012060?sc=rss.iron</guid>                <description><![CDATA[<p>接續上篇 Attribute 的介紹,本文將再介紹一些伺服器控制項常用的 Attribute。<br /> <strong>六、ToolboxDataAttribute 類別</strong><...]]></description>                                    <content:encoded><![CDATA[<p>接續上篇 Attribute 的介紹,本文將再介紹一些伺服器控制項常用的 Attribute。<br /> <strong>六、ToolboxDataAttribute 類別</strong><br /> 作用:指定當自訂控制項從工具箱拖曳到頁面時,為此自訂控制項產生的預設標記。<br /> 當我們新增一個伺服器控制項,它就會預設在控制項類別套用 ToolboxDataAttribute,定義在控制項在 aspx 程式碼中的標記。</p> <pre><code>&lt;ToolboxData(&quot;&lt;{0}:TBButton runat=server &gt;&lt;/{0}:TBButton&gt;&quot;)&gt; _ Public Class TBButton    Inherits System.Web.UI.WebControls.Button End Class </code></pre> <p><strong>七、DefaultPropertyAttribute 類別</strong><br /> 作用:指定類別的預設屬性。<br /> 下面的範例中,MyTextbox 類別套用 DefaultPropertyAttribute,設定 Text 屬性為預設屬性。</p> <pre><code>&lt;DefaultProperty(&quot;Text&quot;)&gt; _ Public Class MyTextbox    Inherits WebControl    Public Property Text() As String        Get            Return CType(Me.ViewState(&quot;Text&quot;), String)        End Get        Set(ByVal value As String)            Me.ViewState(&quot;Text&quot;) = value        End Set    End Property End Class </code></pre> <p><strong>八、DefaultEventAttribute 類別</strong><br /> 作用:指定控制項的預設事件。<br /> 下面的範例中,MyTextbox 類別套用 DefaultEventAttribute,設定 TextChanged 為預設屬性。</p> <pre><code>&lt;DefaultEvent(&quot;TextChanged&quot;)&gt; _ Public Class MyTextbox    Inherits WebControl    ''' &lt;summary&gt;    ''' TextChanged 事件。    ''' &lt;/summary&gt;    Public Event TextChanged As EventHandler End Class </code></pre> <p>當設計階段在頁面上的 MyTextbox 控制項點二下時,就會產生預設事件的處理函式。</p> <pre><code>    Protected Sub MyTextbox1_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyTextbox3.TextChanged    End Sub </code></pre> <p><strong>九、LocalizableAttribute 類別</strong><br /> 作用:指定屬性是否應該當地語系化。<br /> 當屬性套用設為為 true 的 LocalizableAttribute 時,其屬性值會儲存在資源檔中,未來不需修改程式碼就可以將這些資源檔當地語系化。</p> <pre><code>        &lt;Localizable(True)&gt; _        Public Property Text() As String            Get                Return CType(Me.ViewState(&quot;Text&quot;), String)            End Get            Set(ByVal value As String)                Me.ViewState(&quot;Text&quot;) = value            End Set        End Property </code></pre> <p><strong>十、DesignerAttribute 類別</strong><br /> 作用:設定控制項在設計階段服務的類別。<br /> 指定一個設計階段的服務類別,來管理控制項在設計階段的行為,例如控制項的設計階段外觀、智慧標籤內容。例如下面範例的 TBGridView 控制項就定義了 TBGridViewDesigner 來實作設計階段的行為,未來的章節中也會介紹如何實作控制項的 Designer。</p> <pre><code>    &lt; Designer(GetType(TBGridViewDesigner)) &gt; _    Public Class TBGridView        Inherits GridView    End Class </code></pre> <p><strong>十一、EditorAttribute 類別</strong><br /> 作用:指定在屬性視窗中編輯屬性值的編輯器。<br /> 例如 ListBox 控制項的 Items 屬性,在屬性視窗編輯 Items 屬性時,會彈出 Items 集合屬性的編輯器。以下範例就是定義 Items 屬性的編輯器類別為 TBListItemsCollectionEditor,未來的章節中也會介紹如何實作屬性的 Editor。</p> <pre><code>        &lt;Editor(GetType(TBListItemsCollectionEditor), GetType(System.Drawing.Design.UITypeEditor))&gt; _        Public Overrides ReadOnly Property Items() As ListItemCollection </code></pre> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/10/5653.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/10/5653.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-10 11:27:02</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day8] 控制項常用 Attribute 介紹(1)</title>                <link>https://ithelp.ithome.com.tw/articles/10012016?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10012016?sc=rss.iron</guid>                <description><![CDATA[<p>Property 與 Attribute 二個術語一般都是翻譯成「屬性」,例如類別的屬性,是使用英文的 Property,而 HTML/XML 的元素屬性,使用的英文則是 Attribute。在...]]></description>                                    <content:encoded><![CDATA[<p>Property 與 Attribute 二個術語一般都是翻譯成「屬性」,例如類別的屬性,是使用英文的 Property,而 HTML/XML 的元素屬性,使用的英文則是 Attribute。在 .NET 中 Property 與 Attribute 的意義及用法不同,不過微軟線上文件也將它翻譯為「屬性」,這可能讓人發生困擾及誤解;筆者比較喜歡的方式就是 Property 是屬性,Attribute 就維持原文。在 .NET 中類別或屬性上可以套用上不同的 Attribute,使類別或屬性具有不同的特性,本文將介紹一些在伺服器控制項常使用到的 Attribute。<br /> <strong>一、DescriptionAttribute 類別</strong><br /> 作用:指定控制項或屬性的描述。<br /> 當 DescriptionAttribute 套用至控制項的類別時,設定的描述內容就會出現在工具箱中控制項的提示。</p> <pre><code>&lt;Description(&quot;按鈕控制項&quot;)&gt; _ Public Class TBButton    Inherits System.Web.UI.WebControls.Button End Class </code></pre> <p><img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay7Attribute_D3/image_thumb.png" alt="" /><br /> 當 DescriptionAttribute 套用至控制項的屬性時,在屬性視窗下面就會出現設定的屬性描述內容。</p> <pre><code>&lt;Description(&quot;詢問訊息&quot;)&gt; _ Public Property ConfirmMessage() As String </code></pre> <p><img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay7Attribute_D3/image_thumb_1.png" alt="" /></p> <p><strong>二、DefaultValueAttribute 類別</strong><br /> 作用:指定屬性的預設值。<br /> 使用 DefaultValueAttribute 設定屬性的預設值,若設定的屬性值與預設值相同時,此屬性值就不會出現在 aspx 程式碼中;筆者強烈建議屬性一定套用 DefaultValueAttribute,一來在 aspx 中的程式碼會比較少,另外一個重點是若因為某些因素需要修改屬性的預設值時,所有已開發頁面的控制項屬性值會一併變更;因為當初屬性值是預設值,沒有被寫入 aspx 程式碼中,所以一但控制項的屬性預設值變更,頁面已佈屬的控制項的屬性值就會全面適用。</p> <pre><code>        Private FConfirmMessage As String = String.Empty        &lt;DefaultValue(&quot;&quot;)&gt; _        Public Property ConfirmMessage() As String            Get                Return FConfirmMessage            End Get            Set(ByVal value As String)                FConfirmMessage = value            End Set        End Property </code></pre> <p><strong>三、CategoryAttribute 類別</strong><br /> 作用:指定屬性或事件的分類名稱,當屬性視窗設定為 [分類] 模式時,以群組方式來顯示屬性或事件。<br /> 例如設定 ConfirmMessage 屬性在 &quot;Behavior&quot; 分類,則 ConfirmMessage 屬性會被歸類到「行為」分類。</p> <pre><code>        &lt;Category(&quot;Behavior&quot;)&gt; _        Public Property ConfirmMessage() As String </code></pre> <p><img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay7Attribute_D3/image_thumb_2.png" alt="" /></p> <p><strong>四、BindableAttribute 類別</strong><br /> 作用:指定成員是否通常使用於繫結。<br /> 在資料繫結設定視窗中中,指定屬性是否預設會出現在屬性清單中。</p> <pre><code>&lt;Bindable(True)&gt; _ Public Property ConfirmMessage() As String </code></pre> <p><img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay7Attribute_D3/image_thumb_3.png" alt="" /></p> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/09/5647.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/09/5647.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-09 21:11:43</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day7] 設定工具箱的控制項圖示</title>                <link>https://ithelp.ithome.com.tw/articles/10011933?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10011933?sc=rss.iron</guid>                <description><![CDATA[<p>當我們把自訂控制項加入到工具箱中時,你會發現所有的控制項預設都是同樣的圖示,雖然控制項的圖示不變更不會有什麼影響,不過我們還是希望為自訂控制項加上合適的外衣,本文將介紹如何設定工具箱控制項圖示。...]]></description>                                    <content:encoded><![CDATA[<p>當我們把自訂控制項加入到工具箱中時,你會發現所有的控制項預設都是同樣的圖示,雖然控制項的圖示不變更不會有什麼影響,不過我們還是希望為自訂控制項加上合適的外衣,本文將介紹如何設定工具箱控制項圖示。<br /> <strong>一、加入控制項圖示檔</strong><br /> 首先要準備一個 16 x 16 的點陣圖(bmp),如下所示。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay6_BA88/image_thumb_1.png" alt="" /><br /> 將此圖檔加入至「伺服器控制項專案」中,可以如下圖所示,用一個特定的資料夾來儲存所有工具箱的圖示。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay6_BA88/image_thumb_2.png" alt="" /><br /> 然後在圖檔的屬性視窗中,設定建置動作為「內嵌資源」。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay6_BA88/image_thumb_3.png" alt="" /><br /> <strong>二、設定控制項的圖示</strong><br /> 首先定義一個 TBResource 類別,此為一個空的類別,其命名空間需與根命名空間相同,做為引用資源檔時使用。並加上控制項圖示的 WebResource 定義,因為根命名空間是 Bee.Web,而圖檔名稱為 TBButton.bmp,所以定義如下所示。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay6_BA88/image_thumb_5.png" alt="" /><br /> 假設我們要設定 TBButton 的工具箱圖示,則在 TBButton 類別套用 ToolboxBitmapAttribute 如下,其中第一個參數為 GetType(TBResource),第二個參數為圖檔檔名。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay6_BA88/image_thumb_7.png" alt="" /><br /> 重新編輯伺服器控制項專案,再將 Bee.Web.dll 組件的控制項加入工具箱中,你就可以發現 TBButton 的圖示已經變成設定的圖示了。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay6_BA88/image_thumb_8.png" alt="" /></p> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/08/5624.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/08/5624.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-08 22:26:13</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day6] 事件與 PostBack</title>                <link>https://ithelp.ithome.com.tw/articles/10011861?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10011861?sc=rss.iron</guid>                <description><![CDATA[<p>一般類別的事件撰寫很單純,不過在 ASP.NET 中與前端使用者互動產生的事件就不是那麼簡單了;在以往的 ASP 年代是沒有事件這回事的,而在 ASP.NET 把網頁程式撰寫真正的物件導向化,用...]]></description>                                    <content:encoded><![CDATA[<p>一般類別的事件撰寫很單純,不過在 ASP.NET 中與前端使用者互動產生的事件就不是那麼簡單了;在以往的 ASP 年代是沒有事件這回事的,而在 ASP.NET 把網頁程式撰寫真正的物件導向化,用戶端使用者的操作透過 PostBack 來產生相對應的事件。例如前端使用者按鈕後會引發伺服端 Button 的 Click 事件,當前端使用者輸入文字框完畢後離開後會引發伺服端 TextBox 的 TextChanged 事件,在本文中就是要說明如何透過 PostBack 來產生與使用者互動的事件。<br /> <strong>一、IPostBackEventHandler 與 IPostBackDataHandler 介面</strong><br /> 控制項要處理 PostBack 產生的事件,必須實作 IPostBackEventHandler 或 IPostBackDataHandler 介面,這二個介面有什麼差別呢?例如 Button 是實作IPostBackEventHandler 介面,由控制項產生的 PostBack 直接引發事件,如 Button 的 Click 事件。例如 TextBox 是實作 IPostBackDataHandler 介面,當頁面產生 PostBack 時,會傳用戶端輸入的新值給控制項,由控制項本身去決定是否引發該事件;以 TextBox 舉例來說,它會判斷新值與舊值不同時才會引發 TextChanged 事件。</p> <p><strong>二、IPostBackEventHandler 介面實作</strong><br /> 首先介紹 IPostBackEventHandler 介面,它包含 RaisePostBackEvent 方法,控制項在此方法中需處理要引發那些事件。我們繼承 WebControl 撰寫 MyButton 類別來說明 IPostBackEventHandler 介面,我們簡化控制項程式碼直接在 Render 方法輸入按鈕的 HTML 原始碼,並定義一個 Click 事件。實作 IPostBackEventHandler 介面的 RaisePostBackEvent 方法,在此方法中直接引發 Click 事件。</p> <pre><code>Public Class MyButton    Inherits WebControl    Implements IPostBackEventHandler    ''' &lt;summary&gt;    ''' Click 事件。    ''' &lt;/summary&gt;    Public Event Click As EventHandler    ''' &lt;summary&gt;    ''' 引發 Click 事件。    ''' &lt;/summary&gt;    Private Sub OnClick(ByVal e As EventArgs)        RaiseEvent Click(Me, e)    End Sub    Public Sub RaisePostBackEvent(ByVal eventArgument As String) Implements System.Web.UI.IPostBackEventHandler.RaisePostBackEvent        Dim e As New EventArgs()        OnClick(e) '引發 Click 事件    End Sub    ''' &lt;summary&gt;    ''' 覆寫 Render 方法。    ''' &lt;/summary&gt;    Protected Overrides Sub Render(ByVal writer As System.Web.UI.HtmlTextWriter)        Dim sHTML As String        sHTML = String.Format(&quot;&lt;INPUT TYPE=Submit Name={0} Value = '按鈕'/&gt;&quot;, Me.UniqueID)        writer.Write(sHTML)    End Sub End Class </code></pre> <p>在頁面上拖曳 MyButton 控制項,在屬性視窗找到 Click 事件,點二下產生 Click 事件處理函式,並撰寫測試程式碼如下。</p> <pre><code>    Protected Sub MyButton1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyButton1.Click        Me.Page.Response.Write(&quot;MyButton Click 事件&quot;)    End Sub </code></pre> <p>執行程式,當按下 MyButton 按鈕時,就會執行它的 RaisePostBackEvent 方法,進而引發 Click 事件,也就會執行 Click 事件處理函式的程式碼。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay5PostBack_143C0/image_2.png" alt="" /></p> <p><strong>三、IPostBackDataHandler 介面實作</strong><br /> IPostBackDataHandler 介面包含 LoadPostData 及 RaisePostDataChangedEvent 方法,當頁面 PostBack 時,會尋找具 IPostBackDataHandler 介面的控制項,先執行LoadPostData 方法,控制項在 LoadPostData 方法中會判斷用戶端傳入值決定是否引發事件,若 LoadPostData 傳回 True 表示要引發事件,此時會執行RaisePostDataChangedEvent 方法去決定要引發那些事件,反之傳回 False 表示不引發事件。</p> <p>我們繼承 WebControl 撰寫 MyText 類別來說明 IPostBackDataHandler 介面,我們簡化控制項程式碼直接在 Render 方法輸入文字框的 HTML 原始碼,並定義一個 TextChanged 事件。在 LoadPostData 方法中我們會判斷用戶端傳入值與目前的值是否不相同,不相同時才會傳回 True,此時才會執行 RaisePostDataChangedEvent 方法,進而引發 TextChanged 事件。</p> <pre><code>Public Class MyTextbox    Inherits WebControl    Implements IPostBackDataHandler    Public Property Text() As String        Get            Return CType(Me.ViewState(&quot;Text&quot;), String)        End Get        Set(ByVal value As String)            Me.ViewState(&quot;Text&quot;) = value        End Set    End Property    ''' &lt;summary&gt;    ''' TextChanged 事件。    ''' &lt;/summary&gt;    Public Event TextChanged As EventHandler    ''' &lt;summary&gt;    ''' 引發 TextChanged 事件。    ''' &lt;/summary&gt;    Private Sub OnTextChanged(ByVal e As EventArgs)        RaiseEvent TextChanged(Me, e)    End Sub    Public Function LoadPostData(ByVal postDataKey As String, ByVal postCollection As System.Collections.Specialized.NameValueCollection) As Boolean Implements System.Web.UI.IPostBackDataHandler.LoadPostData        '前端使用者輸入值        Dim oNewValue As String = postCollection.Item(postDataKey)        If oNewValue &lt;&gt; Me.Text Then            Me.Text = oNewValue            Return True        Else            Return False        End If    End Function    Public Sub RaisePostDataChangedEvent() Implements System.Web.UI.IPostBackDataHandler.RaisePostDataChangedEvent        Dim e As New EventArgs()        '引發 TextChanged 事件        OnTextChanged(e)    End Sub    ''' &lt;summary&gt;    ''' 覆寫 Render 方法。    ''' &lt;/summary&gt;    Protected Overrides Sub Render(ByVal writer As System.Web.UI.HtmlTextWriter)        Dim sHTML As String        sHTML = String.Format(&quot;&lt;INPUT Type=text Name={0} Value={1} &gt;&quot;, Me.UniqueID, Me.Text)        writer.Write(sHTML)    End Sub End Class </code></pre> <p>在頁面上拖曳 MyTextbox 及 MyButton 控制項,在 MyButton 的 Click 及 MyTextbox 的 TextChanged 事件撰寫如下測試程式碼。</p> <pre><code>    Protected Sub MyButton1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyButton1.Click        Me.Page.Response.Write(&quot;MyButton Click 事件&quot;)        Me.Page.Response.Write(&quot;&lt;br/&gt;&quot;)    End Sub    Protected Sub MyTextbox1_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyTextbox1.TextChanged        Me.Page.Response.Write(&quot;MyTextbox TextChanged 事件&quot;)        Me.Page.Response.Write(&quot;&lt;br/&gt;&quot;)    End Sub </code></pre> <p>執行程式,在 MyTextbox 輸入 &quot;A&quot;,再按下 MyButton,因為 MyTextbox 的值「空字串-&gt;&quot;A&quot;」,所以會引發 MyTextbox 的 TextChanged 事件及 MyButton 的 Click 事件。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay5PostBack_143C0/image_6.png" alt="" /></p> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格</p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-07 23:30:19</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day5] 屬性與 ViewState</title>                <link>https://ithelp.ithome.com.tw/articles/10011745?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10011745?sc=rss.iron</guid>                <description><![CDATA[<p>在 ASP.NET 中,控制項的屬性與 ViewState 有著密不可分的關係,透過 ViewState 才有辨法維護控制項的屬性值。在本文中將介紹屬性與 ViewState 的關係,並說明屬性...]]></description>                                    <content:encoded><![CDATA[<p>在 ASP.NET 中,控制項的屬性與 ViewState 有著密不可分的關係,透過 ViewState 才有辨法維護控制項的屬性值。在本文中將介紹屬性與 ViewState 的關係,並說明屬性如何存取 ViewState 是比較有效率的方式。<br /> 當你加入一個「ASP.NET 伺服器控制項」時,類別中預設會有一個 Text 屬性寫法的範例如下所示,屬性的讀寫都是直接存取 ViewState,這是一般常見的控制項屬性寫法。可是這種屬性的寫法是沒有效率的,因為 ViewState 的成員是 Object 型別,每次讀取屬性時都是由 ViewState 取出指定鍵值的成員再轉型為屬性的型別,寫入屬性的動作也是直接寫入 ViewState 中。</p> <pre><code>    Property Text() As String        Get            Dim s As String = CStr(ViewState(&quot;Text&quot;))            If s Is Nothing Then                Return String.Empty            Else                Return s            End If        End Get        Set(ByVal Value As String)            ViewState(&quot;Text&quot;) = Value        End Set    End Property </code></pre> <p>比較好的方式應該是讀取 ViewState 成員只做一次型別轉換的動作,而寫入 ViewState 的動作可以在 Render 前做批次寫入的動作即可。為了達到這樣的需求,我們可以覆寫 LoadViewState 及 SaveViewState 方法來處理屬性與 ViewState 的存取動作;當控制項初始化後會執行 LoadViewState 方法,來載入 ViewState 還原的控制項狀態,當控制項 Render 之前,會執行 SaveViewState 方法,將控制項的最終狀態存入 ViewState 中,也就是在此方法之後對控制項所做的任何變更都將會被忽略。</p> <p>我們改寫屬性的寫法,不直接用 ViewState 來存取屬性,而是改用「屬性區域變數」來存取屬性,在 LoadViewState 時載入 ViewState 到屬性區域變數,而 SaveViewState 時再將屬性區域變數寫入 ViewState 中。我們依此方式將 Text 屬性改寫如下。</p> <pre><code>    Private FText As String    Property Text() As String        Get            Return FText        End Get        Set(ByVal Value As String)            FText = Value        End Set    End Property    ''' &lt;summary&gt;    ''' 載入 ViewState 還原控制項狀態。    ''' &lt;/summary&gt;    Protected Overrides Sub LoadViewState(ByVal savedState As Object)        If Not (savedState Is Nothing) Then            ' Load State from the array of objects that was saved at vedViewState.            Dim myState As Object() = CType(savedState, Object())            If Not (myState(0) Is Nothing) Then                MyBase.LoadViewState(myState(0))            End If            If Not (myState(1) Is Nothing) Then                FText = CType(myState(1), String)            End If        End If    End Sub    ''' &lt;summary&gt;    ''' 將控制項狀態寫入 ViewState 中。    ''' &lt;/summary&gt;    Protected Overrides Function SaveViewState() As Object        Dim baseState As Object = MyBase.SaveViewState()        Dim myState(1) As Object        myState(0) = baseState        myState(1) = FText        Return myState    End Function </code></pre> <p>利用上述的方式,我們可以在 LoadViewState 批次載入所有屬性值,而在 SaveViewState 批次寫入屬性值,如此在讀取屬性就不用一直做型別轉換的動作以改善效率。</p> <p><strong>結語</strong><br /> 雖然屬性一般都是儲存於 ViewState 中,不過若是一些無關緊要的屬性或是完全不會執行階段就變更的屬性,可以考慮不需要將這些屬性儲存於 ViewState 中;因為 ViewState 是個兩面刃,ViewState 可以很輕易幫我們維護屬性值,不過相對的也增加了面頁的傳輸量,所以可以視實際情形來決定屬性是否要儲存於 ViewState 中。</p> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/07/5601.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/07/5601.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-06 21:17:20</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day4] 複合控制項</title>                <link>https://ithelp.ithome.com.tw/articles/10011633?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10011633?sc=rss.iron</guid>                <description><![CDATA[<p>複合控制項就是控制項可包含其他子控制項,複合控制項繼承至 System.Web.UI.WebControls.CompositeControl,例如 Login 及 Wizard 等控制項就是屬...]]></description>                                    <content:encoded><![CDATA[<p>複合控制項就是控制項可包含其他子控制項,複合控制項繼承至 System.Web.UI.WebControls.CompositeControl,例如 Login 及 Wizard 等控制項就是屬於複合控制項。我們常在網頁上常看到一種輸入日期的方式是年月日三個下拉清單,本文將利用複合控制項來實作這個年月日下拉清單控制項,示範如何實作複合控制項。<br /> <strong>一、CompositeControl 類別的特性</strong><br /> CompositeControl 類別是抽象類別,它會實作 INamingContaner 介面,INamingContaner 介面會在子控制項的 ClinetID 加上父控制項的 ID,以確保頁面上控制項的 ClientID 是唯一的。繼承 CompositeControl 類別一般都是覆寫 CreateChildControls 方法,在此方法中將建立子控制項並加入 Controls 集合屬性中;當存取其子控制項時,若子控制項未建立,會執行 CreateChildControls 方法,以會確保所有子控制項皆已在存取 ControlCollection 之前建立。<br /> <strong>二、日期下拉清單輸入器</strong><br /> 我們繼承 CompositeControl 類別,命名為 TBDropDownDate。這個控制項會包含年月日三個下拉清單(DropDownList),所以我們只要在 CreateChildControls 方法中依序建立年月日的 DropDownList 子控制項,並加入 Controls 集合屬性中即可。</p> <pre><code>''' &lt;summary&gt; ''' 日期下拉清單輸入器。 ''' &lt;/summary&gt; &lt; _ ToolboxData(&quot;&lt;{0}:TBDropDownDate runat=server&gt;&lt;/{0}:TBDropDownDate&gt;&quot;) _ &gt; _ Public Class TBDropDownDate    Inherits System.Web.UI.WebControls.CompositeControl    Protected Overrides Sub CreateChildControls()        Dim oYear As DropDownList        Dim oMonth As DropDownList        Dim oDay As DropDownList        Dim N1 As Integer        '年下拉清單區間為 1950-2010 (年區間可以用屬性來設定)        oYear = New DropDownList        oYear.ID = &quot;Year&quot;        For N1 = 1950 To 2010            oYear.Items.Add(N1.ToString)        Next        Me.Controls.Add(oYear) '加入子控制項        Me.Controls.Add(New LiteralControl(&quot;年&quot;))        '月下拉清單區間為 1-12        oMonth = New DropDownList        oMonth.ID = &quot;Month&quot;        For N1 = 1 To 12            oMonth.Items.Add(N1.ToString)        Next        Me.Controls.Add(oMonth) '加入子控制項        Me.Controls.Add(New LiteralControl(&quot;月&quot;))        '日下拉清單區為為 1-31        oDay = New DropDownList        oDay.ID = &quot;Day&quot;        For N1 = 1 To 12            oDay.Items.Add(N1.ToString)        Next        Me.Controls.Add(oDay) '加入子控制項        Me.Controls.Add(New LiteralControl(&quot;日&quot;))    End Sub End Class </code></pre> <p>在設定階段拖曳 TBDropDownDate 到頁面上,就可以看到我們在 CreateChildControls 方法中所加入的子控制項。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/ASP.NETDay4_9C76/image_2.png" alt="" /></p> <p>執行程式,檢視它的 HTML 原始碼,會發現年月日的子控制項的 ClientID 都會在原 ID 前加上父控制項的 ID,這樣命名規則可以確保所有的控制項的 ClinetID 都是唯一值。</p> <pre><code>&lt;span id=&quot;TBDropDownDate1&quot;&gt; &lt;select name=&quot;TBDropDownDate1$Year&quot; id=&quot;TBDropDownDate1_Year&quot;&gt; ....省略 &lt;select name=&quot;TBDropDownDate1$Month&quot; id=&quot;TBDropDownDate1_Month&quot;&gt; ....省略 &lt;select name=&quot;TBDropDownDate1$Day&quot; id=&quot;TBDropDownDate1_Day&quot;&gt; &lt;/span&gt; </code></pre> <p><strong>三、結語</strong><br /> 我們已經看過三類伺服器控制項的簡單案例,不過這三個案例都只是簡單說明控制項 UI 的部分,一個完整的控制項需具備屬性、方法、事件、設計階段支援...等,在後面的文章中,我們將陸續針對這些部分做詳細的介紹。</p> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/05/5583.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/05/5583.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-05 22:22:25</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day3] 擴展現有伺服器控制項功能</title>                <link>https://ithelp.ithome.com.tw/articles/10011562?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10011562?sc=rss.iron</guid>                <description><![CDATA[<p>相對於由無到有開發控制項,繼承現有現伺服器控制項是比較簡單且實用的方式;若希望在現有的控制項增加某些屬性或功能,直接繼承該控制項下來擴展功能是最快的方式,例如「按下 Button 會彈出詢問訊息...]]></description>                                    <content:encoded><![CDATA[<p>相對於由無到有開發控制項,繼承現有現伺服器控制項是比較簡單且實用的方式;若希望在現有的控制項增加某些屬性或功能,直接繼承該控制項下來擴展功能是最快的方式,例如「按下 Button 會彈出詢問訊息」、「TextBox 設為 ReadOnly 時,可以取得前端傳回的 Text 屬性」這類需求,都可以直接繼承原控制項下來,加上我們需要的功能即可。以下我們就以一個簡單的案例來說明如何繼承現有伺服器下來擴展功能。<br /> <strong>一、擴展 Button 控制項:按鈕加上詢問訊息</strong><br /> 按下按鈕執行某些動作前,有時會詢問使用者是否執行該動作;例如按下刪除鈕,會詢問使用者是否確定要執行刪除的動作。當然這只需要簡單的 JavaScript 就可以完成,不過相對於 .NET 的程式語言,JavaScript 是非常不易維護的用戶端指令碼,如果能讓開發人員完全用不到 JavaScript,那何樂不為呢? 那就由 Button 控制項本身提供加上詢問訊息的功能就可以,相關的 JavaScript 由控制項去處理。<br /> 一般要在 Button 加上詢問訊息,只要在 OnClientClick 屬性設定如下的 JavaScript 即可。我們的目的只是讓開發人員連設定 OnClientClick 屬性的 JavaScript 都省略,直接設定要詢問的訊息即可,接下來我們就要開始實作這個控制項。</p> <pre><code>&lt;asp:Button ID=&quot;Button1&quot; runat=&quot;server&quot; Text=&quot;Button&quot;  OnClientClick=&quot;if (confirm('確定執行嗎?')==false) {return false;}&quot; /&gt;   </code></pre> <p>在 Bee.Web 專案中,加入「ASP.NET 伺服器控制項」,此控制項繼承 Button 下來命名為 TBButton (命名空間為 Bee.Web.WebControls)。在 TBButton 類別中加入 ConfirmMessage 屬性,用來設定詢問訊息的內容。然後在 Render 方法將詢問詢息的 JavaScript 設定到 OnClientClick 屬性即可。</p> <pre><code>Namespace WebControls    &lt; _    Description(&quot;按鈕控制項&quot;), _    ToolboxData(&quot;&lt;{0}:TBButton runat=server&gt;&lt;/{0}:TBButton&gt;&quot;) _    &gt; _    Public Class TBButton        Inherits System.Web.UI.WebControls.Button        &lt;Description(&quot;詢問訊息&quot;)&gt; _        Public Property ConfirmMessage() As String            Get                Dim sConfirmMessage As String                sConfirmMessage = CStr(ViewState(&quot;ConfirmMessage&quot;))                If sConfirmMessage Is Nothing Then                    Return String.Empty                Else                    Return sConfirmMessage                End If            End Get            Set(ByVal value As String)                ViewState(&quot;ConfirmMessage&quot;) = value            End Set        End Property        ''' &lt;summary&gt;        ''' 覆寫 Render 方法。        ''' &lt;/summary&gt;        Protected Overrides Sub Render(ByVal writer As System.Web.UI.HtmlTextWriter)            Dim sScript As String            Dim sConfirm As String            '若有設定 ConfirmMessage 屬性,則在 OnClientClick 加入詢問訊息的 JavaScript            If Me.ConfirmMessage &lt;&gt; String.Empty Then                sScript = Me.OnClientClick                '詢問訊息的 JavaScript                sConfirm = String.Format(&quot;if (confirm('{0}')==false) {{return false;}}&quot;, Me.ConfirmMessage)                If sScript = String.Empty Then                    Me.OnClientClick = sConfirm                Else                    Me.OnClientClick = sConfirm &amp; sScript                End If            End If            MyBase.Render(writer)        End Sub    End Class End Namespace </code></pre> <p>將 TBButton 拖曳到測試頁面,設定 ConfirmMessage 屬性。</p> <pre><code>&lt;bee:TBButton ID=&quot;TBButton1&quot; runat=&quot;server&quot; ConfirmMessage=&quot;確定刪除此筆資料嗎?&quot; Text=&quot;刪除&quot; /&gt; </code></pre> <p>執行結果如下。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/8cea6e0221af_B473/image_2.png" alt="" /></p> <p><strong>二、結語</strong><br /> 筆者在開發 ASP.NET 的應用程式過程中,通常會習慣把所有現有控制項繼承下來,無論目前需不需要擴展控制項功能。這種方式對於開發大型系統是相當有幫助的,因為無法預期在系統開發的過程中會不會因為某些狀況,而臨時需要擴展控制項的功能,所以就先全部繼承下來以備不時之需,也為未來保留修改的彈性。</p> <p><strong>三、相關連結</strong><br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/03/17/1748.aspx" target="_blank">擴展 CommandField 類別 - 刪除提示訊息</a><br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/03/17/1697.aspx" target="_blank">按鈕加上詢問訊息</a></p> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/04/5578.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/04/5578.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-04 21:24:49</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day2] 建立第一個伺服器控制項</title>                <link>https://ithelp.ithome.com.tw/articles/10011523?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10011523?sc=rss.iron</guid>                <description><![CDATA[<p>上一篇中已經建立「ASP.NET 伺服器控制項」專案,接下來我們將學習來撰寫第一個伺服器控制項。<br /> 撰寫伺服器控制項大致分為下列三種方式<br /> 1.由無到有建立全新的控制項,一般...]]></description>                                    <content:encoded><![CDATA[<p>上一篇中已經建立「ASP.NET 伺服器控制項」專案,接下來我們將學習來撰寫第一個伺服器控制項。<br /> 撰寫伺服器控制項大致分為下列三種方式<br /> 1.由無到有建立全新的控制項,一般會繼承至 System.Web.UI.Control 或 System.Web.UI.WebControls.WebControl 類別。<br /> 2.繼承現有控制項,擴展原有控制項的功能,如繼承原有 TextBox 來擴展功能。<br /> 3.複合式控制項,將多個現有的控制項組合成為一個新的控制項,例如 TextBox 右邊加個 Button 整合成一個控制項,一般會繼承至 System.Web.UI.WebControls.CompositeControl 類別。</p> <p>本文將先介紹第1種方式,由無到有來建立控制項,後面的文章中會陸續介紹第2、3種方式的控制項。要建立全新的控制項會繼承至 Control 或 WebControl,沒有 UI 的控制項可由 Control 繼承下來 (如 SqlDataSource),具 UI 的控制項會由 WebControl 繼承下來。接下來的範例中,我們將繼承 WebControl 來建立第一個 MyTextBox 控制項。</p> <p><strong>一、新增 MyTextBox 控制項</strong><br /> 在 Bee.Web 專案按右鍵選單,執行「加入\新增項目」,選擇「ASP.NET 伺服器控制項」,在名稱文字框中輸入 MyTextbox,按下「確定」鈕,就會在專案中加入 MyTextbox 控制項類別。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/0e8fe1ad2977_14385/image_thumb.png" alt="" /><br /> 新加入的控制項預設有一個 Text 屬性,以及覆寫 Render 方法。Render 方法是「將控制項呈現在指定的 HTML 寫入器中」,簡單的說就是在 Render 方法會將控制項對應的 HTML 碼輸出,用來呈現在用戶端的瀏覽器上。假設我們要撰寫一個網頁上的文字框,那就先去看一下文字框在網頁中對應的 HTML 碼,然後在 Render 方法中想辨法輸出這些 HTML 碼即可。</p> <p><strong>二、輸出控制項的 HTML 碼</strong><br /> 你可以使用 FrontPage 之類的 HTML 編輯器,先編輯出控制項的呈現方式,進而去觀查它的 HTML 碼,再回頭去思考如何去撰寫這個伺服器控制項。假設 MyTextbox 控制項包含一個文字框及一個按鈕,那最終輸出的 HTML 碼應該如下。</p> <pre><code>&lt;input id=&quot;Text1&quot; type=&quot;text&quot; /&gt; &lt;input id=&quot;Button1&quot; type=&quot;button&quot; value=&quot;button&quot; /&gt; </code></pre> <p>我們在 MyTextbox 的 RenderContents 方法中輸出上述的 HTML 碼。</p> <pre><code>    Protected Overrides Sub RenderContents(ByVal writer As HtmlTextWriter)        Dim sHTML As String        sHTML = &quot;&lt;input id=&quot;&quot;Text1&quot;&quot; type=&quot;&quot;text&quot;&quot; /&gt;&quot; &amp; _                &quot;&lt;input id=&quot;&quot;Button1&quot;&quot; type=&quot;&quot;button&quot;&quot; value=&quot;&quot;button&quot;&quot; /&gt;&quot;        writer.Write(sHTML)    End Sub </code></pre> <p>建置控制項專案,然後拖曳 MyTextbox 在測試頁面上,設計階段就會呈現出我們期望的結果。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/0e8fe1ad2977_14385/image_4.png" alt="" /></p> <p>執行程式,在瀏覽器看一下 MyTextbox 控制項輸出的結果,是不是跟我們預期的一樣呢。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/0e8fe1ad2977_14385/image_6.png" alt="" /></p> <p><strong>三、屬性套用到控制項 HTML 碼</strong><br /> 控制項不可能單純這樣輸出 HTML 碼而已,控制項的相關屬性設定,一般都影響到輸出的 HTML 碼。假設 MyTextbox 有 Text 及 ButtonText 二個屬性,分別對應到 文字框的內容及按鈕的文字,MyTextbox 本來就有 Text 屬性,依像畫蘆葫新增 ButtonText 屬性。</p> <pre><code>    &lt; _    Bindable(True), _    Category(&quot;Appearance&quot;), _    DefaultValue(&quot;&quot;), _    Localizable(True)&gt; _    Property ButtonText() As String        Get            Dim s As String = CStr(ViewState(&quot;ButtonText&quot;))            If s Is Nothing Then                Return String.Empty            Else                Return s            End If        End Get        Set(ByVal Value As String)            ViewState(&quot;ButtonText&quot;) = Value        End Set    End Property </code></pre> <p>RenderContents 方法改寫如下。</p> <pre><code>    Protected Overrides Sub RenderContents(ByVal writer As HtmlTextWriter)        Dim sHTML As String        sHTML = &quot;&lt;input id=&quot;&quot;Text1&quot;&quot; type=&quot;&quot;text&quot;&quot; value=&quot;&quot;{0}&quot;&quot;/&gt;&quot; &amp; _                &quot;&lt;input id=&quot;&quot;Button1&quot;&quot; type=&quot;&quot;button&quot;&quot; value=&quot;&quot;{1}&quot;&quot; /&gt;&quot;        sHTML = String.Format(sHTML, Me.Text, Me.ButtonText)        writer.Write(sHTML)    End Sub </code></pre> <p>重新建置控制項專案,在頁面上測試 MyTextbox 的 Text 及 ButtonText 屬性。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/0e8fe1ad2977_14385/image_8.png" alt="" /></p> <p><strong>四、使 ClientID (HTML 原始碼控制項的 ID) 是唯一值</strong><br /> 在頁面上放置二個 MyTextbox 控制項,執行程式,在瀏覽器中檢查 MyTextbox 的 HTML 原始碼。你會發現 MyTextbox 會以一個 span 包住控制項的內容,而每個控制項的輸出的 ClientID 是唯一的。不過 MyTextbox 內含的文字框及按鈕卻會重覆,所以一般子控制項的 ClientID 會在前面包含父控制項的 ID。</p> <pre><code>&lt;span id=&quot;MyTextbox1&quot;&gt; &lt;input id=&quot;Text1&quot; type=&quot;text&quot; value=&quot;這是文字&quot;/&gt; &lt;input id=&quot;Button1&quot; type=&quot;button&quot; value=&quot;這是按鈕&quot; /&gt; &lt;/span&gt; &lt;br /&gt; &lt;span id=&quot;MyTextbox2&quot;&gt; &lt;input id=&quot;Text1&quot; type=&quot;text&quot; value=&quot;這是文字&quot;/&gt; &lt;input id=&quot;Button1&quot; type=&quot;button&quot; value=&quot;這是按鈕&quot; /&gt; &lt;/span&gt; </code></pre> <p>所以我們再次修改 RenderContents 方法的程式碼</p> <pre><code>    Protected Overrides Sub RenderContents(ByVal writer As HtmlTextWriter)        Dim sHTML As String        sHTML = &quot;&lt;input id=&quot;&quot;{0}_Text&quot;&quot; type=&quot;&quot;text&quot;&quot; value=&quot;&quot;{1}&quot;&quot;/&gt;&quot; &amp; _                &quot;&lt;input id=&quot;&quot;{0}_Button&quot;&quot; type=&quot;&quot;button&quot;&quot; value=&quot;&quot;{2}&quot;&quot; /&gt;&quot;        sHTML = String.Format(sHTML, Me.ID, Me.Text, Me.ButtonText)        writer.Write(sHTML)    End Sub </code></pre> <p>執行程式,再次檢視 HTML 原始碼,所有的 ClinetID 都會是唯一的。</p> <pre><code>&lt;span id=&quot;MyTextbox1&quot;&gt; &lt;input id=&quot;MyTextbox1_Text&quot; type=&quot;text&quot; value=&quot;這是文字&quot;/&gt; &lt;input id=&quot;MyTextbox1_Button&quot; type=&quot;button&quot; value=&quot;這是按鈕&quot; /&gt; &lt;/span&gt; &lt;br /&gt; &lt;span id=&quot;MyTextbox2&quot;&gt; &lt;input id=&quot;MyTextbox2_Text&quot; type=&quot;text&quot; value=&quot;這是文字&quot;/&gt; &lt;input id=&quot;MyTextbox2_Button&quot; type=&quot;button&quot; value=&quot;這是按鈕&quot; /&gt; &lt;/span&gt; </code></pre> <p><strong>五、控制項前置詞</strong><br /> 自訂控制項的預設前置詞是 cc1,不過這是可以修改的,在專案中的 AssemblyInfo.vb 檔案中,加入如下定義即可。詳細的作法請參考筆者部落格中的「<a href="http://www.dotblogs.com.tw/jeff377/archive/2008/03/17/1744.aspx" target="_blank">自訂伺服器控制項前置詞</a>」一本有詳細介紹,在此不再累述。</p> <pre><code>'設定控制項的標記前置詞 &lt;Assembly: TagPrefix(&quot;Bee.Web.WebControls&quot;, &quot;bee&quot;)&gt; </code></pre> <p><strong>六、結語</strong><br /> 本文中是用土法鍊鋼的方法在撰寫伺服器控制項,一般在實作控制項時會有更好的方式、更易維護的寫法,後續的文章中會陸續介紹相關作法。</p> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/03/5573.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/03/5573.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-03 23:51:35</pubDate>                                                                                                                                            </item>                    <item>                <title>[ASP.NET 控制項實作 Day1] 建立 ASP.NET 伺服器控制項專案</title>                <link>https://ithelp.ithome.com.tw/articles/10011408?sc=rss.iron</link>                <guid isPermaLink="true">https://ithelp.ithome.com.tw/articles/10011408?sc=rss.iron</guid>                <description><![CDATA[<p>在 ASP.NET 開發環境中,我們常使用現成的控制項直接拖曳至頁面中使用,有沒有想過我們也可以開發自用的控制項呢?本文將本文以 VS2008 為開發工具,VB.NET 為開發程式語言,來說明如...]]></description>                                    <content:encoded><![CDATA[<p>在 ASP.NET 開發環境中,我們常使用現成的控制項直接拖曳至頁面中使用,有沒有想過我們也可以開發自用的控制項呢?本文將本文以 VS2008 為開發工具,VB.NET 為開發程式語言,來說明如何建立「伺服器控制項」專案,以及如何測試開發階段的的伺服器控制項。<br /> <strong>一、建立「ASP.NET 伺服器控制項」專案</strong><br /> 首先執行功能表「檔案\新增專案」,在專案類型中選擇 Visual Basic -&gt; Web,選取「ASP.NET 伺服器控制項」範本,在名稱文字框中輸入專案名稱,也就是組件的檔案名稱,我們輸入 Bee.Web 為專案名稱,組件檔案為 Bee.Web.dll,按下「確定」鈕即會建立新的「ASP.NET 伺服器控制項」專案。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/166fb54653d6_12877/image_thumb_1.png" alt="" /><br /> 在新建立「ASP.NET 伺服器控制項」專案中,會預設加入一個伺服器控制項類別(ServerControl1.vb),這個伺服器控制項已經事件幫我們加入一些控制項的程式碼。目前暫不做任何修改,直接使用此控制項來做測試說明。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/166fb54653d6_12877/image_thumb_2.png" alt="" /><br /> 接下來執行功能表「專案\Bee.Web 屬性」,設定此組件的根命名空間,一般慣用的根命名空間都會與組件名稱相同,以方便加入參考時可以快速找到相關組件。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/166fb54653d6_12877/image_thumb_10.png" alt="" /><br /> 我們先儲存這個「ASP.NET 伺服器控制項」專案,指定儲存位置,按下「儲存」鈕。整個專案相關檔案,會儲存在以專案名稱的資料夾中。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/166fb54653d6_12877/image_thumb_3.png" alt="" /></p> <p><strong>二、加入測試網站</strong><br /> 不要關閉目前「ASP.NET 伺服器控制項」專案,執行功能表「檔案\加入\新網站」,選擇「ASP.NET 網站」,會在方案中加入一個網站,來測試開發階段的伺服器控制項使用。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/166fb54653d6_12877/image_thumb_5.png" alt="" /><br /> 在測試網站加入參考,選擇「專案」頁籤,此頁籤中會列出該方案中其他可加入參考的專案,選取 Bee.Web 專案,按下「確定」鈕。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/166fb54653d6_12877/image_thumb_6.png" alt="" /><br /> 先在 Bee.Web 專案中執行「建置」動作,然後切換到測試網站的頁面設計,工具箱中就會出現 ServerControl1 伺服器控制項。這個控制項就可以直接拖曳至頁面中使用,這個控制項只是單純 Render 出 Text 屬性值,你可以在控制項屬性視窗中,更改 Text 屬性值為 &quot;測試文字&quot;,就會看到這個控制項顯示 &quot;測試文字&quot;。將測試網站設為啟動專案,按下「F5」執行程式,就會看到該控制在執行階段的結果。<br /> <img src="http://files.dotblogs.com.tw/jeff377/0810/166fb54653d6_12877/image_thumb_12.png" alt="" /></p> <p>備註:本文同步發佈於筆者「ASP.NET 魔法學院」部落格<br /> <a href="http://www.dotblogs.com.tw/jeff377/archive/2008/10/02/5562.aspx" target="_blank">http://www.dotblogs.com.tw/jeff377/archive/2008/10/02/5562.aspx</a></p> ]]></content:encoded>                                <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jeff377</dc:creator>                <pubDate>2008-10-02 23:16:29</pubDate>                                                                                                                                            </item>            </channel> </rss>