2010年11月4日 星期四

使用JavaScpript計算日期(幾年後、幾月後、幾天後)

使用JavaScpript計算日期(幾年後、幾月後、幾天後)

在使用JS時,
有時候可能會需要計算到期日,
就是就會某天,再加上某個天數(或年或月)後,
計算出來的日期。
在SQL裡,有DATEADD的函式;
在.Net裡,有DateTime.AddDays等函式;
而若要在JS計算的話,該如何實現呢??

主是要使用setYear()setMonth()setDate()

不過呢,這方法它的計算邏輯與.net及SQL的不太相同
不相同的地方就是在於大小月的處理方式

SQL的大小月處理及潤年

JavaScript的大小月處理及潤年


由上圖可知,JavaScript的潤年規則還是有的~~
不過,在計算跨月處理大小月時的邏輯,是會將多餘的天數累加上去的~~這點請注意。

至於.Net的呢,邏輯是與SQL相同。

程式碼參考如下:

//轉成日期格式
var orgDay = new Date("1983/4/29");
orgDay.setMonth(orgDay.getMonth() + 2);//加月份

//以下則為取出年、月、日
var d = orgDay.getDate();
var Y = orgDay.getFullYear();//此方法才可以確實的支援FX、IE、Chrome各大瀏覽器
var M = orgDay.getMonth() + 1;//月份是由0開始計算,也就是一月的話,取出的值會是0

if (d < 10) { d = "0" + d; } //設定日期若為個數則加0
if (M < 10) { M = "0" + M; } //設定日期若為個數則加0

//設定為1983/06/29的日期格式
var OkDay = Y + "/" + M + "/" + d;



抓取年份時,請採用getFullYear()。不要太直覺性的使用getYear(),
該方法會在FireFox及Chrome上發生問題~~
例如應該回傳2010的值,會變成「110」。
這110,是從「2010-1900」計算而來的~~~

2010年8月17日 星期二

使用RSClientPrint直接列印RS報表

使用RSClientPrint直接列印RS報表


一般而言,當我們想要列印RS報表時,
都是先將報表另存下來後,再開啟檔案列印的。

原來,Report Services早就幫我們想好這點了,
它提供了一個叫「RSClientPrint」的cab元件,
直接執行JavaScript就可以列印報表了!!

雖然在很早以前就以前提供了,但這時候,也需特別注意環境,
也就是SQL Server的版本,在這邊,以SQL 2005為例。
在SQL 2005最初版來說,有被攻擊的危險,
所以,在某次系統安全性更新後,該功能會被拿掉,必須再去升級才行使用。
當然,如果允許的話,建議將其升級為最新版本的最好囉。(目前為SP3)

以目前來說,至少需為SQL Server 2005 SP2 的版本才能列印,
至少必須確定
C:\Program Files\Microsoft SQL Server\MSSQL.2\Reporting Services\ReportServer\bin\RSClientPrint.cab
2008/8/5之後的版本才行。
若不是的話,可能是有些更新沒有裝到。試著安裝此更新

環境都確定好後,就可以開始實作了。

程式碼參考如下:(其實這段,網路上一堆,到處都可以copy的到)

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="RSClientPrint.aspx.cs" Inherits="RSClientPrint" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>未命名頁面</title>

<script type="text/javascript" language="javascript">
function Print()
{
alert('進入列印');

if (typeof RSClientPrint.Print == "undefined") 
{
   alert("Unable to load client print control.");
   return;
}
//邊界
RSClientPrint.MarginLeft = 0;
RSClientPrint.MarginTop = 0;
RSClientPrint.MarginRight = 0;
RSClientPrint.MarginBottom = 0;

//繁體中文
RSClientPrint.Culture = 2052;
RSClientPrint.UICulture = 2052;

//預設為A4
//如果 PageWidth 大於 PageHeight,列印方向就會設定為 [橫向]。 否則,就會設定為 [縱向]。
RSClientPrint.PageHeight = 297;
RSClientPrint.PageWidth = 210;

RSClientPrint.Authenticate = true;

RSClientPrint.Print('http://localhost/ReportServer', '/TestPage', 'TestPage')
}
</script>

</head>
<body>
    <object style="display: none;" id="RSClientPrint" classid="CLSID:0D221D00-A6ED-477C-8A91-41F3B660A832"
        codebase="RSClientPrint.cab#Version=2005,90,4053,00" VIEWASTEXT>
    </object>
    <form id="form1" runat="server">
        <div>
                 <asp:Button ID="Button1" runat="server" Text="列印" OnClientClick ="Print();return false;" />
        </div>
    </form>
</body>
</html>



有個地方需要注意一下。classid 及 codebase 這邊:
  1. Version」也請參考該元件裡的RSClientPrint.inf內的版次。(不過,有測試過,就算拿掉也可以用)
  2. CLSID:0D221D00-A6ED-477C-8A91-41F3B660A832」也請參考RSClientPrint.inf的資料
  3. codebase」將指向該元件檔案的位置,由於這邊我是將網頁及元件放在同個目錄下。請配合調整。
如果值亂改的話,會導致元件安裝不正常。如下圖


倘若設定都正常的話,執行該網頁,則會看到以下畫面:

想用的話,當然只能選擇「安裝」
安裝完後,按下列印,即會彈出列印方塊。按下「確定」就可以列印囉~~
或者可以點選「預覽」功能。(我的測試報表字好像有點小)

微軟的說明文件:在自訂應用程式中使用 RSClientPrint 控制項
另外,此方法…只能支援IE瀏覽器。





2010年7月7日 星期三

安裝Visual Studio 2010

安裝Visual Studio 2010


系統硬碟空間:至少7.4GB(Ultimate)
系統安裝期間,會有三次的「重新開機」,若電腦目前有在作業而不方便重開的話,
建議暫時不要安裝。等電腦閒置時,再裝。



安裝完 .Net 4.0後,馬上要求重新開機。

又要重開?

即將開始一段冗長的等待…

按完「完成」後,又要重開機。

啟動畫面

環境設定

耶~~VS2010 入手~~


2010年6月11日 星期五

線上列印-Word

線上列印-Word


這個功能呢~~
主要就是可以讓使用者在線上列印我們Web應用程式產生的Word。
而不用讓使用者自行下載下來後,再開啟Word來列印。

首先,必須先「加入參考
之後,便會再「Web.Config」上,看到自動幫你新增的一行組件資訊

<add assembly="Microsoft.Office.Interop.Word, Version=11.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"/></assemblies>

那這邊,也來說明一下目前我的程式流程!

1 載入指定目標路徑的「範本檔案
2 將範本檔案進行修改:(使用第三方元件:Aspose.Word)
  • 從資料庫撈對應的資料至Word裡對應的「功能變數」
  • 再另存修改後的檔案至指定路徑
3 由指定路徑載入Word檔進行列印作業
4 刪除指定路徑的Word檔

以下的程式碼,為執行列印作業的範例:
主要方法是在「PrintOut」,它的列印格式可以很活。詳細可參考Document.PrintOut 方法


        //物件宣告
        Microsoft.Office.Interop.Word.Application app = null;
        Microsoft.Office.Interop.Word.Document doc = null;
        object oMissing = System.Reflection.Missing.Value;
        object templateFile = "指定路徑:欲列印的檔案";

        //繫結Word檔
        app = new Microsoft.Office.Interop.Word.ApplicationClass();
        doc = app.Documents.Add(ref templateFile, ref oMissing, ref oMissing, ref oMissing);

        //列印參數設定
        object oBackground = false;//true 表示當 Microsoft Office Word 列印文件時,繼續執行自訂程式碼。
        object oRange = WdPrintOutRange.wdPrintAllDocument;//頁面範圍。
        object oOutputFileName = oMissing;//如果 PrintToFile 為 true,這個引數會指定輸出檔的路徑和檔名。
        object oItems = WdPrintOutItem.wdPrintDocumentContent;//要列印的項目。
        object oCopies = 1;//要列印的份數。
        object oPages = "";//要列印的頁數和頁面範圍,以逗號分隔。例如,「2, 6-10」是表示列印第 2 頁以及第 6 到第 10 頁。
        object oPageType = WdPrintOutPages.wdPrintAllPages;//要列印的頁面類型。
        object oPrintToFile = false;//true 表示將印表機指令傳送至檔案。請確定使用 OutputFileName 指定檔案名稱。
        object oCollate = true;//當列印文件的多份複本時,true 表示先列印文件的所有頁面,再列印下一份複本。(自動分頁)
        object oManualDuplexPrint = false;
        object oPrintZoomColumn = 0;
        object oPrintZoomRow = 0;
        object oPrintZoomPaperWidth = 0;
        object oPrintZoomPaperHeight = 0;
        object oTrue = true;
        object oFalse = false;
    
        
        //釋放物件用
        object m_sc = 0;
        object m_of = oMissing;
        object m_rd = oMissing;


        //執行列印
        doc.PrintOut(ref oBackground, ref oFalse, ref oRange, ref oOutputFileName, ref oMissing, ref oMissing, ref oItems, ref oCopies, ref oPages, ref oPageType, ref oPrintToFile, ref oCollate, ref oMissing, ref oManualDuplexPrint, ref oPrintZoomColumn, ref oPrintZoomRow, ref oPrintZoomPaperWidth, ref oPrintZoomPaperHeight);

        
        // 關閉 Word 物件
        if (app != null)
        {
            app.Quit(ref m_sc, ref m_of, ref m_rd);
        }
        // 釋放文件
        if (doc != null)
        {
            doc = null;
        }
        // 釋放 Word 物件
        app = null;



請注意~~~
這個是因為IIS在執行MS Word時,發生權限不足的問題~
必須在Web.Config中,設定讓ASP.NET實作「本機模擬」

<compilation debug="true">

若要進一步設定,可參考如何在 ASP.NET 應用程式中實作模擬

當然,指定模擬的話,需要注意,在「主控台根目錄/元件服務/電腦/我的電腦(右鍵內容)/COM安全設定/存取權限
裡面有指定的帳戶。

開啟主控台根目錄方式:
1 執行:DCOMCNFG.EXE
2 控制台->系統管理工具->元件服務





2009年11月11日 星期三

我的查詢不怕大小寫喲~~

對自己而言,是個「大發現」~~不知道別人是否已經知道這個小技巧了~~

往往我們在SQL 下查詢語法時,
為了避免要找「3Probe」時,鍵入「3probe」會找不到資料,
於是乎,我們會針對關鍵字做二件事
txt.Text.ToLower()」,針對我們鍵入的值轉成「小寫」(當然也可以是大寫);
lower(company) like '%@keyword%'」,針對資料庫欄位資料也轉成小寫;
這樣去比對的話,「小寫對小寫」就沒問題可以找出來了~~

如今,我的大發現就是在查詢語法的欄位處,去更改它的「定序」再去比對資料,
將「定序」設成「Chinese_Taiwan_Stroke_CI_AS(忽略大小寫)」的值,
可以不管三七二十一的給它去找,
而且,這種方法,也支援我們一向害怕的「ntext」資料型態的欄位。
(因為之前用轉小寫的的方法在ntext這邊沒辦法用)

至於效能的話呢,在這邊也提供了圖片大家參考,在SQL裡面測一下試試,
多了一個轉換定序的動作,會不會耗效能呢?
圖片所示,所佔比例都是「33%」,看起來,似乎不會太佔效能
也許資料量不多測試的不完整~~請多包涵。






2009年7月29日 星期三

三位一撇…好簡單

之前,想要在報表將金額的部份,需有「1,234」這樣的格式,
於是很直覺的想說在SQL撈資料時,就將其轉成「1,234」就好,
就上網去找看看有沒有什麼語法,在網路上,也看到有人自訂了函式來產生,
但,覺得有點麻煩,主要是覺得,這種東西應該很大眾化,大家都會有需求才對,
微軟應該會貼心一點才是,於是便往SQL的預設函式去尋找,後來找到了~~嘻嘻
是利用大家常用的「Convert」函式喲~~

MSDN:


實際的語法:
SELECT REPLACE(CONVERT(VARCHAR,CONVERT(MONEY,12345678.123),1),'.00','')

當然,若是想在報表要輸出,而不是透過SQL轉好再輸出,
則可以利用報表的「Format」函式來做。

格式語法:
Format(CLng(First( 欄位值 , "ds")),"###,###,###,##0")
(在前面有個CLng就是將其轉成數字格式,若是有小數點的話,則應該使用CDbl)

(以上測試,感謝 三趨科技 官大龍 協助)

2009年7月17日 星期五

預存程式的資料也可 Join 資料表

各位有沒有試過,將StoreProcedure裡的資料,再去join別的資料表呢?
之前遇到一個問題,就是原本的清單必須要還要再過濾一些條件,

但清單的資料已經是從StoreProcedure裡撈出來的,

StoreProcedure是共用的呀,我總不能為了自己的這個地方,

而去改共用的StoreProcedure,那這樣的話,不就會影響到其它的程式了,

那另外自己再寫一個查詢 SQL 咧?

偏偏那個 SQL 又是一長串,懶得自己再寫了。

於是就覺得,應該可以把StoreProcedure撈出來的資料,再去join別的資料表吧。

於是,又去拜訪了Google大神~~


嘿嘿嘿!!一下子就找到資料了,果然真的有嘛~~
--將查詢結果存入暫存資料表
create table #temp(mid nvarchar(10),memberchname nvarchar(10),uid nvarchar(32),unitname varchar(100))

insert into #temp EXEC spMemberList @uid

--只挑出8及5的值
select #temp.* ,B02POPESN,B02ADKIND from #temp
inner join p2kdb.dbo.CPABT02M on mid=B02IDNO
where (B02POPESN='8' or B02ADKIND='5')

drop table #temp

2009年4月17日 星期五

在WebPart中讓加入的UserControl動態產生動作按鈕

現在大部份的網站都支援客製化的設定
也就是說,可以讓使用者自行定義自己的畫面,想要看到的東西
就像「iGoogle」那樣~~

微軟在.net 2.0提供了「WebPart」的元件,供大家使用~~
至於WebPart的使用方式,其實,拉一拉就出來了~~並不難
這邊就不多加介紹說明了

在此,提供一個比較進階的使用方法。如題,
可以自行在WebPart的標題列按鈕區,動態增加自己要的按鈕
並執行指定的程式碼。

WebUserControl.ascx.cs 程式碼
-----------------------------------------------------------
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class WebUserControl : System.Web.UI.UserControl, IWebActionable
{
    protected void Page_Load(object sender, EventArgs e)
    {
        this.Button1.Visible = false;
    }
    WebPartVerbCollection IWebActionable.Verbs
    {
        get
        {
            WebPartVerb editVerb = new WebPartVerb(
            "editVerb1",
            new WebPartEventHandler(this.Button1_Click)
            );
            editVerb.Text = "我是動態產生的";

            
            return new WebPartVerbCollection(
            new WebPartVerb[] { editVerb }
            );
        }
    }

    protected void Button1_Click(object sender, EventArgs e)
    {
        //要執行的指令
    }
}

----------------------------------------------------------------


2008年12月26日 星期五

在SQL中使用自訂函數-->十進位轉二進位(12.26)

SQL中要將10進位轉2進位,到底應該怎麼轉呢?
原先想說,
select Convert(binary(10),20),這樣試試
結果,出來的卻是
0x00000000000000000014
天丫,居然變成16進位了,這不是我想要的耶~~
我是希望,打了20,可以幫我轉成「10100」。這樣才對!

在網路上找了挺久,sql似乎沒有這樣的函數,
既然沒有default的,那就自己來寫一個吧!
在c#中,寫function,很簡單,而在sql自訂函數呢?嘻~一樣很簡單
  1. 可程式性」中,有個「函數」,將分支打開後,裡面有sql預設的所有函數,若在找函數用時,可以來參考看看喲!(我也是這次才注意到),直接在「函數」上按右鍵選「新增」,另有一層,是選擇傳回值的資料,看是傳回單值,還是傳回資料表的,這次是要傳回一個轉換後的字串,所以選擇「純量值函數」。
  2. 在新增畫面中,感覺跟「預存程序」差不多嘛~姑且,我將要填入值的地方,分成幾個部份。「說明」「自訂函數名稱」「定義自訂函數參數」「定義回傳資料型態」「宣告回傳值變數」「運算區」「回傳指令」
  3. 確定執行無誤後,接著就是呼叫啦~~~執行: select dbo.ToBinary(20,5)。結果:10100

以下是自訂函數的程式:
-- =============================================
-- Author: 宗
-- Create date: 20081226
-- Description: 將數值資料轉換成二進位字串
-- =============================================

ALTER FUNCTION [dbo].[ToBinary]
(
-- Add the parameters for the function here
@Number int ,--傳入要轉換的數值資料
@Max int --可接受的最大字元數
)
RETURNS nvarchar(31) --共可接受31位數(因為int只到2的31次方)
AS
BEGIN

-- Declare the return variable here
DECLARE @binery nvarchar(31)
set @binery=''
-- Add the T-SQL statements to compute the return value here

--若數值超過所設定的次方數的或是超過函數自訂的31次方,則回傳空字串
if (@Max>31)
begin
return @binery
end

if @Number>power(2,@Max)
begin
return @binery
end
--檢查若都無誤,則進行轉換

declare @min int
set @min =0 --起始值
--進行轉換
while @min<@max+1
  begin
   if @Number=0
    break
   set @binery = Convert(nvarchar(10),@Number % 2)+ @binery;
   set @Number = @Number / 2;
   set @min=@min+1
   end
    -- Return the result of the function
  RETURN @binery
  END  

2008年12月2日 星期二

RadioButton 不准動(12.2)

想要讓CheckBox不能讓使用者點選的話,有很多種方式。
例如:設 Enabled=False,或是來個 disabled,但是呢,這都影響到其外觀,
也就是說,當設了以上的屬性時,他的外觀就會變成是灰色的了。
當然,這樣有好處,也有壞處。這邊就介紹一個可以不影響外觀的小技巧。

<asp:CheckBox ID="CheckBox1" runat="server" onclick="return false;" />

如此一來,怎麼點,他就是不能勾選或取消喲!!

然而,既然 CheckBox 可以用的話,那 RadioButton 應該也可以用吧~~
那就來套套看吧~~
呃~~~結果,動是不能動了,可是,當我是RadioButton群組時,
當點了非預設的選項時,原本預設的選項便會被清空。看來這個小技巧不適合它了。
那就只好寫個小 Function 來協助一下吧!

物件
<asp:RadioButtonList ID="RadioButtonList1" runat="server"  onclick="readonlyRadio(this.id,2)"  >
        <asp:ListItem Value="a">Aasp:ListItem>
        <asp:ListItem Value="b" Selected="true">Basp:ListItem>
        <asp:ListItem Value="c">Casp:ListItem>
asp:RadioButtonList>

JavaScript 函式

function readonlyRadio(name,defaultCheckedIndex) 
{  
    document.getElementsByName(name)[defaultCheckedIndex].checked = true;   
    
}   
看了後,應該是看得懂吧?將預設的選項帶給它,之後,再讓它還原預設的選項就行了!!
對了,有一點要提示的是,有沒有注意到,
這邊使用的是「document.getElementsByName」,而不是「Id」?
原因是,ServerControl RadioButtonList編譯出來的是很多個「input」「type="radio" 」的HTML元件,
其中,將這些input全部以「name」屬性包起來。就跟設Group一樣囉~
所以,當我們在抓時,就該用 getElementsByName 抓呀

2008年11月27日 星期四

何謂「委派(Delegate)?」(11.27)

委派(Delegate):
  1. 委派就如中文表面的意思一樣,就是將我們定義好的方法,透過委派的物件,來執行該方法。
  2. 在我們一般寫程式時,也許甚少會用到委派的東西,但,若你在開發一些共用元件,需要提供方法、事件讓別人使用時,就應該要透過委派來達到安全性及共用性。
範例:

//以下是一個四則運算的簡單範例


    delegate int arithmetic(int num1, int num2); //定義委派類型


    protected void Page_Load(object sender, EventArgs e)
    {
        //先宣告委派
        arithmetic ari=null;

        //設定算術原則
        string fun="/";

        switch (fun)
        {
            //依照fun所給的算術原則,將該算術原則的方法,指派給「ari」
            case "+":
                ari = new arithmetic(this.add);
                break;
            case "-":
                ari = new arithmetic(subtract);
                break;
            case "*":
                ari = new arithmetic(multiply);
                break;
            case "/":
                ari = new arithmetic(divide);//實作委派
                break;
                //(這些方法,必須也要跟定義委派類型的是相同的喲。

就是說,也必須有回傳int,及有兩個數值參數。)
        }

        int ccc = ari(6, 3);//這時候,只要統一用「ari」就可以呼叫對應的方法了。

    }


    private int add(int a,int b)
    {
        //加
        return a + b;
    }

    private int subtract(int a, int b)
    {
        //減
        return a - b;
    }

    private int multiply(int a, int b)
    {
        //乘
        return a * b;
    }

    private int divide(int a, int b)
    {
        //除
        return a / b;
    }



另外,委派也有「組合」的功能,可以將數個方法,一起組合起來,依序執行。
例:
ari += new arithmetic(this.add);
ari += new arithmetic(this. subtract);

如此的話,程式便會先執行「add」完後,接著執行「subtract」。另外,有了「+」,也可有「-」

ari += new arithmetic(this.add);
ari += new arithmetic(this. subtract);
ari -= new arithmetic(this.add);

經過了「-」的動作,原本加上的「add」方法,又被移除了,於是就只會執行「subtract」而已。


2008年11月19日 星期三

按Enter,就執行我要的按鈕(11.19)

常常在網頁中,例如「登入」「查詢」的功能時,
我們會希望輸入完資料後,
按下「Enter」,就能執行登入或查詢的功能,
而不是用滑鼠去點選按鈕,
以往,我們要達到這種目的,
需要用javascript判斷我們所鍵入的按鍵key值
再去觸發該按鈕的事件。

現在,.Net 2.0幫我們包好了我們要的功能囉。

我們可在「Form」標籤裡的「defaultbutton」屬性,
設定我們要執行按鈕的ID即可
又或是可在「Panel」的 ServerControl中的「DefaultButton」也可喲。

使用Panel的話,彈性可以更廣,因為,每個網頁可以有許多個Panel呀
例如,一個網頁中,同時放有登入及查詢的功能,我們就可將其各用Panel包起來
這樣,就可以各自跑各自的DefaultButton了。

用Panel的話,在MasterPage的話,也可通用。



GridView的表頭跨欄設計(11.19)

這個功能,在Google用「GridView 跨欄」去搜尋,就會有一大堆的文章。
對這功能來說,是個老梗了啦!
現下,我便引用某位大大的文章,及配合自己的實例,來幫助註解一下吧。


if (e.Row.RowType == DataControlRowType.Header)
{
TableCellCollection oldCell = e.Row.Cells;
oldCell.Clear();//將原有的表頭格式移除

//產生多重表列的第一列
GridViewRow headRow = new GridViewRow(0,0, DataControlRowType.Header, DataControlRowState.Insert);

//第一欄
TableCell head2Cell = new TableCell();
head2Cell.Text = "單位";
head2Cell.BackColor = row1color();//自訂的方法用以統一取得色彩
head2Cell.HorizontalAlign = HorizontalAlign.Center;
head2Cell.RowSpan = 2;//所跨的欄數
headRow.Cells.Add(head2Cell);//新增自製的儲存格


//第二欄
head2Cell = new TableCell();
head2Cell.Text = "群組";
head2Cell.BackColor = row1color();
head2Cell.ColumnSpan = 8;//所跨的欄數
head2Cell.HorizontalAlign = HorizontalAlign.Center;
headRow.Cells.Add(head2Cell);//新增自製的儲存格

//第三欄
head2Cell = new TableCell();
head2Cell.Text = "聯絡人";
head2Cell.BackColor = row1color();
head2Cell.ColumnSpan = 3;//所跨的欄數
head2Cell.HorizontalAlign = HorizontalAlign.Center;
headRow.Cells.Add(head2Cell);//新增自製的儲存格

//第四欄
head2Cell = new TableCell();
head2Cell.Text = "行事曆";
head2Cell.BackColor = row1color();
head2Cell.ColumnSpan = 3;//所跨的欄數
head2Cell.HorizontalAlign = HorizontalAlign.Center;
headRow.Cells.Add(head2Cell);//新增自製的儲存格

//將自製的資料列新增上去
GridView1.Controls[0].Controls.Add(headRow);

//產生多重表列的第二列
headRow = new GridViewRow(0, 0, DataControlRowType.Header, DataControlRowState.Insert);

#region 群組裡的欄位

//用法都與第一列相同
head2Cell = new TableCell();
head2Cell.Text = "使用量";
head2Cell.BackColor = row2color();//自訂的方法用以統一取得色彩
headRow.Cells.Add(head2Cell);

head2Cell = new TableCell();
head2Cell.Text = "成員數";
head2Cell.BackColor = row2color();
headRow.Cells.Add(head2Cell);

head2Cell = new TableCell();
head2Cell.Text = "員工數";
head2Cell.BackColor = row2color();
headRow.Cells.Add(head2Cell);

head2Cell = new TableCell();
head2Cell.Text = "通訊錄量";
head2Cell.BackColor = row2color();
headRow.Cells.Add(head2Cell);

head2Cell = new TableCell();
head2Cell.Text = "檔案總數";
head2Cell.BackColor = row2color();
headRow.Cells.Add(head2Cell);

head2Cell = new TableCell();
head2Cell.Text = "總檔案量";
head2Cell.BackColor = row2color();
headRow.Cells.Add(head2Cell);

head2Cell = new TableCell();
head2Cell.Text = "檔案下載次數";
head2Cell.BackColor = row2color();
headRow.Cells.Add(head2Cell);

head2Cell = new TableCell();
head2Cell.Text = "下載磁碟總量";
head2Cell.BackColor = row2color();
headRow.Cells.Add(head2Cell);

#endregion

#region 聯絡人裡的欄位

head2Cell = new TableCell();
head2Cell.Text = "使用人數";
head2Cell.BackColor = row2color();
headRow.Cells.Add(head2Cell);

head2Cell = new TableCell();
head2Cell.Text = "聯絡人數量";
head2Cell.BackColor = row2color();
headRow.Cells.Add(head2Cell);

head2Cell = new TableCell();
head2Cell.Text = "同步次數";
head2Cell.BackColor = row2color();
headRow.Cells.Add(head2Cell);

#endregion

#region 行事曆裡的欄位

head2Cell = new TableCell();
head2Cell.Text = "使用人數";
head2Cell.BackColor = row2color();
headRow.Cells.Add(head2Cell);

head2Cell = new TableCell();
head2Cell.Text = "events_personal";
head2Cell.BackColor = row2color();
headRow.Cells.Add(head2Cell);

head2Cell = new TableCell();
head2Cell.Text = "events_group";
head2Cell.BackColor = row2color();
headRow.Cells.Add(head2Cell);

#endregion

GridView1.Controls[0].Controls.Add(headRow);


完成後,我們的資料表頭,就會變成下列樣式:


2008年10月21日 星期二

如何在多行的TextBox加入斷行(10.21)

有時候,我們在設計表單要讓使用者填寫時,有時候設定預設的資料格式,如下圖

那我們在程式中,如何設定預設的斷行呢?
Environment.NewLine:取得為這個環境定義的新行字串 (Newline String)。msdn


範例:
txt_content.Text = string.Format(@"時間:{0}地點:{0}主辦單位:{0}執行單位:{0}協辦單位:{0}報名費用:{0}報名方式:{0}聯絡窗口:{0}活動議程:{0}", Environment.NewLine);

2008年10月3日 星期五

IIS 6.0 預設不支援 ASP.NET的程式(10.3)

前幾天,家裡的Server2003系統更新後,IIS也幫我由原本的5版提升到6版了!
結果呢,原本運行正常的程式,後來就都不行了,持續出現如下畫面。







原本以為是IIS壞掉了,於是移除重裝,但,仍然是這樣~~於是上網去搜尋了一下,
果然,已有許多大大遇見過這種問題,也都提供了解法。感謝天~感謝地~感謝這些無私的大大!



簡單地說,就是要新增ASP.NET 2.0的「網頁延伸服務」,並設為「允許」。以下為解法




2008年9月12日 星期五

如何產生辨識圖形(9.12)

現在有很多網頁,它們都會有個圖形驗證的功能。
有時候可能會出現在加入會員,
有時候可能會出現在發表問題、論壇等,
主要就是防止別人使用「程式」來胡作非為,
畢竟,加了一個圖形驗證,是用肉眼來辨識的,
「程式」要突破,就比較難了~~~(或許根本沒法做到)。
那現在,我們來看看這功能是如何達成的。


要產生如此的畫面,建議使用二個網頁,
一個是主畫面,另一個是負責畫圖的。
以下採用
「Default.aspx」:主畫面
「Default2.aspx」:畫圖的網頁
來制作

程式碼 Default.aspx.cs


using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Drawing;//畫圖相關的類別


public partial class _Default : System.Web.UI.Page
{

protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{

//產生圖形

BindIMG();

}

}

#region 產生圖形

private void BindIMG()
{

//定義圖形大小、圖形解析度
Bitmap BMP = new Bitmap(300, 100,System.Drawing.Imaging.PixelFormat.Format24bppRgb );

Graphics formGraphics = Graphics.FromImage(BMP);

//內填滿

formGraphics.FillRectangle(new SolidBrush(Color.PaleGoldenrod
), 0, 0, 300, 100);

string drawString = "";

//用亂數取六位數

Random rnd = new Random();

for (int i = 0; i < 6; i++)
{

drawString += string.Format("{0} ", rnd.Next(9));//產生小於10的整數

}



//定義字型,大小

Font drawFont = new Font("Comic Sans MS", 32);

//定義筆刷顏色

SolidBrush drawBrush = new SolidBrush(Color.YellowGreen
);

//座標位置

Single x = 20;
Single y = 15;

//畫出內容

formGraphics.DrawString(drawString, drawFont, drawBrush, x, y);

//釋出資源
drawFont.Dispose();
drawBrush.Dispose();
formGraphics.Dispose();


//將繪圖相關存到session,在另一個網頁拿來用


Session["BMP"] = BMP;

//由另一個網頁輸出

Image1.ImageUrl = "Default2.aspx";


}
#endregion

}



程式碼 Default2.aspx.cs


using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Drawing;
using System.IO;


public partial class Default2 : System.Web.UI.Page
{

protected void Page_Load(object sender, EventArgs e)
{
//利用剛剛存到session的圖片讀出
Bitmap BMP = (Bitmap)Session["BMP"];
MemoryStream tempStream = new
MemoryStream();
//將圖片存到記憶體
BMP.Save(tempStream,System.Drawing.Imaging.ImageFormat.Png);

Response.ClearContent();
Response.ContentType = "image/png";
Response.BinaryWrite(tempStream.ToArray());//將圖片用二進位輸出
Response.End();

}

}



由於圖片是根據我們製作的「drawString」字串畫出來的,
接下來若要判斷的話,我們則使用它來比對使用者輸入的文字即可。

2008年8月23日 星期六

出現「這個安裝不支援這種專案類型」?(8.23)

由於要承接別人案子的緣故
所以我的同夥將他的程式整包丟給我
那想當然爾,就一如往常的要將專案建置起來
沒想到,出乎意料的搞不定
出現了這樣的錯誤訊息,讓我苦惱一時
後來又看到這個專案裡的程式
跟我們一般的不同,就是一支網頁不只有
*.aspx
*.aspx.cs
又多了
*.aspx.designer.cs
這樣的東西
這一下這支程式裡的內容,似乎只是介紹控制項而已。
後來上網查了一下
原來是因為此專案在設計時
已經安裝了VS2005 SP1 的 Service Pack
所在這個專案在新增時,就會另外出現這樣的程式(*.aspx.designer.cs
而原本尚未安裝SP1的我,遇到這種不認識的程式
就會發生錯誤,專案自然就開啟不了
所以,記得請先安裝VS2005 SP1 再開專案吧。

2008年8月7日 星期四

物件導向程式設計_介面(Interface)(8.6)

何謂介面(Interface):
在google上,的確有著非常多相關於介面(Interface)的討論、說明。
不曉得是不是本人智商過低,亦或是人家講的不清楚? 我是都有看沒有懂。
不過,看大家在都可以在各論壇討論得沸沸騰騰,所以,猜想答案應該是前者吧(本人智商過低)。
但是,畢竟用一種說法,並不代表可以說懂每一個人嘛,不然,哪來的「因材施教」呢?
也幸好,本人並非「朽木不可雕也」,看了一堆人的說法,總算是有點心得。
其實,透過字面上,我們也可以看得出來「介面(Interface)」是什麼東西。
就是某個東西,要操控、使用另一個東西時,中間的橋梁,
就像我們在使用電腦時,會有一個介面(window畫面),來指引你使用,
我們在看電視轉台時,會有個搖控器或是選台的按鈕讓你來轉台。
這邊主要的觀念是想說,「介面(Interface)」主要就是構成二者互動的橋梁。
有了這個概念後,我們把概念帶到程式這邊來:
介面(Interface)就是「程式碼」與「類別(Class)」之間的橋梁。
當然,我們在寫程式時,也不見得會採取介面(Interface)的方法,
我們會直接「程式碼--->類別」,並不會「程式碼--->介面--->類別」的流程。
只是說,若使用介面(Interface)的話,它們的關係,是這樣子的。
介面(Interface)的使用:(C#)
interface IHardDisk
{
void setDefault(); //設定硬碟容量的起始值
bool compareHD(int HD); //比較看哪個容量大
int HD_gigabyte{ set;get;} //設定/取得硬碟容量
public void errtest();
}
小提醒:
  1. 一般習慣,在命名介面(Interface)時,都以「I」為開頭表示Interface。
  2. 在定義介面(Interface)時,裡面的方法,屬性都只「定義」而已,並未真正的實作內容
  3. 由於,此為測試,所以真正在應用時,請適時地加上「Public」修飾詞。ex: Public interface IHardDisk {...}。
  4. 上面紅色字體,表示為錯誤的使用方法:不用加上「Public」修飾詞.
看完了如何定義一個介面(Interface)後,我們接著看範例。
介面(Interface)範例:
範例說明(實作):
  1. 定義介面(IHardDisk)
  2. 利用類別(HardDisk)實作介面
  3. 程式中,一改以往呼叫類別的方法,改以呼叫介面
  4. 使用該介面的各屬性、方法
小提醒:
  1. 在實作介面時,該介面所定義的方法、屬性,在類別那,都要一一實作
  2. 在實作介面時,每個「方法」都請加上修飾詞「Public
  3. 程式宣告時「IHardDisk ComputerHD=new HardDisk() ; 」,後面是 new 一個類別。
程式碼:
---------------------------------------------
interface IHardDisk
{
void setDefault(); //設定硬碟容量的起始值
bool compareHD(int HD); //比較看哪個容量大
int HD_gigabyte{ set;get;} //設定/取得硬碟容量

}
class HardDisk : IHardDisk //實作IHardDisk的介面
{
//將介面的各個方法、屬性實作出來
int hd_gigabyte;//宣告一個變數來存取硬碟容量的值

public void setDefault()//實作「設定起始值」的方法
{
hd_gigabyte = 520;
}

public bool compareHD(int HD)//實作「比較大小」的方法
{
if (HD > hd_gigabyte){return true;}
else{return false;}
}

public int HD_gigabyte //實作「取得/設定容量」的屬性
{
get { return hd_gigabyte; }
set {hd_gigabyte=value;}
}
}

protected void Page_Load(object sender, EventArgs e)
{
IHardDisk ComputerHD=new HardDisk() ; //宣告
ComputerHD.setDefault(); //設定硬碟容量的預設值
Response.Write(ComputerHD.HD_gigabyte); //取得硬碟容量
Response.Write(ComputerHD.compareHD(567)); //比較大小

}
--------------------------------------------
為何要使用介面(Interface):
看了以上的範例,會有個想法:這種作法,比我直接呼叫類別的方法還要繁瑣
我直接將方法寫在類別裡,再呼叫類別使用就好啦!(「程式碼--->類別」)
何必要這麼麻煩,還透過介面,多了一道手續(「程式碼--->介面--->類別」)
沒錯,藉由以上的範例,的確看不出用介面(Interface)的好處。
然而,使用介面的好處在於「泛用」。
所謂的「泛用」或許可以解釋成「廣泛地使用」,
也就是說,我們只要使用介面,就可以使用不同的類別(前提為,該類別必須實作該介面)
範例說明:(實作)
  1. 相同地我們定義一個介面(Interface)
  2. 另外,我們產生兩個類別一個適用於小型硬碟(miniHardDisk),另一個適用於大型硬碟(bigHardDisk)
  3. 兩者也都實作了IHardDisk的介面
  4. 再來,我們又新增了一個類別,這個類別裡,定義的方法為回傳一個介面的型態(將來都實作產生這個類別)
  5. 在程式碼中,可看到,我們在Computer的類別裡,我們目前是使用「小型硬碟」
  6. 在Page_Load中,我們輸出了介面,及二類別的資料
程式重點:
  1. 程式中,我們目前是使用「小型硬碟」,若突然要改成「大型硬碟」時,我們只需更動,Computer的類別即可,程式碼,完全不用更動
  2. 將類別中的「miniHardDisk cc = new miniHardDisk();」,改成「bigHardDisk cc = new bigHardDisk ();」
程式碼:
======================================

interface IHardDisk
{
void setDefault();//設定硬碟容量的起始值
bool compareHD(int HD);//比較看哪個容量大
int HD_gigabyte { set;get;}//設定/取得硬碟容量

}

class miniHardDisk : IHardDisk //實作IHardDisk的介面
{
//將介面的各個方法、屬性實作出來

int hd_gigabyte=0;//宣告一個變數來存取硬碟容量的值
public void setDefault()
{
hd_gigabyte = 40;

}
public bool compareHD(int HD)
{
if (HD > hd_gigabyte){return true;}
else{return false;}
}
public int HD_gigabyte
{
get { return hd_gigabyte; }
set {hd_gigabyte=value;}

}
}
class bigHardDisk : IHardDisk //實作IHardDisk的介面
{
//將介面的各個方法、屬性實作出來

int hd_gigabyte=0;//宣告一個變數來存取硬碟容量的值
public void setDefault()
{
hd_gigabyte = 1024;

}
public bool compareHD(int HD)
{
if (HD > hd_gigabyte) { return true; }
else { return false; }
}
public int HD_gigabyte
{
get { return hd_gigabyte; }
set { hd_gigabyte = value; }

}
}

class Computer
{
public IHardDisk Disk()
{
miniHardDisk cc = new miniHardDisk();
cc.setDefault();
return cc;
}
}


protected void Page_Load(object sender, EventArgs e)
{

IHardDisk Iabc = new Computer().Disk();
Response.Write("使用介面取得的值:");
Response.Write(Iabc.HD_gigabyte);
Response.Write("<br><br>");

Response.Write("使用bigHardDisk類別取得的值:");
bigHardDisk bHD = new bigHardDisk();
bHD.setDefault();
Response.Write(bHD.HD_gigabyte);
Response.Write("<br><br>");

Response.Write("使用miniHardDisk類別取得的值:");
miniHardDisk mHD = new miniHardDisk();
mHD.setDefault();
Response.Write(mHD.HD_gigabyte);



}

======================================
議題:
這時,也會有個疑問:
既然這樣的話,我還是一樣可以使用類別呀,
反正也是一定要創造兩個類別,那我在Page_Load時,再改呀
類別的寫法-->
Response.Write("使用bigHardDisk類別取得的值:");
miniHardDisk mHD = new miniHardDisk ();
mHD .setDefault();
Response.Write(mHD .HD_gigabyte);
Response.Write("<br><br>");
那當我要由小型硬碟改成大型時,就把
miniHardDisk mHD = new miniHardDisk ();
改成
bigHardDisk bHD = new bigHardDisk();
也行呀。
------------>
很好,說得沒錯,不過,首先,會先遇到個問題
「命名」,已由 mHD --> bHD ,勢必程式碼裡面的名稱都要修改
再者,假設,不修改名稱,我就硬用 mHD 用到底,反正都可以用嘛。
是啊,可以用,可是,又面臨到另個問題,
目前程式是只有一頁而已,那假設,我們已經使用原先物件的寫法,寫了10頁,
甚至於好幾十頁,請問,你要一支一支改嗎?
那如果我們使用「介面」的方法,就只要修改我們類別庫裡的該Computer類別即可。