在七月中的時候曾經寫過一篇AWStats 重新分析特定時段 log 的方法,當時是第一次遇到 AWStats 報表執行失敗的問題,很不幸的後來又陸續遇到幾次需要重跑 AWStats 報表的需求。原本是參考Neo's Blog - awstats 加入/重新計算分析某時段的方法,老老實實的手動去修改 AWStats 統計資料檔中的「LastLine」、「LastTime」、「LastUpdate」三個參數,但由於我要計算的報表多達 26 個,連續 26 次用 vi 去編輯統計資料檔中的三行資料不但累人,而且很容易出錯!經過一番摸索,終於利用三個指令就把 26 個檔案中的資料一次修改完成!
其實這次用到的技巧跟前陣子分享的[Shell Script] 批次修改使用者的密碼有效期限 - V2差不多,主要是利用 xargs -i 來濃縮大量、只有一個參數不同的指令。這次要用到的指令範例如下:
批次將 26 個 AWStats 統計資料檔的 LastTime 修改為「LastTime 20100630000000」:
find /path/to/awstats/statistic/files -name awstats122010* | xargs -i sed -i '/^LastTime/c LastTime 20100630000000' {}
首先利用 find 指令找出要修改的月份的所有統計資料檔(-name 參數支援 Regular Expression),此例是要找出2010年12月的檔案。因為 find 的結果會是完整的檔案路徑(e.g., /etc/fstab),因此可作為 sed 指令的參數,用以指定要修改的檔案。
下一步是利用 sed -i 指令來編輯檔案,在此也支援 Regular Expression,因此「^LastTime」就是以「LastTime」開頭的那一行文字,這裡的「^」很重要,表示這一行文字的開頭第一個字就是「L」,若去掉「^」,則會一併編輯到「#LastTime」的註解文字。
找到 LastTime 開頭的那行文字以後,「c」表示整行取代,因此「c」後面接的就是我們想要這行變成怎樣的最後內容:「LastTime 20100630000000」(不一定要指定成2010年6月30號,只要日期比今天更早就可以了)。
最後最重要的就是「{}」了,xargs -i 會把 find pipe 過來的完整檔案路徑代入「{}」中(一次代入一個檔案),因此就看 find 指令可以找到多少檔案(以我的例子來說是 26 個),這行指令就可以一次修改多少檔案中的「LastTime」的內容了!
接下來要編輯「LastLine」和「LastUpdate」的內容就很簡單了:
find /var/lib/awstats/ -name awstats122010* | xargs -i sed -i '/^LastLine/c LastLine 20100630000000 0 0 0' {}
find /var/lib/awstats/ -name awstats122010* | xargs -i sed -i '/^LastUpdate/c LastUpdate 20100630000000 0 0 0 0 0' {}
學會 xargs -i 以後真的是太好用了,很快就越用越上手,想忘也忘不掉啦!
2010年12月22日
2010年12月18日
[NPOI] Excel 上傳用 User Control
上篇坎尼寫了 [NPOI] 輕鬆地將 GridView 匯出成試算表
坎尼的朋友就問:那有沒有上傳的?
當然有,要什麼有什麼 :D
接著建立 User 可以委派的事件:ImportToDB
確認按鈕的 Click 事件則去呼叫 User 的委派事件
建立上傳資料屬性,以利使用者進行後續的資料匯入動作
由於 PostBack 之後不會記住屬性的資料
所以用 ViewState 把資料記住,並在 Page_Load 事件檢查
但要注意的一點是,1.2.3 版本的 NPOI 在以下紅框處需進行轉型的動作
另外再加入一個 GridView,用來確認資料是否真的上傳到 server
動作只是很簡單地判斷 UserControl 的 DataTable 有沒有資料
有的話就把資料繫結到畫面上的 GridView 之中
點下確認之後,使用者自行定義的事件會把資料繫結到另一個 GridView
大功告成!!!
所以還沒用此版本的讀者記得去 codeplex 下載新版本
另外上傳的 Excel 檔案需為 97-2003 的格式
若是用 office 2007 或是 office 2010 的朋友,記得改存為舊格式
此次的範例下載 (含 npoi library)
參考資料:
坎尼的朋友就問:那有沒有上傳的?
當然有,要什麼有什麼 :D
I. 實作過程
首先,建立一個 WebUserControl
加入一個 FileUpload、兩個 Button、一個 GridView
- FileUpload 及上傳按鈕用來進行檔案上傳的動作
- 確認按鈕則是給使用者自行定義事件
- GridView 用來顯示上傳完成的檔案
建立委派事件
接著建立 User 可以委派的事件:ImportToDB 確認按鈕的 Click 事件則去呼叫 User 的委派事件
建立屬性
建立上傳資料屬性,以利使用者進行後續的資料匯入動作 由於 PostBack 之後不會記住屬性的資料
所以用 ViewState 把資料記住,並在 Page_Load 事件檢查
上傳按鈕事件
- 第一個紅框為呼叫 NPOI 上傳事件
把 Excel 內容傳到 DataTable 之中並回傳 - 第二個紅框為將資料存到 ViewState 之中
另外把確認按鈕改成可作用 - 第三個紅框則是把資料顯示到畫面上
NPOI 匯入事件
這邊的程式碼引用 hunterpo 大所寫的 利用 NPOI Library 合併多個 Excel 檔但要注意的一點是,1.2.3 版本的 NPOI 在以下紅框處需進行轉型的動作
II. 使用方法
建立新的頁面,把 User Control 放到畫面上另外再加入一個 GridView,用來確認資料是否真的上傳到 server
自行撰寫事件
這邊可以看到坎尼自己定義了新的事件:ImportToDB動作只是很簡單地判斷 UserControl 的 DataTable 有沒有資料
有的話就把資料繫結到畫面上的 GridView 之中
執行畫面
上傳資料,成功的話 UserControl 會將資料顯示出來III. 小結
本次範例是用 NPOI 1.2.3 寫的 (上一篇是用舊版)所以還沒用此版本的讀者記得去 codeplex 下載新版本
另外上傳的 Excel 檔案需為 97-2003 的格式
若是用 office 2007 或是 office 2010 的朋友,記得改存為舊格式
此次的範例下載 (含 npoi library)
參考資料:
2010年12月13日
[Shell Script] 批次修改使用者的密碼有效期限 - V2
之前寫過一篇[Shell Script] 批次修改使用者的密碼有效期限 - V1,當時是自己寫了一個有點囉唆的 shell script 來處理這樣的需求,最麻煩的問題是「如何判斷哪些帳號是使用者帳號」,過濾 /etc/passwd 檔案有以下困難:
- 在 RHEL 系統中,通常使用者帳號的 uid 是從 500 開始,但是在 Solaris 系統中是從 100 開始。
- 上次寫的:加強過濾 /etc/passwd 檔案時使用的 regular expression,雖然目前實務上接觸到的主機還不至於帳號多到 uid > 600 或者更高,但可以當作一個練習 regular expression 的機會。<--相當麻煩
最近又要去修改使用者密碼的到期日(每三個月就要做一次),因為不想再跑這個很麻煩的 script,因此研究出一個更方便的指令,主要是以 echo -e 搭配 xargs 來完成。
要設定「密碼有效期為90天」以及「密碼到期前30天警告」可使用以下指令:
echo -e "account1\naccount2" | xargs -i chage -M 90 -W 30 {}
echo 加上 -e 參數後會讓兩個帳號間的「\n」換行字元生效(不加 -e 的話 xargs 會收到「account1\naccount2」這個完整的字串),再搭配 xargs -i 的置換效果({}會被置換成透過 pipeline 接收的字元),上面一行指令相當於下面兩行指令:
chage -M 90 -W 30 account1
chage -M 90 -W 30 account2
這樣的寫法的彈性在於,要 echo 哪些帳號出來完全可以自由控制,不用考慮不同系統中 uid 的起始數字不同,也不用考慮例外狀況。
在我管的系統中每個 OS 中的帳號都類似(大概是5~8個),透過 xargs 可以把 5~8 行指令濃縮成一行執行,非常省事。
接下來的幾個指令就依樣畫葫蘆:
xargs 真的是非常好用,下一篇再來介紹怎樣用 find、sed 搭配 xargs 來批次修改 awstats 統計資料檔(純文字檔)的內容。
參考:[2010-03-17] [Shell Script] 批次修改使用者的密碼有效期限 - V1
要設定「密碼有效期為90天」以及「密碼到期前30天警告」可使用以下指令:
echo -e "account1\naccount2" | xargs -i chage -M 90 -W 30 {}
echo 加上 -e 參數後會讓兩個帳號間的「\n」換行字元生效(不加 -e 的話 xargs 會收到「account1\naccount2」這個完整的字串),再搭配 xargs -i 的置換效果({}會被置換成透過 pipeline 接收的字元),上面一行指令相當於下面兩行指令:
chage -M 90 -W 30 account1
chage -M 90 -W 30 account2
這樣的寫法的彈性在於,要 echo 哪些帳號出來完全可以自由控制,不用考慮不同系統中 uid 的起始數字不同,也不用考慮例外狀況。
在我管的系統中每個 OS 中的帳號都類似(大概是5~8個),透過 xargs 可以把 5~8 行指令濃縮成一行執行,非常省事。
接下來的幾個指令就依樣畫葫蘆:
- 檢查上述指令是否生效:echo -e "account1\naccount2" | xargs -i chage -l {}
- 設定最後一次變更密碼的日期:echo -e "account1\naccount2" | xargs -i chage -d YYYY-MM-DD {}
- 在 Unix 系統(e.g., Solaris)上設定密碼90天到期、到期30天前提醒:echo -e "account1\naccount2" | xargs -i passwd -x 90 -w 30 {}(Solaris預設沒有 chage 指令)
xargs 真的是非常好用,下一篇再來介紹怎樣用 find、sed 搭配 xargs 來批次修改 awstats 統計資料檔(純文字檔)的內容。
參考:[2010-03-17] [Shell Script] 批次修改使用者的密碼有效期限 - V1
2010年12月12日
利用Blogger Touch服務快速建立.NET碎碎唸手機版
最近偶爾會把iPad測試機帶回家玩,今天熊熊想到之前在電腦玩物看過一篇邀請大家測試電腦玩物手機版,與Feedburner被牆二三事,裡面提到Sopili 軟體邦製作了一個新的網路服務:Blogger Touch,專門幫採用Google Blogger平台的部落格轉換出手機適用的閱讀版面,當時一直沒有認真的去試用。但最近適逢iPad正式開賣,各家廠商的Android Pad也蓄勢待發,所以還是不要偷懶,趕快把手機/平板電腦適用的行動版面作出來吧XD
Blogger Touch的使用非常簡單,首先連到Blogger Touch,點選Mobile Edition Maker的連結,依序輸入Blogger的網址、登入用來建立部落格的Google帳號、選擇一個在Blogger Touch服務上不重複的id、調整Blogger的設定,最後把Blogger Touch的js組件新增到部落格的版面就可以了。
調整前的PC版版面如下:
由Blogger Touch 產生的行動版面如下:
如果有特殊需求,要在手機/平版電腦上閱讀PC版的版面(例如要在iPad上新增一篇新增一篇Bloggerr文章),只要移到畫面最下方,關閉「Mobile Theme」就可以了:
希望未來用手機/平版電腦閱讀本部落格的讀者能有更好的閱讀體驗^_^
2010-12-18 更新:今天看到電腦玩物的一篇,Google Blogger幫部落格擴增行動版,自動切換手機專用網頁模板,於是又去嘗試了官方提供的行動版網頁,測試以後發現一頁顯示的文章比較少,但是字比較大,顯示速度也更快,所以暫時就先換成官方版的囉 XD
Ps. 本文除了插入圖片外,其餘編輯都在iPad上完成,iPad的中文輸入鍵盤真的是很不錯用啊!
Blogger Touch的使用非常簡單,首先連到Blogger Touch,點選Mobile Edition Maker的連結,依序輸入Blogger的網址、登入用來建立部落格的Google帳號、選擇一個在Blogger Touch服務上不重複的id、調整Blogger的設定,最後把Blogger Touch的js組件新增到部落格的版面就可以了。
調整前的PC版版面如下:
由Blogger Touch 產生的行動版面如下:
如果有特殊需求,要在手機/平版電腦上閱讀PC版的版面(例如要在iPad上新增一篇新增一篇Bloggerr文章),只要移到畫面最下方,關閉「Mobile Theme」就可以了:
希望未來用手機/平版電腦閱讀本部落格的讀者能有更好的閱讀體驗^_^
2010-12-18 更新:今天看到電腦玩物的一篇,Google Blogger幫部落格擴增行動版,自動切換手機專用網頁模板,於是又去嘗試了官方提供的行動版網頁,測試以後發現一頁顯示的文章比較少,但是字比較大,顯示速度也更快,所以暫時就先換成官方版的囉 XD
Ps. 本文除了插入圖片外,其餘編輯都在iPad上完成,iPad的中文輸入鍵盤真的是很不錯用啊!
2010年12月11日
[NPOI] 輕鬆地將 GridView 匯出成試算表
相信大家都遇過要將資料匯出成 Excel 的問題
這次坎尼用 NPOI 製作匯出用的 WebUserControl
如果以後有相同需求,不介意就直接拿去用吧 :D
在畫面上加入按鈕,用來觸發匯出事件
接著建立兩個屬性:TargetGridViewID、SheetName
TargetGridViewID 用來指定要匯出的 GridView
SheetName 則是匯出的試算表名稱
進入按鈕事件,這邊唯一要做的事,就是去找引用頁面的 GridView
找到之後丟給 ExportToFile 這個 method 就沒事了(十分輕鬆)
接著到 ExportToFile(GridView gv)
這邊可參考 NPOI 建立試算表的方法,不再多提
要注意的就是抓取 GridView 欄位數時,不用要 Columns.Count
而是改用 HeaderRow.Cell.Count
大功告成,其他部分的 Code 有興趣的話可以到這邊下載
接著再加入 GridView 及設定其繫結事件
設定 UserControl 的 TargetGridViewID 及 SheetName 屬性
執行測試頁面,點下匯出之後即會把資料轉換成試算表
怎樣,是不是很簡單呢?
使用上也限制了 GridView 不能啟動分頁
如果要加入自定樣式或是分頁也可以匯出的功能
可將 Source Code下載回去自行修改
坎尼有空再來擴充這個 UserControl 的功能 : )
這次坎尼用 NPOI 製作匯出用的 WebUserControl
如果以後有相同需求,不介意就直接拿去用吧 :D
I. 實作過程
首先,建立一個 WebUserControl在畫面上加入按鈕,用來觸發匯出事件
接著建立兩個屬性:TargetGridViewID、SheetName
TargetGridViewID 用來指定要匯出的 GridView
SheetName 則是匯出的試算表名稱
進入按鈕事件,這邊唯一要做的事,就是去找引用頁面的 GridView
找到之後丟給 ExportToFile 這個 method 就沒事了
這邊可參考 NPOI 建立試算表的方法,不再多提
要注意的就是抓取 GridView 欄位數時,不用要 Columns.Count
而是改用 HeaderRow.Cell.Count
II. 測試
建立一個測試頁面,把剛做好熱騰騰的 WebUserControl 放上去接著再加入 GridView 及設定其繫結事件
設定 UserControl 的 TargetGridViewID 及 SheetName 屬性
怎樣,是不是很簡單呢?
III. 小結
這次只陽春地做出了匯出功能使用上也限制了 GridView 不能啟動分頁
如果要加入自定樣式或是分頁也可以匯出的功能
可將 Source Code下載回去自行修改
坎尼有空再來擴充這個 UserControl 的功能 : )
2011/02/11 修改:User Control 已有新版本,請前往 連結 下載新的檔案
2010年12月5日
[FireFox] 利用 FireGestures 撰寫 script 呼叫 Readability
FireFox 瀏覽器擁有許多好用附加元件是眾所皆知
而 FireGestures (滑鼠手勢)便是其中一項
今天就來介紹如何自行撰寫 FireGestures 的 scripts
用來呼叫另一個閱讀用附加元件 - Readability
接著開啟 FireFox 的 Add-on 視窗,選擇 FireGestures –> 選項
進入手勢對應(Mapping)頁籤,選新增腳本手勢(Add Script…)
填入名稱之後,在腳本手勢視窗(Script) 裡寫入底下這行指令
接著再設定要用的滑鼠手勢指令
在手勢(Gesture)下面的視窗中,按住滑鼠右鍵不放,畫出想要的手勢
指令確定無誤之後就放開右鍵 (手勢指令說明見下列表)
滑鼠先按住右鍵不放,往下,往上,再往右,放開右鍵即會呼叫指令
(左下角會有指令的名稱)
放開滑鼠右鍵之後即會執行指令
(原本密密麻麻不是很好讀的文件,瞬間就改成較舒服的閱讀方式)

FireGestures 的 script 其實是 javascript-based
所以一般的 javascript 指令也能寫在 script 中
或許可利用這點,開發出好用的懶人手勢指令 : )
最後補充一點,如果有安裝 NoScript
要執行 Readability 之前要先打開該頁主要 domain 的 script 限制
而 FireGestures (滑鼠手勢)便是其中一項
今天就來介紹如何自行撰寫 FireGestures 的 scripts
用來呼叫另一個閱讀用附加元件 - Readability
I. 實作
首先,要先安裝 FireGestures 及 Readability接著開啟 FireFox 的 Add-on 視窗,選擇 FireGestures –> 選項
進入手勢對應(Mapping)頁籤,選新增腳本手勢(Add Script…)
填入名稱之後,在腳本手勢視窗(Script) 裡寫入底下這行指令
Readability.enableREADABILITY({target: {id: 'readability-statusbar-icon'}});接著再設定要用的滑鼠手勢指令
在手勢(Gesture)下面的視窗中,按住滑鼠右鍵不放,畫出想要的手勢
指令確定無誤之後就放開右鍵 (手勢指令說明見下列表)
- U=Up
- D=Down
- L=Left
- R=Right
滑鼠先按住右鍵不放,往下,往上,再往右,放開右鍵即會呼叫指令
II. 實際執行畫面
先在要執行指令的頁面按住右鍵不放,畫下 DUR(左下角會有指令的名稱)
放開滑鼠右鍵之後即會執行指令
(原本密密麻麻不是很好讀的文件,瞬間就改成較舒服的閱讀方式)
III. 小結
FireGestures 的 script 其實是 javascript-based
所以一般的 javascript 指令也能寫在 script 中
或許可利用這點,開發出好用的
最後補充一點,如果有安裝 NoScript
要執行 Readability 之前要先打開該頁主要 domain 的 script 限制
2010年9月2日
傳統的架站方式(非雲端運算/虛擬化環境)要如何應付超大量的流量
前陣子我負責維運的網站由於配合行銷活動的關係,在短時間內湧入超大的流量,而這個系統是用傳統的架構(也就是用多台實體 server 做 load-balance,配合網路的 VIP 設定以 IP-hashing 分流)做的,在應付這種超大流量的時候顯得力不從心,以下紀錄採用如此架構要應付超大流量時,要注意的地方。
流量控管
另外補充一點,MySQL DB 瞬間倒台(RAM 被吃光) 以後,除了緊急擴充 RAM 以外,還討論了以下兩種方案:
流量控管
- 應該請行銷人員事先通知系統管理人員何時會發行銷簡訊,以便提早設定 web server 的流量限制 (concurrent sessions),以免瞬間倒台。雖然超出流量限制的 user 無法連線成功,但只要 retry 就可能連的上。這樣的作法可確保 web server 不會倒台,在能力範圍內提供最多的服務。
- DB server 倒台時可能要花很長時間才能回復,在這些 downtime 時損失的流量是難以挽回的。
- 平常應該透過壓力測試,或者流量分析的歷史紀錄來評估每台 Web server 最多可接受多少個concurrent sessions,以便進行上述的流量限制。
- Web server concurrent sessions 的設定應慢慢逐步放寬,以免瞬間超過 server 的負荷量而倒台。
- 要注意 Apache httpd.conf 裡面的「MaxClients」設定值,若設定值過高可能造成 server 無法負荷(甚至造成接 console 也無反應,沒有螢幕,必須重開機)。(預設值為256)
- 上線前要作 end to end 的測試(包含所有備用機),備用機的狀態應該調整到只要 VIP 一 enable,就會有流量進來的程度,只是在 VIP 設定中暫時 disable,保持隨時可以上線的狀態。本次準備的一台備用機因 OS 環境與正式環境差太多 (如 Apache 版本、Apache modules 版本等),最後無法即時在當天 config 完成並上線提供服務。
- 設備的 RAM 應提早估計是否夠用,臨時要調 server 使用的 RAM 相當困難(e.g., 創見門市不賣 server 使用的 RAM,價錢也蠻貴的),頂多只能把閒置的 server 停機來支援 (等到活動結束又要安排時間把 server 組態回復原狀,又要再花時間測試、驗證)。
- IBM X3650/X3850 M2 的 RAM 無法讓 IBM X3850 使用。
另外補充一點,MySQL DB 瞬間倒台(RAM 被吃光) 以後,除了緊急擴充 RAM 以外,還討論了以下兩種方案:
- 維持 active/standby:如此當 active server 倒台的時候 backup server 可接手服務,資料也比較不會有不一致的問題。但是現況是 backup server 的 RAM 比 active server 還弱!因此若 active server 倒台,backup server 一定撐不住 (而且會更快倒),也就無法發揮「接手服務」的功能。
- 將 Web Server & DB Server 分群:如上所述,當倒台時由於 backup server 實際上無法接手 active server 的服務,因此不如設定 n 台 web server 對應 active DB server,另外 m 台 web server 對應到 backup DB server,在兩台 DB Server 資料隨時雙向同步的狀況下,同時讓兩台 DB server 一起提供服務。有的考量是怕資料會不一致,而且萬一某一台 server 倒掉了就沒人接手了。
最後經過討論,仍決定維持方案1 (active/standby),幸好到後來 DB 有撐住。以當天的 loading 來看,若 RAM 沒有擴充可能會撐不住,但研判改寫程式才是 DB loading 能降低的主因(動態網頁-->靜態網頁),也許未來遇到像這次可預期的超大需求的時候可以提早調整程式。
個人的感想是採用方案二可以提供更好的效能,因為發生硬體障礙的機率應該是遠低於把所有的流量都導向 active server 而造成倒台。而且一旦 active server 倒台,服務會完全停擺 (standby server 一接手就會馬上倒),除非把 web server 的流量限制設定的很嚴格,才能讓 DB 維持運作。
若採用分群,則兩台 DB server 的 loading 都不會太高,倒台的機率就會大大降低,但最重要的前提是兩台 server 間的資料可以完美的同步,最後每一筆資料都要能由 timestamp 來排序。
在 MySQL HA Overview 一文中官方也說明了如何提供 HA 的架構,很值得仔細研究。
個人的感想是採用方案二可以提供更好的效能,因為發生硬體障礙的機率應該是遠低於把所有的流量都導向 active server 而造成倒台。而且一旦 active server 倒台,服務會完全停擺 (standby server 一接手就會馬上倒),除非把 web server 的流量限制設定的很嚴格,才能讓 DB 維持運作。
若採用分群,則兩台 DB server 的 loading 都不會太高,倒台的機率就會大大降低,但最重要的前提是兩台 server 間的資料可以完美的同步,最後每一筆資料都要能由 timestamp 來排序。
在 MySQL HA Overview 一文中官方也說明了如何提供 HA 的架構,很值得仔細研究。
其他感想
- 要擴充實體機器是相當麻煩的,遠比擴充 VM 困難的多,特別是網路設定的部份(設定 IP、VIP 等,不小心還會插錯 switch…而且插錯 switch 挺難查的,可能會造成明明網路有通,但是 apache 接不到 HTTP request 的詭異情況)。
- 如果活動真的很盛大,瞬間湧入超大的流量,那麼 DB Server 有可能會瞬間倒台,時間推測在幾十秒到一分鐘之間。假設系統架設在 Amazon EC2 上,能不能在這麼短的時間內 clone 一台新的 server 並且立刻上線提供服務?雖然說在虛擬化環境中可在短短數分鐘內就新增一台 server,相較於擴充實體 server 已經是非常快速,但要應付瞬間如此大量的需求可能還是不足,最理想的狀況是能夠在數秒鐘,或者 10 秒內就擴充第一台 server,讓整個 DB cluster 能夠撐下去,之後就比較有餘裕來進一步擴充了。
訂閱:
文章 (Atom)
Google Spreadsheet 裡用規則運算式
最近因為工作關係,遇到要用 Google Form 及 Google Sheet 所以研究了 Google Sheet 裡的一些 function 怎麼用 首先,分享一下如何在 Google Sheet 裡用規則運算 :D
-
好久沒開 Chart Control 議題了 剛好前陣子 Codeplex 出現可以輕鬆建立 Excel 檔案的 Library- NPOI 於是坎尼想說研究一下,看能不能把 Chart Control 匯出圖片到 Excel 中 沒想到只花了不到1小時就研究...
-
雖然在圖片上直接按右鍵就可以另存圖片 (沒設定權限的話 不過客戶還是想要有個按鈕能讓圖片下載 所以坎尼只好再想辦法滿足客戶的需求 UI設定 首先,在畫面上準備好下載按鈕和圖表 順便設定一下樣式和內容,這部分之前講過很多次就不多談了 撰寫按鈕事件 先宣告 System.IO.Mem...
-
拖稿拖了好幾天 坎尼夢見了富檻出新連載 所以上來把欠的東西還一還 (富檻快給我畫 坎尼廢話就少講一點 直接進入 自訂分頁 Sample 首先,畫面上要有個 Gridview 這邊坎尼偷懶用了 SqlDataSource 見下圖 可以看到 Pager 已經出現了 來看一下...


